From f7ee014dee09b4089924342b0fe5654b2fe91e90 Mon Sep 17 00:00:00 2001 From: Yulong Pei Date: Wed, 11 May 2022 04:29:50 +0000 Subject: Add ipsec policy test suites with flow director or rss accelerated The test scenario is about two private networks which communication was protected by ipsec. The test suites are to show performance impovement about ipsec esp flow lookup that offloaded by NIC flow director and rss. Verified on 3n-clx and Intel E810 NIC environment, with 64B ipsec packet flow, performance improved ~31% with 1C2T, ~110% with 2C4T, ~250% with 4C8T. Signed-off-by: xinfeng zhao Signed-off-by: Yulong Pei Change-Id: I30aec8c5115e5a6fbef88c11d1bef2624029d1b9 --- resources/libraries/python/FlowUtil.py | 110 ++++++++++++++++---------------- resources/libraries/python/IPsecUtil.py | 80 ++++++++++++++++++++--- 2 files changed, 127 insertions(+), 63 deletions(-) (limited to 'resources/libraries') diff --git a/resources/libraries/python/FlowUtil.py b/resources/libraries/python/FlowUtil.py index 3eb3b99519..23293b6dc6 100644 --- a/resources/libraries/python/FlowUtil.py +++ b/resources/libraries/python/FlowUtil.py @@ -1,4 +1,4 @@ -# copyright (c) 2021 Intel and/or its affiliates. +# copyright (c) 2022 Intel and/or its affiliates. # 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: @@ -13,12 +13,41 @@ """Flow Utilities Library.""" +from enum import IntEnum from ipaddress import ip_address from resources.libraries.python.topology import Topology from resources.libraries.python.ssh import exec_cmd_no_error from resources.libraries.python.PapiExecutor import PapiSocketExecutor +class FlowType(IntEnum): + """Flow types.""" + FLOW_TYPE_ETHERNET = 1 + FLOW_TYPE_IP4 = 2 + FLOW_TYPE_IP6 = 3 + FLOW_TYPE_IP4_L2TPV3OIP = 4 + FLOW_TYPE_IP4_IPSEC_ESP = 5 + FLOW_TYPE_IP4_IPSEC_AH = 6 + FLOW_TYPE_IP4_N_TUPLE = 7 + FLOW_TYPE_IP6_N_TUPLE = 8 + FLOW_TYPE_IP4_VXLAN = 11 + FLOW_TYPE_IP6_VXLAN = 12 + FLOW_TYPE_IP4_GTPU = 14 + +class FlowProto(IntEnum): + """Flow protocols.""" + IP_API_PROTO_TCP = 6 + IP_API_PROTO_UDP = 17 + IP_API_PROTO_ESP = 50 + IP_API_PROTO_AH = 51 + IP_API_PROTO_L2TP = 115 + +class FlowAction(IntEnum): + """Flow actions.""" + FLOW_ACTION_MARK = 2 + FLOW_ACTION_REDIRECT_TO_QUEUE = 16 + FLOW_ACTION_DROP = 64 + class FlowUtil: """Utilities for flow configuration.""" @@ -48,15 +77,13 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip4_n_tuple" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_N_TUPLE + flow_type = FlowType.FLOW_TYPE_IP4_N_TUPLE if proto == u"TCP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP + flow_proto = FlowProto.IP_API_PROTO_TCP elif proto == u"UDP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_proto = FlowProto.IP_API_PROTO_UDP else: raise ValueError(f"proto error: {proto}") @@ -99,15 +126,13 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip6_n_tuple" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP6_N_TUPLE + flow_type = FlowType.FLOW_TYPE_IP6_N_TUPLE if proto == u"TCP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP + flow_proto = FlowProto.IP_API_PROTO_TCP elif proto == u"UDP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_proto = FlowProto.IP_API_PROTO_UDP else: raise ValueError(f"proto error: {proto}") @@ -147,15 +172,13 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip4" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4 + flow_type = FlowType.FLOW_TYPE_IP4 if proto == u"TCP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP + flow_proto = FlowProto.IP_API_PROTO_TCP elif proto == u"UDP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_proto = FlowProto.IP_API_PROTO_UDP else: raise ValueError(f"proto error: {proto}") @@ -191,15 +214,13 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip6" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP6 + flow_type = FlowType.FLOW_TYPE_IP6 if proto == u"TCP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_TCP + flow_proto = FlowProto.IP_API_PROTO_TCP elif proto == u"UDP": - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_proto = FlowProto.IP_API_PROTO_UDP else: raise ValueError(f"proto error: {proto}") @@ -237,11 +258,9 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip4_gtpu" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_GTPU - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_type = FlowType.FLOW_TYPE_IP4_GTPU + flow_proto = FlowProto.IP_API_PROTO_UDP pattern = { u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"}, @@ -273,16 +292,14 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - if proto == u"ESP": flow = u"ip4_ipsec_esp" - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_ESP - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_IPSEC_ESP + flow_proto = FlowProto.IP_API_PROTO_ESP + flow_type = FlowType.FLOW_TYPE_IP4_IPSEC_ESP elif proto == u"AH": flow = u"ip4_ipsec_ah" - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_AH - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_IPSEC_AH + flow_proto = FlowProto.IP_API_PROTO_AH + flow_type = FlowType.FLOW_TYPE_IP4_IPSEC_AH else: raise ValueError(f"proto error: {proto}") @@ -312,11 +329,9 @@ class FlowUtil: :returns: flow_index. :rtype: int """ - from vpp_papi import VppEnum - flow = u"ip4_l2tpv3oip" - flow_proto = 115 # IP_API_PROTO_L2TP - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_L2TPV3OIP + flow_proto = FlowProto.IP_API_PROTO_L2TP + flow_type = FlowType.FLOW_TYPE_IP4_L2TPV3OIP pattern = { u'protocol': {u'prot': flow_proto}, @@ -347,11 +362,9 @@ class FlowUtil: :type value: int :returns: flow_index. """ - from vpp_papi import VppEnum - flow = u"ip4_vxlan" - flow_type = VppEnum.vl_api_flow_type_t.FLOW_TYPE_IP4_VXLAN - flow_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP + flow_type = FlowType.FLOW_TYPE_IP4_VXLAN + flow_proto = FlowProto.IP_API_PROTO_UDP pattern = { u'src_addr': {u'addr': src_ip, u'mask': u"255.255.255.255"}, @@ -387,29 +400,26 @@ class FlowUtil: :rtype: int :raises ValueError: If action type is not supported. """ - from vpp_papi import VppEnum - cmd = u"flow_add" if action == u"redirect-to-queue": flow_rule = { u'type': flow_type, - u'actions': VppEnum.vl_api_flow_action_t.\ - FLOW_ACTION_REDIRECT_TO_QUEUE, + u'actions': FlowAction.FLOW_ACTION_REDIRECT_TO_QUEUE, u'redirect_queue': value, u'flow': {flow : pattern} } elif action == u"mark": flow_rule = { u'type': flow_type, - u'actions': VppEnum.vl_api_flow_action_t.FLOW_ACTION_MARK, + u'actions': FlowAction.FLOW_ACTION_MARK, u'mark_flow_id': value, u'flow': {flow : pattern} } elif action == u"drop": flow_rule = { u'type': flow_type, - u'actions': VppEnum.vl_api_flow_action_t.FLOW_ACTION_DROP, + u'actions': FlowAction.FLOW_ACTION_DROP, u'flow': {flow : pattern} } else: @@ -437,8 +447,6 @@ class FlowUtil: :type flow_index: int :returns: Nothing. """ - from vpp_papi import VppEnum - cmd = u"flow_enable" sw_if_index = Topology.get_interface_sw_index(node, interface) args = dict( @@ -463,8 +471,6 @@ class FlowUtil: :type flow_index: int :returns: Nothing. """ - from vpp_papi import VppEnum - cmd = u"flow_disable" sw_if_index = Topology.get_interface_sw_index(node, interface) args = dict( @@ -487,8 +493,6 @@ class FlowUtil: :type flow_index: int :returns: Nothing. """ - from vpp_papi import VppEnum - cmd = u"flow_del" args = dict( flow_index=int(flow_index) @@ -508,8 +512,6 @@ class FlowUtil: :returns: flow entry. :rtype: str """ - from vpp_papi import VppEnum - cmd = u"vppctl show flow entry" err_msg = u"Failed to show flow on host {node[u'host']}" @@ -545,8 +547,6 @@ class FlowUtil: :raises RuntimeError: If the verification of flow action fails. :raises ValueError: If action type is not supported. """ - from vpp_papi import VppEnum - err_msg = f"Failed to show trace on host {node[u'host']}" cmd = u"vppctl show trace" stdout, _ = exec_cmd_no_error( diff --git a/resources/libraries/python/IPsecUtil.py b/resources/libraries/python/IPsecUtil.py index e3b3c88941..6ed2db1eae 100644 --- a/resources/libraries/python/IPsecUtil.py +++ b/resources/libraries/python/IPsecUtil.py @@ -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" @@ -2114,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. @@ -2131,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 @@ -2142,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 @@ -2184,7 +2196,7 @@ class IPsecUtil: 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( @@ -2196,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), @@ -2226,7 +2238,8 @@ class IPsecUtil: 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, @@ -2238,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, @@ -2268,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) -- cgit 1.2.3-korg