Add ipsec policy test suites with flow director or rss accelerated
[csit.git] / resources / libraries / python / IPsecUtil.py
index e455dd7..6ed2db1 100644 (file)
@@ -1,5 +1,5 @@
-# Copyright (c) 2021 Cisco and/or its affiliates.
-# Copyright (c) 2021 PANTHEON.tech s.r.o.
+# Copyright (c) 2022 Cisco and/or its affiliates.
+# Copyright (c) 2022 PANTHEON.tech s.r.o.
 # 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:
@@ -34,6 +34,7 @@ from resources.libraries.python.ssh import scp_node
 from resources.libraries.python.topology import Topology, NodeType
 from resources.libraries.python.VatExecutor import VatExecutor
 from resources.libraries.python.VPPUtil import VPPUtil
+from resources.libraries.python.FlowUtil import FlowUtil
 
 
 IPSEC_UDP_PORT_NONE = 0xffff
@@ -471,7 +472,8 @@ class IPsecUtil:
     @staticmethod
     def vpp_ipsec_add_sad_entries(
             node, n_entries, sad_id, spi, crypto_alg, crypto_key,
-            integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
+            integ_alg=None, integ_key=u"", tunnel_src=None,tunnel_dst=None,
+            tunnel_addr_incr=True):
         """Create multiple Security Association Database entries on VPP node.
 
         :param node: VPP node to add SAD entry on.
@@ -488,6 +490,8 @@ class IPsecUtil:
             specified ESP transport mode is used.
         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
             not specified ESP transport mode is used.
+        :param tunnel_addr_incr: Enable or disable tunnel IP address
+            incremental step.
         :type node: dict
         :type n_entries: int
         :type sad_id: int
@@ -498,6 +502,7 @@ class IPsecUtil:
         :type integ_key: str
         :type tunnel_src: str
         :type tunnel_dst: str
+        :type tunnel_addr_incr: bool
         """
         if isinstance(crypto_key, str):
             crypto_key = crypto_key.encode(encoding=u"utf-8")
@@ -510,8 +515,11 @@ class IPsecUtil:
             src_addr = u""
             dst_addr = u""
 
-        addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
-            else 1 << (32 - 24)
+        if tunnel_addr_incr:
+            addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
+                else 1 << (32 - 24)
+        else:
+            addr_incr = 0
 
         if int(n_entries) > 10:
             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
@@ -627,6 +635,7 @@ class IPsecUtil:
         tunnel_src = ip_address(tunnel_src)
         tunnel_dst = ip_address(tunnel_dst)
         traffic_addr = ip_address(traffic_addr)
+        tunnel_dst_prefix = 128 if tunnel_dst.version == 6 else 32
         addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
             else 1 << (32 - raddr_range)
 
@@ -636,11 +645,15 @@ class IPsecUtil:
             with open(tmp_filename, 'w') as tmp_file:
                 if_name = Topology.get_interface_name(node, interface)
                 for i in range(n_tunnels):
+                    tunnel_dst_addr = tunnel_dst + i * addr_incr
                     conf = f"exec set interface ip address {if_name} " \
                         f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
                         f"exec ip route add {traffic_addr + i}/" \
-                        f"{128 if traffic_addr.version == 6 else 32} " \
-                        f"via {tunnel_dst + i * addr_incr} {if_name}\n"
+                        f"{tunnel_dst_prefix} " \
+                        f"via {tunnel_dst_addr} {if_name}\n" \
+                        f"exec ip route add {tunnel_dst_addr}/" \
+                        f"{tunnel_dst_prefix} " \
+                        f"via {tunnel_dst_addr} {if_name}\n"
                     if dst_mac:
                         conf = f"{conf}exec set ip neighbor {if_name} " \
                                f"{tunnel_dst + i * addr_incr} {dst_mac}\n"
@@ -684,20 +697,29 @@ class IPsecUtil:
 
         with PapiSocketExecutor(node) as papi_exec:
             for i in range(n_tunnels):
+                tunnel_dst_addr = tunnel_dst + i * addr_incr
                 args1[u"prefix"] = IPUtil.create_prefix_object(
                     tunnel_src + i * addr_incr, raddr_range
                 )
                 args2[u"route"] = IPUtil.compose_vpp_route_structure(
                     node, traffic_addr + i,
-                    prefix_len=128 if traffic_addr.version == 6 else 32,
-                    interface=interface, gateway=tunnel_dst + i * addr_incr
+                    prefix_len=tunnel_dst_prefix,
+                    interface=interface, gateway=tunnel_dst_addr
                 )
                 history = bool(not 1 < i < n_tunnels - 2)
                 papi_exec.add(cmd1, history=history, **args1).\
                     add(cmd2, history=history, **args2)
+
+                args2[u"route"] = IPUtil.compose_vpp_route_structure(
+                    node, tunnel_dst_addr,
+                    prefix_len=tunnel_dst_prefix,
+                    interface=interface, gateway=tunnel_dst_addr
+                )
+                papi_exec.add(cmd2, history=history, **args2)
+
                 if dst_mac:
                     args3[u"neighbor"][u"ip_address"] = ip_address(
-                        tunnel_dst + i * addr_incr
+                        tunnel_dst_addr
                     )
                     papi_exec.add(cmd3, history=history, **args3)
             papi_exec.get_replies(err_msg)
@@ -2100,7 +2122,8 @@ class IPsecUtil:
     @staticmethod
     def vpp_ipsec_add_multiple_tunnels(
             nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
-            tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
+            tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range,
+            tunnel_addr_incr=True):
         """Create multiple IPsec tunnels between two VPP nodes.
 
         :param nodes: VPP nodes to create tunnels.
@@ -2117,6 +2140,8 @@ class IPsecUtil:
             first tunnel in direction node2->node1.
         :param raddr_range: Mask specifying range of Policy selector Remote
             IPv4 addresses. Valid values are from 1 to 32.
+        :param tunnel_addr_incr: Enable or disable tunnel IP address
+            incremental step.
         :type nodes: dict
         :type interface1: str or int
         :type interface2: str or int
@@ -2128,6 +2153,7 @@ class IPsecUtil:
         :type raddr_ip1: string
         :type raddr_ip2: string
         :type raddr_range: int
+        :type tunnel_addr_incr: bool
         """
         spd_id = 1
         p_hi = 100
@@ -2136,6 +2162,10 @@ class IPsecUtil:
         sa_id_2 = 200000
         spi_1 = 300000
         spi_2 = 400000
+        dut1_local_outbound_range = ip_network(f"{tunnel_ip1}/8", False).\
+            with_prefixlen
+        dut1_remote_outbound_range = ip_network(f"{tunnel_ip2}/8", False).\
+            with_prefixlen
 
         crypto_key = gen_key(
             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
@@ -2155,16 +2185,18 @@ class IPsecUtil:
         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
         IPsecUtil.vpp_ipsec_add_spd_entry(
             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
-            proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
+            proto=50, laddr_range=dut1_local_outbound_range,
+            raddr_range=dut1_remote_outbound_range
         )
         IPsecUtil.vpp_ipsec_add_spd_entry(
             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
-            proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
+            proto=50, laddr_range=dut1_remote_outbound_range,
+            raddr_range=dut1_local_outbound_range
         )
 
         IPsecUtil.vpp_ipsec_add_sad_entries(
             nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
-            integ_alg, integ_key, tunnel_ip1, tunnel_ip2
+            integ_alg, integ_key, tunnel_ip1, tunnel_ip2, tunnel_addr_incr
         )
 
         IPsecUtil.vpp_ipsec_add_spd_entries(
@@ -2176,7 +2208,7 @@ class IPsecUtil:
 
         IPsecUtil.vpp_ipsec_add_sad_entries(
             nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
-            integ_alg, integ_key, tunnel_ip2, tunnel_ip1
+            integ_alg, integ_key, tunnel_ip2, tunnel_ip1, tunnel_addr_incr
         )
         IPsecUtil.vpp_ipsec_add_spd_entries(
             nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
@@ -2186,26 +2218,28 @@ class IPsecUtil:
         )
 
         if u"DUT2" in nodes.keys():
+            rmac = Topology.get_interface_mac(nodes[u"DUT1"], interface1)
             IPsecUtil.vpp_ipsec_set_ip_route(
                 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
-                interface2, raddr_range)
+                interface2, raddr_range, rmac)
 
             IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
             IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
             IPsecUtil.vpp_ipsec_add_spd_entry(
                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
-                inbound=False, proto=50, laddr_range=u"100.0.0.0/8",
-                raddr_range=u"100.0.0.0/8"
+                inbound=False, proto=50, laddr_range=dut1_remote_outbound_range,
+                raddr_range=dut1_local_outbound_range
             )
             IPsecUtil.vpp_ipsec_add_spd_entry(
                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
-                inbound=True, proto=50, laddr_range=u"100.0.0.0/8",
-                raddr_range=u"100.0.0.0/8"
+                inbound=True, proto=50, laddr_range=dut1_local_outbound_range,
+                raddr_range=dut1_remote_outbound_range
             )
 
             IPsecUtil.vpp_ipsec_add_sad_entries(
                 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
-                crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2
+                crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2,
+                tunnel_addr_incr
             )
             IPsecUtil.vpp_ipsec_add_spd_entries(
                 nodes[u"DUT2"], n_tunnels, spd_id,
@@ -2217,7 +2251,8 @@ class IPsecUtil:
 
             IPsecUtil.vpp_ipsec_add_sad_entries(
                 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
-                crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1
+                crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1,
+                tunnel_addr_incr
             )
             IPsecUtil.vpp_ipsec_add_spd_entries(
                 nodes[u"DUT2"], n_tunnels, spd_id,
@@ -2247,3 +2282,53 @@ class IPsecUtil:
             u"ipsec_sa_v3_dump"
         ]
         PapiSocketExecutor.dump_and_log(node, cmds)
+
+    @staticmethod
+    def vpp_ipsec_flow_enale_rss(node, proto, type, function="default"):
+        """Ipsec flow enable rss action.
+
+        :param node: DUT node.
+        :param proto: The flow protocol.
+        :param type: RSS type.
+        :param function: RSS function.
+
+        :type node: dict
+        :type proto: str
+        :type type: str
+        :type function: str
+        :returns: flow_index.
+        """
+        # TODO: to be fixed to use full PAPI when it is ready in VPP
+        cmd = f"test flow add src-ip any proto {proto} rss function " \
+            f"{function} rss types {type}"
+        stdout = PapiSocketExecutor.run_cli_cmd(node, cmd)
+        flow_index = stdout.split()[1]
+
+        return flow_index
+
+    @staticmethod
+    def vpp_create_ipsec_flows_on_dut(
+            node, n_flows, rx_queues, spi_start, interface):
+        """Create mutiple ipsec flows and enable flows onto interface.
+
+        :param node: DUT node.
+        :param n_flows: Number of flows to create.
+        :param rx_queues: NUmber of RX queues.
+        :param spi_start: The start spi.
+        :param interface: Name of the interface.
+
+        :type node: dict
+        :type n_flows: int
+        :type rx_queues: int
+        :type spi_start: int
+        :type interface: str
+        :returns: flow_index.
+        """
+
+        for i in range(0, n_flows):
+            rx_queue = i%rx_queues
+
+            spi = spi_start + i
+            flow_index = FlowUtil.vpp_create_ip4_ipsec_flow(
+                    node, "ESP", spi, "redirect-to-queue", value=rx_queue)
+            FlowUtil.vpp_flow_enable(node, interface, flow_index)