Introduce VPP-IPsec container tests.
[csit.git] / resources / libraries / python / ContainerUtils.py
index 74add98..d10360f 100644 (file)
 
 from collections import OrderedDict, Counter
 from io import open
+from re import search
 from string import Template
+from time import sleep
 
 from robot.libraries.BuiltIn import BuiltIn
 
 from resources.libraries.python.Constants import Constants
+from resources.libraries.python.CpuUtils import CpuUtils
 from resources.libraries.python.ssh import SSH
 from resources.libraries.python.topology import Topology, SocketType
 from resources.libraries.python.VppConfigGenerator import VppConfigGenerator
@@ -153,6 +156,12 @@ class ContainerManager:
             self.engine.container = self.containers[container]
             self.engine.restart_vpp()
 
+    def verify_vpp_in_all_containers(self):
+        """Verify that VPP is installed and running in all containers."""
+        for container in self.containers:
+            self.engine.container = self.containers[container]
+            self.engine.verify_vpp()
+
     def configure_vpp_in_all_containers(self, chain_topology, **kwargs):
         """Configure VPP in all containers.
 
@@ -208,6 +217,17 @@ class ContainerManager:
                     mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2,
                     guest_dir=guest_dir, **kwargs
                 )
+            elif chain_topology == u"chain_vswitch":
+                self._configure_vpp_chain_vswitch(
+                    mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2,
+                    guest_dir=guest_dir, **kwargs)
+            elif chain_topology == u"chain_ipsec":
+                idx_match = search(r"\d+$", self.engine.container.name)
+                if idx_match:
+                    idx = int(idx_match.group())
+                self._configure_vpp_chain_ipsec(
+                    mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2,
+                    guest_dir=guest_dir, nf_instance=idx, **kwargs)
             else:
                 raise RuntimeError(
                     f"Container topology {chain_topology} not implemented"
@@ -299,6 +319,134 @@ class ContainerManager:
             vif1_mac=vif1_mac, vif2_mac=vif2_mac
         )
 
+    def _configure_vpp_chain_vswitch(self, **kwargs):
+        """Configure VPP as vswitch in container.
+
+        :param kwargs: Named parameters.
+        :param kwargs: dict
+        """
+        dut = self.engine.container.name.split(u"_")[0]
+        if dut == u"DUT1":
+            if1_pci = Topology.get_interface_pci_addr(
+                self.engine.container.node, kwargs[u"dut1_if2"])
+            if2_pci = Topology.get_interface_pci_addr(
+                self.engine.container.node, kwargs[u"dut1_if1"])
+            if_red_name = Topology.get_interface_name(
+                self.engine.container.node, kwargs[u"dut1_if2"])
+            if_black_name = Topology.get_interface_name(
+                self.engine.container.node, kwargs[u"dut1_if1"])
+            tg_if_ip4 = kwargs[u"tg_if2_ip4"]
+            tg_if_mac = kwargs[u"tg_if2_mac"]
+        else:
+            tg_if_ip4 = kwargs[u"tg_if1_ip4"]
+            tg_if_mac = kwargs[u"tg_if1_mac"]
+            if1_pci = Topology.get_interface_pci_addr(
+                self.engine.container.node, kwargs[u"dut2_if1"])
+            if2_pci = Topology.get_interface_pci_addr(
+                self.engine.container.node, kwargs[u"dut2_if2"])
+            if_red_name = Topology.get_interface_name(
+                self.engine.container.node, kwargs[u"dut2_if1"])
+            if_black_name = Topology.get_interface_name(
+                self.engine.container.node, kwargs[u"dut2_if2"])
+
+        n_instances = int(kwargs[u"n_instances"])
+        rxq = 1
+        if u"rxq" in kwargs:
+            rxq = int(kwargs[u"rxq"])
+        buffers = 215040
+        if u"buffers" in kwargs:
+            buffers = int(kwargs[u"buffers"])
+        nodes = kwargs[u"nodes"]
+        cpuset_cpus = CpuUtils.get_affinity_nf(
+            nodes, dut, nf_chains=1, nf_nodes=1, nf_chain=1,
+            nf_node=1, vs_dtc=0, nf_dtc=8, nf_mtcr=1, nf_dtcr=1
+        )
+        self.engine.create_vpp_startup_config_vswitch(
+            cpuset_cpus, rxq, buffers, if1_pci, if2_pci
+        )
+
+        instances = []
+        for i in range(1, n_instances + 1):
+            instances.append(
+                f"create interface memif id {i} socket-id 1 master\n"
+                f"set interface state memif1/{i} up\n"
+                f"set interface l2 bridge memif1/{i} 1\n"
+                f"create interface memif id {i} socket-id 2 master\n"
+                f"set interface state memif2/{i} up\n"
+                f"set interface l2 bridge memif2/{i} 2\n"
+                f"set ip arp memif2/{i} {tg_if_ip4} {tg_if_mac} "
+                f"static\n\n"
+            )
+
+        self.engine.create_vpp_exec_config(
+            u"memif_create_chain_vswitch_ipsec.exec",
+            socket1=f"{kwargs[u'guest_dir']}/{dut}_memif-vswitch-1",
+            socket2=f"{kwargs[u'guest_dir']}/{dut}_memif-vswitch-2",
+            if_red_name=if_red_name,
+            if_black_name=if_black_name,
+            instances=u"\n\n".join(instances))
+
+
+    def _configure_vpp_chain_ipsec(self, **kwargs):
+        """Configure VPP in container with memifs.
+
+        :param kwargs: Named parameters.
+        :param kwargs: dict
+        """
+        nf_nodes = int(kwargs[u"nf_nodes"])
+        nf_instance = int(kwargs[u"nf_instance"])
+        nodes = kwargs[u"nodes"]
+        dut = self.engine.container.name.split(u"_")[0]
+        cpuset_cpus = CpuUtils.get_affinity_nf(
+            nodes, dut, nf_chains=1, nf_nodes=nf_nodes, nf_chain=1,
+            nf_node=nf_instance, vs_dtc=10, nf_dtc=1, nf_mtcr=1, nf_dtcr=1)
+        self.engine.create_vpp_startup_config_ipsec(cpuset_cpus)
+        local_ip_base = kwargs[u"dut2_if1_ip4"].rsplit(u".", 1)[0]
+
+        if dut == u"DUT1":
+            tnl_local_ip = f"{local_ip_base}.{nf_instance + 100}"
+            tnl_remote_ip = f"{local_ip_base}.{nf_instance}"
+            remote_ip_base = kwargs[u"dut1_if1_ip4"].rsplit(u".", 1)[0]
+            tg_if_ip4 = kwargs[u"tg_if1_ip4"]
+            tg_if_mac = kwargs[u"tg_if1_mac"]
+            raddr_ip4 = kwargs[u"laddr_ip4"]
+            l_mac1 = 17
+            l_mac2 = 18
+            r_mac = 1
+        else:
+            tnl_local_ip = f"{local_ip_base}.{nf_instance}"
+            tnl_remote_ip = f"{local_ip_base}.{nf_instance + 100}"
+            remote_ip_base = kwargs[u"dut2_if2_ip4"].rsplit(u".", 1)[0]
+            tg_if_ip4 = kwargs[u"tg_if2_ip4"]
+            tg_if_mac = kwargs[u"tg_if2_mac"]
+            raddr_ip4 = kwargs[u"raddr_ip4"]
+            l_mac1 = 1
+            l_mac2 = 2
+            r_mac = 17
+
+        self.engine.create_vpp_exec_config(
+            u"memif_create_chain_ipsec.exec",
+            socket1=f"{kwargs['guest_dir']}/{dut}_memif-vswitch-1",
+            socket2=f"{kwargs['guest_dir']}/{dut}_memif-vswitch-2",
+            mid1=nf_instance,
+            mid2=nf_instance,
+            sid1=u"1",
+            sid2=u"2",
+            mac1=f"02:02:00:00:{l_mac1:02X}:{(nf_instance - 1):02X}",
+            mac2=f"02:02:00:00:{l_mac2:02X}:{(nf_instance - 1):02X}",
+            tg_if2_ip4=tg_if_ip4,
+            tg_if2_mac=tg_if_mac,
+            raddr_ip4=raddr_ip4,
+            tnl_local_ip=tnl_local_ip,
+            tnl_remote_ip=tnl_remote_ip,
+            tnl_remote_mac=f"02:02:00:00:{r_mac:02X}:{(nf_instance - 1):02X}",
+            remote_ip=f"{remote_ip_base}.{nf_instance}"
+        )
+        self.engine.execute(
+            f"cat {kwargs['guest_dir']}/ipsec_create_tunnel_cnf_"
+            f"{dut}_{nf_instance}.config >> /tmp/running.exec"
+        )
+
     def _configure_vpp_pipeline_ip4(self, **kwargs):
         """Configure VPP in pipeline topology with ip4.
 
@@ -448,15 +596,13 @@ class ContainerEngine:
             self.container.node,
             SocketType.PAPI,
             self.container.name,
-            f"{self.container.root}/tmp/vpp_sockets/{self.container.name}/"
-            f"api.sock"
+            f"/tmp/vpp_sockets/{self.container.name}/api.sock"
         )
         topo_instance.add_new_socket(
             self.container.node,
             SocketType.STATS,
             self.container.name,
-            f"{self.container.root}/tmp/vpp_sockets/{self.container.name}/"
-            f"stats.sock"
+            f"/tmp/vpp_sockets/{self.container.name}/stats.sock"
         )
 
     def restart_vpp(self):
@@ -464,13 +610,37 @@ class ContainerEngine:
         self.execute(u"supervisorctl restart vpp")
         self.execute(u"cat /tmp/supervisord.log")
 
-    def create_base_vpp_startup_config(self):
+    # TODO Rewrite .execute to accept retries parameter and get rid of this
+    # function.
+    def verify_vpp(self, retries=120, retry_wait=1):
+        """Verify that VPP is installed and running inside container.
+
+        :param retries: Check for VPP for this number of times Default: 120
+        :param retry_wait: Wait for this number of seconds between retries.
+
+        """
+        cmd = (u"vppctl show pci 2>&1 | "
+               u"fgrep -v 'Connection refused' | "
+               u"fgrep -v 'No such file or directory'")
+
+        for _ in range(retries + 1):
+            try:
+                self.execute(cmd)
+                break
+            except RuntimeError:
+                sleep(retry_wait)
+        else:
+            msg = f"VPP did not come up in container: {self.container.name}"
+            raise RuntimeError(msg)
+
+    def create_base_vpp_startup_config(self, cpuset_cpus=None):
         """Create base startup configuration of VPP on container.
 
         :returns: Base VPP startup configuration.
         :rtype: VppConfigGenerator
         """
-        cpuset_cpus = self.container.cpuset_cpus
+        if cpuset_cpus is None:
+            cpuset_cpus = self.container.cpuset_cpus
 
         # Create config instance
         vpp_config = VppConfigGenerator()
@@ -519,8 +689,7 @@ class ContainerEngine:
         # Apply configuration
         self.execute(u"mkdir -p /etc/vpp/")
         self.execute(
-            f'echo "{vpp_config.get_config_str()}" | '
-            f'tee /etc/vpp/startup.conf'
+            f'echo "{vpp_config.get_config_str()}" | tee /etc/vpp/startup.conf'
         )
 
     def create_vpp_startup_config_func_dev(self):
@@ -540,8 +709,58 @@ class ContainerEngine:
         # Apply configuration
         self.execute(u"mkdir -p /etc/vpp/")
         self.execute(
-            f'echo "{vpp_config.get_config_str()}" | '
-            f'tee /etc/vpp/startup.conf'
+            f'echo "{vpp_config.get_config_str()}" | tee /etc/vpp/startup.conf'
+        )
+
+    def create_vpp_startup_config_vswitch(self, cpuset_cpus, rxq, buffers,
+                                          *devices):
+        """Create startup configuration of VPP vswitch.
+
+        :param cpuset_cpus: CPU list to run on.
+        :param rxq: Number of interface RX queues.
+        :param buffers: Number of buffers per numa.
+        :param devices: List of PCI devices to add.
+        :type cpuset_cpus: list
+        :type rxq: int
+        :type buffers: int
+        :type devices: list
+        """
+        vpp_config = self.create_base_vpp_startup_config(cpuset_cpus)
+        vpp_config.add_dpdk_dev(*devices)
+        vpp_config.add_dpdk_log_level(u"debug")
+        vpp_config.add_plugin(u"disable", u"default")
+        vpp_config.add_plugin(u"enable", u"dpdk_plugin.so")
+        vpp_config.add_plugin(u"enable", u"memif_plugin.so")
+        vpp_config.add_dpdk_no_tx_checksum_offload()
+        vpp_config.add_buffers_per_numa(buffers)
+        vpp_config.add_dpdk_dev_default_rxq(rxq)
+
+        # Apply configuration
+        self.execute(u"mkdir -p /etc/vpp/")
+        self.execute(
+            f'echo "{vpp_config.get_config_str()}" | tee /etc/vpp/startup.conf'
+        )
+
+    def create_vpp_startup_config_ipsec(self, cpuset_cpus):
+        """Create startup configuration of VPP with IPsec on container.
+
+        :param cpuset_cpus: CPU list to run on.
+        :type cpuset_cpus: list
+        """
+        vpp_config = self.create_base_vpp_startup_config(cpuset_cpus)
+        vpp_config.add_plugin(u"disable", u"default")
+        vpp_config.add_plugin(u"enable", u"memif_plugin.so")
+        vpp_config.add_plugin(u"enable", u"crypto_ia32_plugin.so")
+        vpp_config.add_plugin(u"enable", u"crypto_ipsecmb_plugin.so")
+        vpp_config.add_plugin(u"enable", u"crypto_openssl_plugin.so")
+        vpp_config.add_heapsize(u"4G")
+        vpp_config.add_ip_heap_size(u"4G")
+        vpp_config.add_statseg_size(u"4G")
+
+        # Apply configuration
+        self.execute(u"mkdir -p /etc/vpp/")
+        self.execute(
+            f'echo "{vpp_config.get_config_str()}" | tee /etc/vpp/startup.conf'
         )
 
     def create_vpp_exec_config(self, template_file, **kwargs):