WIP:Infrastructure for supporting more K8S Tests. 29/72629/3
authorSridhar K. N. Rao <sridhar.rao@spirent.com>
Wed, 2 Jun 2021 13:41:18 +0000 (19:11 +0530)
committerSridhar K. N. Rao <sridhar.rao@spirent.com>
Tue, 15 Jun 2021 16:04:48 +0000 (21:34 +0530)
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 <sridhar.rao@spirent.com>
Change-Id: Ie01735f99c0687cc812eae8e67ee2353347924f2

conf/02_vswitch.conf
conf/12_k8s.conf
conf/kubernetes/01_testcases.conf
core/pod_controller.py
pods/papi/papi.py
testcases/testcase.py
tools/extvswitchflctl.py [new file with mode: 0644]
tools/pkt_fwd/dummy.py [new file with mode: 0644]

index 4eca1a5..7a29fc7 100644 (file)
@@ -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'
index 5cfac96..545870c 100644 (file)
@@ -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'
index c5b3135..25eea36 100644 (file)
@@ -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",
+            },
+        },
+    },
 ]
index 8bc91ec..109daa4 100644 (file)
@@ -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):
index 5a21f1d..5a96660 100644 (file)
@@ -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)
 
index c300bfc..40bec18 100644 (file)
@@ -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 (file)
index 0000000..56eeafd
--- /dev/null
@@ -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 (file)
index 0000000..97ffc66
--- /dev/null
@@ -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 []