From 8137692dd94e112943dcc576470f4b361fbd8c5c Mon Sep 17 00:00:00 2001 From: "Sridhar K. N. Rao" Date: Wed, 2 Jun 2021 19:11:18 +0530 Subject: WIP:Infrastructure for supporting more K8S Tests. This patch add multiple changes to ViNePerf to support following tests. 1. External virtual switch - not managed by Vineperf. 2. CNI not based on virtual switch 3. Fixed bugs after successful testing. 4. Pylint issues fixed 4. Fix some license-content and comments Signed-off-by: Sridhar K. N. Rao Change-Id: Ie01735f99c0687cc812eae8e67ee2353347924f2 --- conf/02_vswitch.conf | 3 + conf/12_k8s.conf | 10 ++- conf/kubernetes/01_testcases.conf | 20 ++++++ core/pod_controller.py | 13 ++-- pods/papi/papi.py | 21 ++++--- testcases/testcase.py | 12 ++++ tools/extvswitchflctl.py | 129 ++++++++++++++++++++++++++++++++++++++ tools/pkt_fwd/dummy.py | 62 ++++++++++++++++++ 8 files changed, 256 insertions(+), 14 deletions(-) create mode 100644 tools/extvswitchflctl.py create mode 100644 tools/pkt_fwd/dummy.py diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf index 4eca1a52..7a29fc70 100644 --- a/conf/02_vswitch.conf +++ b/conf/02_vswitch.conf @@ -250,3 +250,6 @@ VSWITCH_VPP_L2_CONNECT_MODE = 'xconnect' # Options used during creation of dpdkvhostuser interface VSWITCH_VPP_VHOSTUSER_ARGS = ['feature-mask', '0xFF'] + +EXT_VSWITCH_VPP_FLOWCTL = 'vppctl' +EXT_VSWITCH_OVS_FLOWCTL = 'ovs-ofctl' diff --git a/conf/12_k8s.conf b/conf/12_k8s.conf index 5cfac966..545870cd 100644 --- a/conf/12_k8s.conf +++ b/conf/12_k8s.conf @@ -32,10 +32,16 @@ WORKER_PASSWD = 'opnfv' PLUGIN = 'ovsdpdk' # Paths. Default location: Master Node. -NETWORK_ATTACHMENT_FILEPATH = ['/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netAttach.yaml'] -POD_MANIFEST_FILEPATH = '/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netapp-pod.yaml' +# NETWORK_ATTACHMENT_FILEPATH = ['/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netAttach.yaml'] +NETWORK_ATTACHMENT_FILEPATH = ['/home/opnfv/sridhar/cnb/userspace/vpp/userspace-vpp-netAttach-memif.yaml'] +#POD_MANIFEST_FILEPATH = '/home/opnfv/sridhar/cnb/userspace/ovsdpdk/userspace-ovs-netapp-pod.yaml' +POD_MANIFEST_FILEPATH = ['/home/opnfv/sridhar/cnb/userspace/vpp/userspace-dpdk-pod.yaml', + '/home/opnfv/sridhar/cnb/userspace/vpp/userspace-dpdk-pod2.yaml'] # Application pod APP_NAME = 'l2fwd' +EXT_VSWITCH = True +EXT_VSWITCH_TYPE = 'VPP' +EXT_OVS_BRIDGE = 'br0' diff --git a/conf/kubernetes/01_testcases.conf b/conf/kubernetes/01_testcases.conf index c5b3135c..25eea362 100644 --- a/conf/kubernetes/01_testcases.conf +++ b/conf/kubernetes/01_testcases.conf @@ -9,4 +9,24 @@ K8SPERFORMANCE_TESTS = [ }, }, }, + { + "Name": "pcp_evs_tput", + "Deployment": "pcp", + "Description": "LTD.Throughput.RFC2544.Throughput", + "Parameters" : { + "TRAFFIC" : { + "traffic_type" : "rfc2544_throughput", + }, + }, + }, + { + "Name": "pccp_evs_tput", + "Deployment": "pccp", + "Description": "LTD.Throughput.RFC2544.Throughput", + "Parameters" : { + "TRAFFIC" : { + "traffic_type" : "rfc2544_throughput", + }, + }, + }, ] diff --git a/core/pod_controller.py b/core/pod_controller.py index 8bc91ec4..109daa43 100644 --- a/core/pod_controller.py +++ b/core/pod_controller.py @@ -16,7 +16,7 @@ import logging import pexpect -#from conf import settings +from conf import settings from pods.pod.pod import IPod class PodController(): @@ -44,12 +44,15 @@ class PodController(): self._pod_class = pod_class self._deployment = deployment.lower() self._pods = [] - if self._deployment == 'p2p': + if 'pcp' in self._deployment or 'p2p' in self._deployment: pod_number = 1 - + elif 'pccp'in self._deployment: + pod_number = 2 + print("POD COUNTING DONE") + settings.setValue('POD_COUNT', pod_number) + # we will have single controller for all pods if pod_number: - self._pods = [pod_class() for _ in range(pod_number)] - + self._pods.append(pod_class()) self._logger.debug('Initializing the pod') def get_pods(self): diff --git a/pods/papi/papi.py b/pods/papi/papi.py index 5a21f1d6..5a96660d 100644 --- a/pods/papi/papi.py +++ b/pods/papi/papi.py @@ -49,9 +49,12 @@ class Papi(IPod): """ Creation Process """ + print("Entering Create Function") # create vswitchperf namespace api = client.CoreV1Api() namespace = 'default' + pod_manifests = S.getValue('POD_MANIFEST_FILEPATH') + pod_count = int(S.getValue('POD_COUNT')) #namespace = 'vswitchperf' # replace_namespace(api, namespace) @@ -68,6 +71,8 @@ class Papi(IPod): version = 'v1' kind_plural = 'network-attachment-definitions' api = client.CustomObjectsApi() + + assert pod_count <= len(pod_manifests) for nad_filepath in S.getValue('NETWORK_ATTACHMENT_FILEPATH'): nad_manifest = load_manifest(nad_filepath) @@ -81,15 +86,17 @@ class Papi(IPod): raise Exception from err #create pod workloads - pod_manifest = load_manifest(S.getValue('POD_MANIFEST_FILEPATH')) api = client.CoreV1Api() + + for count in range(pod_count): + pod_manifest = load_manifest(pod_manifests[count]) - try: - response = api.create_namespaced_pod(namespace, pod_manifest) - self._logger.info(str(response)) - self._logger.info("Created POD %d ...", self._number) - except ApiException as err: - raise Exception from err + try: + response = api.create_namespaced_pod(namespace, pod_manifest) + self._logger.info(str(response)) + self._logger.info("Created POD %d ...", self._number) + except ApiException as err: + raise Exception from err time.sleep(12) diff --git a/testcases/testcase.py b/testcases/testcase.py index c300bfc1..40bec186 100644 --- a/testcases/testcase.py +++ b/testcases/testcase.py @@ -35,6 +35,7 @@ from tools import hugepages from tools import functions from tools import namespace from tools import veth +from tools import extvswitchflctl from tools.teststepstools import TestStepsTools from tools.llc_management import rmd @@ -76,6 +77,7 @@ class TestCase(object): self._pod_ctl = None self._pod_list = None self._vswitch_ctl = None + self._evfctl = None self._collector = None self._loadgen = None self._output_file = None @@ -203,6 +205,10 @@ class TestCase(object): # If running in k8s mode. # This value is set in main vsperf file self._k8s = S.getValue('K8S') + if self._k8s: + if S.getValue('EXT_VSWITCH'): + self._evfctl = extvswitchfctl.ExtVswitchFlowCtl() + def run_initialize(self): """ Prepare test execution environment @@ -619,6 +625,12 @@ class TestCase(object): Add connections for Kubernetes Usecases """ logging.info("Kubernetes: Adding Connections") + if self._evfctl: + self._evfctl.add_connections() + return + if self._vswitch_none: + logging.info("Vswitch cannot be None when switch is not external") + return vswitch = self._vswitch_ctl.get_vswitch() bridge = S.getValue('VSWITCH_BRIDGE_NAME') if S.getValue('K8S') and 'sriov' not in S.getValue('PLUGIN'): diff --git a/tools/extvswitchflctl.py b/tools/extvswitchflctl.py new file mode 100644 index 00000000..56eeafd0 --- /dev/null +++ b/tools/extvswitchflctl.py @@ -0,0 +1,129 @@ +""" +Tool to configure flows for Kubernetes Usecases. +""" + +from tools import tasks +from conf import settings as S + +class ExtVswitchFlowCtl(tasks.Process): + """ + Virtual Switch Flow Control + """ + def __init__(self): + """ + Initialization + """ + super().__init__() + self._vpp_ctl = ['sudo', S.getValue('EXT_VSWITCH_VPP_FLOWCTL')] + self._ovs_ctl = ['sudo', S.getValue('EXT_VSWITCH_OVS_FLOWCTL')] + + def get_vpp_interfaces(self): + """ + Get VPP interfaces Names + """ + ifargs = ['show', 'interface'] + output = self.run_vppctl(ifargs) + ifaces = output[0].split('\n') + pifaces = [] + vifaces = [] + for iface in ifaces: + name = iface.split()[0] + if 'Name' in name or 'local' in name: + continue + if 'Ethernet' in name: + pifaces.append(name) + if 'memif' in name: + vifaces.append(name) + assert len(vifaces) == 2 or len(vifaces) == 4 + assert len(pifaces) == 2 + assert pifaces[0][:-1] in pifaces[1][:-1] + return pifaces, vifaces + + def add_connections(self): + """ + Add Connections of OVS or VPP + """ + if 'VPP' in S.getValue('EXT_VSWITCH_TYPE'): + self.add_vpp_xconnect() + else: + self.add_ovs_xconnect() + + def add_ovs_xconnect(self): + """ + Add connections to OVS + """ + entries = [['--timeout', '10', '-o', 'OpenFlow13', 'add-flow', + S.getValue('EXT_VSWITCH_OVS_BRIDGE'), + 'in_port=1,idle_timeout=0,action=output:3'], + ['--timeout', '10', '-o', 'OpenFlow13', 'add-flow', + S.getValue('EXT_VSWITCH_OVS_BRIDGE'), + 'in_port=3,idle_timeout=0,action=output:1'], + ['--timeout', '10', '-o', 'OpenFlow13', 'add-flow', + S.getValue('EXT_VSWITCH_OVS_BRIDGE'), + 'in_port=2,idle_timeout=0,action=output:4'], + ['--timeout', '10', '-o', 'OpenFlow13', 'add-flow', + S.getValue('EXT_VSWITCH_OVS_BRIDGE'), + 'in_port=4,idle_timeout=0,action=output:2']] + for entry in entries: + self.run_ovsfctl(entry) + + def add_vpp_xconnect(self): + """ + Add Connections to VPP + """ + pifaces, vifaces = self.get_vpp_interfaces() + # Bring Physical interface up - In case it is down. + for piface in pifaces: + ifargs = ['set', 'interface', 'state', piface, 'up'] + self.run_vppctl(ifargs) + if len(vifaces) == 2: + entries = [['test', 'l2patch', 'rx', + pifaces[0], 'tx', vifaces[0]], + ['test', 'l2patch', 'rx', + vifaces[0], 'tx', pifaces[0]], + ['test', 'l2patch', 'rx', + pifaces[1], 'tx', vifaces[1]], + ['test', 'l2patch', 'rx', + vifaces[1], 'tx', pifaces[1]]] + elif len(vifaces) == 4: + entries = [['test', 'l2patch', 'rx', + pifaces[0], 'tx', vifaces[0]], + ['test', 'l2patch', 'rx', + vifaces[0], 'tx', pifaces[0]], + ['test', 'l2patch', 'rx', + vifaces[1], 'tx', vifaces[2]], + ['test', 'l2patch', 'rx', + vifaces[2], 'tx', vifaces[1]], + ['test', 'l2patch', 'rx', + pifaces[1], 'tx', vifaces[3]], + ['test', 'l2patch', 'rx', + vifaces[3], 'tx', pifaces[1]]] + + for entry in entries: + self.run_vppctl(entry) + + def run_ovsfctl(self, args, check_error=False): + """Run ``ovs-ofctl`` with supplied arguments. + + :param args: Arguments to pass to ``vppctl`` + :param check_error: Throw exception on error + + :return: None + """ + cmd = self._ovs_ctl + args + return tasks.run_task(cmd, self._logger, + 'Running ovs-ofctl...', + check_error) + + def run_vppctl(self, args, check_error=False): + """Run ``vppctl`` with supplied arguments. + + :param args: Arguments to pass to ``vppctl`` + :param check_error: Throw exception on error + + :return: None + """ + cmd = self._vpp_ctl + args + return tasks.run_task(cmd, self._logger, + 'Running vppctl...', + check_error) diff --git a/tools/pkt_fwd/dummy.py b/tools/pkt_fwd/dummy.py new file mode 100644 index 00000000..97ffc666 --- /dev/null +++ b/tools/pkt_fwd/dummy.py @@ -0,0 +1,62 @@ +# Copyright 2021 Spirent Communications +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""VSPERF Dummy Pkt-Fwd. +""" + +import logging +from conf import settings + +_LOGGER = logging.getLogger(__name__) + +class Dummy(IPktFwd): + """Dummy implementation + + """ + + _logger = logging.getLogger() + + def __init__(self, guest=False): + self._logger.info("Initializing Dummy...") + + def start(self): + """See IPktFwd for general description + + Activates testpmd. + """ + self._logger.info("Starting Dummy...") + + def start_for_guest(self): + """See IPktFwd for general description + + Activates testpmd for guest config + """ + self._logger.info("Starting Dummy for one guest...") + + def stop(self): + """See IPktFwd for general description + + Kills testpmd. + """ + self._logger.info("Stopping Dummy ....") + + # Method could be a function + # pylint: disable=no-self-use + def get_version(self): + """ + Get product version + :return: None + """ + # No way to read Dummy version + return [] -- cgit 1.2.3-korg