feat(api): Use newest API messages after rls2402
[csit.git] / resources / libraries / python / IPsecUtil.py
index 6ae8d10..214764d 100644 (file)
@@ -1,5 +1,5 @@
-# Copyright (c) 2023 Cisco and/or its affiliates.
-# Copyright (c) 2023 PANTHEON.tech s.r.o.
+# Copyright (c) 2024 Cisco and/or its affiliates.
+# Copyright (c) 2024 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:
 
 """IPsec utilities library."""
 
-import os
-
 from enum import Enum, IntEnum
 from io import open
 from ipaddress import ip_network, ip_address
 from random import choice
 from string import ascii_letters
 
+from robot.libraries.BuiltIn import BuiltIn
+
 from resources.libraries.python.Constants import Constants
 from resources.libraries.python.IncrementUtil import ObjIncrement
 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
@@ -36,7 +36,8 @@ from resources.libraries.python.VPPUtil import VPPUtil
 from resources.libraries.python.FlowUtil import FlowUtil
 
 
-IPSEC_UDP_PORT_NONE = 0xffff
+IPSEC_UDP_PORT_DEFAULT = 4500
+IPSEC_REPLAY_WINDOW_DEFAULT = 64
 
 
 def gen_key(length):
@@ -316,6 +317,8 @@ class IPsecUtil:
     def vpp_ipsec_set_async_mode(node, async_enable=1):
         """Set IPsec async mode on|off.
 
+        Unconditionally, attempt to switch crypto dispatch into polling mode.
+
         :param node: VPP node to set IPsec async mode.
         :param async_enable: Async mode on or off.
         :type node: dict
@@ -323,13 +326,23 @@ class IPsecUtil:
         :raises RuntimeError: If failed to set IPsec async mode or if no API
             reply received.
         """
-        cmd = u"ipsec_set_async_mode"
-        err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
-        args = dict(
-            async_enable=async_enable
-        )
         with PapiSocketExecutor(node) as papi_exec:
+            cmd = u"ipsec_set_async_mode"
+            err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
+            args = dict(
+                async_enable=async_enable
+            )
             papi_exec.add(cmd, **args).get_reply(err_msg)
+            cmd = "crypto_set_async_dispatch_v2"
+            err_msg = "Failed to set dispatch mode."
+            args = dict(mode=0, adaptive=False)
+            try:
+                papi_exec.add(cmd, **args).get_reply(err_msg)
+            except (AttributeError, RuntimeError):
+                # Expected when VPP build does not have the _v2 yet
+                # (after and before the first CRC check).
+                # TODO: Fail here when testing of pre-23.10 builds is over.
+                pass
 
     @staticmethod
     def vpp_ipsec_crypto_sw_scheduler_set_worker(
@@ -358,25 +371,26 @@ class IPsecUtil:
 
     @staticmethod
     def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
-            nodes, workers, crypto_enable=False):
+            nodes, crypto_enable=False):
         """Enable or disable crypto on specific vpp worker threads.
 
         :param node: VPP node to enable or disable crypto for worker threads.
-        :param workers: List of VPP thread numbers.
         :param crypto_enable: Disable or enable crypto work.
         :type node: dict
-        :type workers: Iterable[int]
         :type crypto_enable: bool
         :raises RuntimeError: If failed to enable or disable crypto for worker
             thread or if no API reply received.
         """
-        for node in nodes.values():
-            if node[u"type"] == NodeType.DUT:
+        for node_name, node in nodes.items():
+            if node["type"] == NodeType.DUT:
                 thread_data = VPPUtil.vpp_show_threads(node)
                 worker_cnt = len(thread_data) - 1
                 if not worker_cnt:
                     return None
                 worker_ids = list()
+                workers = BuiltIn().get_variable_value(
+                    f"${{{node_name}_cpu_dp}}"
+                )
                 for item in thread_data:
                     if str(item.cpu_id) in workers.split(u","):
                         worker_ids.append(item.id)
@@ -437,7 +451,7 @@ class IPsecUtil:
             src_addr = u""
             dst_addr = u""
 
-        cmd = u"ipsec_sad_entry_add"
+        cmd = u"ipsec_sad_entry_add_v2"
         err_msg = f"Failed to add Security Association Database entry " \
             f"on host {node[u'host']}"
         sad_entry = dict(
@@ -458,8 +472,9 @@ class IPsecUtil:
                 dscp=int(IpDscp.IP_API_DSCP_CS0),
             ),
             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
-            udp_src_port=4500,  # default value in api
-            udp_dst_port=4500  # default value in api
+            udp_src_port=IPSEC_UDP_PORT_DEFAULT,
+            udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
+            anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
         )
         args = dict(entry=sad_entry)
         with PapiSocketExecutor(node) as papi_exec:
@@ -468,7 +483,7 @@ 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.
 
@@ -534,7 +549,7 @@ class IPsecUtil:
                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
                 )
 
-        cmd = u"ipsec_sad_entry_add"
+        cmd = u"ipsec_sad_entry_add_v2"
         err_msg = f"Failed to add Security Association Database entry " \
             f"on host {node[u'host']}"
 
@@ -556,8 +571,9 @@ class IPsecUtil:
                 dscp=int(IpDscp.IP_API_DSCP_CS0),
             ),
             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
-            udp_src_port=4500,  # default value in api
-            udp_dst_port=4500,  # default value in api
+            udp_src_port=IPSEC_UDP_PORT_DEFAULT,
+            udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
+            anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
         )
         args = dict(entry=sad_entry)
         with PapiSocketExecutor(node, is_async=True) as papi_exec:
@@ -879,7 +895,7 @@ class IPsecUtil:
         local_net = ip_network(laddr_range, strict=False)
         remote_net = ip_network(raddr_range, strict=False)
 
-        cmd = u"ipsec_spd_entry_add_del"
+        cmd = u"ipsec_spd_entry_add_del_v2"
 
         spd_entry = dict(
             spd_id=int(spd_id),
@@ -887,7 +903,7 @@ class IPsecUtil:
             is_outbound=not inbound,
             sa_id=int(sa_id) if sa_id else 0,
             policy=int(action),
-            protocol=int(proto) if proto else 0,
+            protocol=255 if proto is None else int(proto),
             remote_address_start=IPAddress.create_ip_address_object(
                 remote_net.network_address
             ),
@@ -1214,7 +1230,7 @@ class IPsecUtil:
             # Configure IPSec SAD entries
             ckeys = [bytes()] * existing_tunnels
             ikeys = [bytes()] * existing_tunnels
-            cmd = u"ipsec_sad_entry_add"
+            cmd = u"ipsec_sad_entry_add_v2"
             c_key = dict(
                 length=0,
                 data=None
@@ -1242,8 +1258,9 @@ class IPsecUtil:
                     dscp=int(IpDscp.IP_API_DSCP_CS0),
                 ),
                 salt=0,
-                udp_src_port=IPSEC_UDP_PORT_NONE,
-                udp_dst_port=IPSEC_UDP_PORT_NONE,
+                udp_src_port=IPSEC_UDP_PORT_DEFAULT,
+                udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
+                anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
             )
             args = dict(entry=sad_entry)
             for i in range(existing_tunnels, n_tunnels):
@@ -1453,7 +1470,7 @@ class IPsecUtil:
                 ]
             )
             # Configure IPSec SAD entries
-            cmd = u"ipsec_sad_entry_add"
+            cmd = u"ipsec_sad_entry_add_v2"
             c_key = dict(
                 length=0,
                 data=None
@@ -1481,8 +1498,9 @@ class IPsecUtil:
                     dscp=int(IpDscp.IP_API_DSCP_CS0),
                 ),
                 salt=0,
-                udp_src_port=IPSEC_UDP_PORT_NONE,
-                udp_dst_port=IPSEC_UDP_PORT_NONE,
+                udp_src_port=IPSEC_UDP_PORT_DEFAULT,
+                udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
+                anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
             )
             args = dict(entry=sad_entry)
             for i in range(existing_tunnels, n_tunnels):
@@ -1887,10 +1905,6 @@ 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)
@@ -1908,16 +1922,27 @@ class IPsecUtil:
 
         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
         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=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=dut1_remote_outbound_range,
-            raddr_range=dut1_local_outbound_range
-        )
+
+        addr_incr = 1 << (128 - 96) if ip_address(tunnel_ip1).version == 6 \
+            else 1 << (32 - 24)
+        for i in range(n_tunnels//(addr_incr**2)+1):
+            dut1_local_outbound_range = \
+                ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
+                           False).with_prefixlen
+            dut1_remote_outbound_range = \
+                ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
+                           False).with_prefixlen
+
+            IPsecUtil.vpp_ipsec_add_spd_entry(
+                nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
+                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=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,
@@ -1950,16 +1975,26 @@ class IPsecUtil:
 
             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=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=dut1_local_outbound_range,
-                raddr_range=dut1_remote_outbound_range
-            )
+            for i in range(n_tunnels//(addr_incr**2)+1):
+                dut2_local_outbound_range = \
+                    ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
+                               False).with_prefixlen
+                dut2_remote_outbound_range = \
+                    ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
+                               False).with_prefixlen
+
+                IPsecUtil.vpp_ipsec_add_spd_entry(
+                    nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
+                    inbound=False, proto=50,
+                    laddr_range=dut2_remote_outbound_range,
+                    raddr_range=dut2_local_outbound_range
+                )
+                IPsecUtil.vpp_ipsec_add_spd_entry(
+                    nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
+                    inbound=True, proto=50,
+                    laddr_range=dut2_local_outbound_range,
+                    raddr_range=dut2_remote_outbound_range
+                )
 
             IPsecUtil.vpp_ipsec_add_sad_entries(
                 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
@@ -2003,10 +2038,8 @@ class IPsecUtil:
         :param node: DUT node.
         :type node: dict
         """
-        cmds = [
-            u"ipsec_sa_v3_dump"
-        ]
-        PapiSocketExecutor.dump_and_log(node, cmds)
+        cmd = "ipsec_sa_v5_dump"
+        PapiSocketExecutor.dump_and_log(node, [cmd])
 
     @staticmethod
     def vpp_ipsec_flow_enale_rss(node, proto, type, function="default"):
@@ -2052,8 +2085,7 @@ class IPsecUtil:
 
         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)
+                node, "ESP", spi, "redirect-to-queue", value=rx_queue)
             FlowUtil.vpp_flow_enable(node, interface, flow_index)