diff options
author | 2021-05-26 16:06:02 +0000 | |
---|---|---|
committer | 2021-06-04 06:45:39 +0000 | |
commit | 0ffdf07bf4b081d5527e7544fc38dc710a3f4537 (patch) | |
tree | 258ec46d4169ab55c10c454b4ea1f964be54a72c /resources/libraries/python/InterfaceUtil.py | |
parent | f96f85afe534f5edda9414ce8cceed66b7619b3c (diff) |
Performance: Add AF_XDP tests
- enabling for fortville, columbiaville
- enabling experimental for mlx
Signed-off-by: pmikus <pmikus@cisco.com>
Change-Id: I1b7ceb54769f4a0089ac7309350499e60c5cca0a
(cherry picked from commit 4a0b0f2b633bb9fd15a7dc8357650a9ac7846edd)
Diffstat (limited to 'resources/libraries/python/InterfaceUtil.py')
-rw-r--r-- | resources/libraries/python/InterfaceUtil.py | 178 |
1 files changed, 155 insertions, 23 deletions
diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index bf36635915..939a34b8d1 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -111,6 +111,13 @@ class RdmaMode(IntEnum): RDMA_API_MODE_DV = 2 +class AfXdpMode(IntEnum): + """AF_XDP interface mode.""" + AF_XDP_API_MODE_AUTO = 0 + AF_XDP_API_MODE_COPY = 1 + AF_XDP_API_MODE_ZERO_COPY = 2 + + class InterfaceUtil: """General utilities for managing interfaces""" @@ -229,6 +236,26 @@ class InterfaceUtil: ) @staticmethod + def set_interface_state_pci( + node, pf_pcis, namespace=None, state=u"up"): + """Set operational state for interface specified by PCI address. + + :param node: Topology node. + :param pf_pcis: List of node's interfaces PCI addresses. + :param namespace: Exec command in namespace. (Optional, Default: none) + :param state: Up/Down. (Optional, default: up) + :type nodes: dict + :type pf_pcis: list + :type namespace: str + :type state: str + """ + for pf_pci in pf_pcis: + pf_eth = InterfaceUtil.pci_to_eth(node, pf_pci) + InterfaceUtil.set_linux_interface_state( + node, pf_eth, namespace=namespace, state=state + ) + + @staticmethod def set_interface_mtu(node, pf_pcis, mtu=9200): """Set Ethernet MTU for specified interfaces. @@ -246,25 +273,43 @@ class InterfaceUtil: exec_cmd_no_error(node, cmd, sudo=True) @staticmethod - def set_interface_flow_control(node, pf_pcis, rx=u"off", tx=u"off"): + def set_interface_channels( + node, pf_pcis, num_queues=1, channel=u"combined"): + """Set interface channels for specified interfaces. + + :param node: Topology node. + :param pf_pcis: List of node's interfaces PCI addresses. + :param num_queues: Number of channels. (Optional, Default: 1) + :param channel: Channel type. (Optional, Default: combined) + :type nodes: dict + :type pf_pcis: list + :type num_queues: int + :type channel: str + """ + for pf_pci in pf_pcis: + pf_eth = InterfaceUtil.pci_to_eth(node, pf_pci) + cmd = f"ethtool --set-channels {pf_eth} {channel} {num_queues}" + exec_cmd_no_error(node, cmd, sudo=True) + + @staticmethod + def set_interface_flow_control(node, pf_pcis, rxf=u"off", txf=u"off"): """Set Ethernet flow control for specified interfaces. :param node: Topology node. :param pf_pcis: List of node's interfaces PCI addresses. - :param rx: RX flow. Default: off. - :param tx: TX flow. Default: off. + :param rxf: RX flow. (Optional, Default: off). + :param txf: TX flow. (Optional, Default: off). :type nodes: dict :type pf_pcis: list - :type rx: str - :type tx: str + :type rxf: str + :type txf: str """ for pf_pci in pf_pcis: pf_eth = InterfaceUtil.pci_to_eth(node, pf_pci) - cmd = f"ethtool -A {pf_eth} rx off tx off" + cmd = f"ethtool -A {pf_eth} rx {rxf} tx {txf}" ret_code, _, _ = exec_cmd(node, cmd, sudo=True) if int(ret_code) not in (0, 78): - raise RuntimeError("Failed to set MTU on {pf_eth}!") - + raise RuntimeError("Failed to set flow control on {pf_eth}!") @staticmethod def set_pci_parameter(node, pf_pcis, key, value): @@ -309,8 +354,7 @@ class InterfaceUtil: with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) except AssertionError as err: - # TODO: Make failure tolerance optional. - logger.debug(f"Setting MTU failed. Expected?\n{err}") + logger.debug(f"Setting MTU failed.\n{err}") @staticmethod def vpp_set_interfaces_mtu_on_node(node, mtu=9200): @@ -1183,6 +1227,58 @@ class InterfaceUtil: return Topology.get_interface_by_sw_index(node, sw_if_index) @staticmethod + def vpp_create_af_xdp_interface( + node, if_key, num_rx_queues=None, rxq_size=0, txq_size=0, + mode=u"auto"): + """Create AF_XDP interface on VPP node. + + :param node: DUT node from topology. + :param if_key: Physical interface key from topology file of interface + to be bound to compatible driver. + :param num_rx_queues: Number of RX queues. (Optional, Default: none) + :param rxq_size: Size of RXQ (0 = Default API; 512 = Default VPP). + :param txq_size: Size of TXQ (0 = Default API; 512 = Default VPP). + :param mode: AF_XDP interface mode. (Optional, Default: auto). + :type node: dict + :type if_key: str + :type num_rx_queues: int + :type rxq_size: int + :type txq_size: int + :type mode: str + :returns: Interface key (name) in topology file. + :rtype: str + :raises RuntimeError: If it is not possible to create AF_XDP interface + on the node. + """ + PapiSocketExecutor.run_cli_cmd( + node, u"set logging class af_xdp level debug" + ) + + cmd = u"af_xdp_create" + pci_addr = Topology.get_interface_pci_addr(node, if_key) + args = dict( + name=InterfaceUtil.pci_to_eth(node, pci_addr), + host_if=InterfaceUtil.pci_to_eth(node, pci_addr), + rxq_num=int(num_rx_queues) if num_rx_queues else 0, + rxq_size=rxq_size, + txq_size=txq_size, + mode=getattr(AfXdpMode, f"AF_XDP_API_MODE_{mode.upper()}").value + ) + err_msg = f"Failed to create AF_XDP interface on host {node[u'host']}" + with PapiSocketExecutor(node) as papi_exec: + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) + + InterfaceUtil.vpp_set_interface_mac( + node, sw_if_index, Topology.get_interface_mac(node, if_key) + ) + InterfaceUtil.add_eth_interface( + node, sw_if_index=sw_if_index, ifc_pfx=u"eth_af_xdp", + host_if_key=if_key + ) + + return Topology.get_interface_by_sw_index(node, sw_if_index) + + @staticmethod def vpp_create_rdma_interface( node, if_key, num_rx_queues=None, rxq_size=0, txq_size=0, mode=u"auto"): @@ -1219,7 +1315,7 @@ class InterfaceUtil: rxq_size=rxq_size, txq_size=txq_size, mode=getattr(RdmaMode, f"RDMA_API_MODE_{mode.upper()}").value, - # TODO: Set True for non-jumbo packets. + # Note: Set True for non-jumbo packets. no_multi_seg=False, max_pktlen=0, ) @@ -1577,9 +1673,52 @@ class InterfaceUtil: exec_cmd_no_error(node, cmd, sudo=True) @staticmethod - def init_avf_interface(node, ifc_key, numvfs=1, osi_layer=u"L2"): - """Init PCI device by creating VIFs and bind them to vfio-pci for AVF - driver testing on DUT. + def init_interface(node, ifc_key, driver, numvfs=0, osi_layer=u"L2"): + """Init PCI device. Check driver compatibility and bind to proper + drivers. Optionally create NIC VFs. + + :param node: DUT node. + :param ifc_key: Interface key from topology file. + :param driver: Base driver to use. + :param numvfs: Number of VIFs to initialize, 0 - disable the VIFs. + :param osi_layer: OSI Layer type to initialize TG with. + Default value "L2" sets linux interface spoof off. + :type node: dict + :type ifc_key: str + :type driver: str + :type numvfs: int + :type osi_layer: str + :returns: Virtual Function topology interface keys. + :rtype: list + :raises RuntimeError: If a reason preventing initialization is found. + """ + kernel_driver = Topology.get_interface_driver(node, ifc_key) + vf_keys = [] + if driver == u"avf": + if kernel_driver not in ( + u"ice", u"iavf", u"i40e", u"i40evf"): + raise RuntimeError( + f"AVF needs ice or i40e compatible driver, not " + f"{kernel_driver} at node {node[u'host']} ifc {ifc_key}" + ) + vf_keys = InterfaceUtil.init_generic_interface( + node, ifc_key, numvfs=numvfs, osi_layer=osi_layer + ) + elif driver == u"af_xdp": + if kernel_driver not in ( + u"ice", u"iavf", u"i40e", u"i40evf", u"mlx5_core"): + raise RuntimeError( + f"AF_XDP needs ice or i40e or rdma compatible driver, not " + f"{kernel_driver} at node {node[u'host']} ifc {ifc_key}" + ) + vf_keys = InterfaceUtil.init_generic_interface( + node, ifc_key, numvfs=numvfs, osi_layer=osi_layer + ) + return vf_keys + + @staticmethod + def init_generic_interface(node, ifc_key, numvfs=0, osi_layer=u"L2"): + """Init PCI device. Bind to proper drivers. Optionally create NIC VFs. :param node: DUT node. :param ifc_key: Interface key from topology file. @@ -1599,11 +1738,6 @@ class InterfaceUtil: pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":") uio_driver = Topology.get_uio_driver(node) kernel_driver = Topology.get_interface_driver(node, ifc_key) - if kernel_driver not in (u"ice", u"iavf", u"i40e", u"i40evf"): - raise RuntimeError( - f"AVF needs ice or i40e compatible driver, not {kernel_driver}" - f"at node {node[u'host']} ifc {ifc_key}" - ) current_driver = DUTSetup.get_pci_dev_driver( node, pf_pci_addr.replace(u":", r"\:")) @@ -1726,8 +1860,7 @@ class InterfaceUtil: @staticmethod def vpp_round_robin_rx_placement( - node, prefix, dp_worker_limit=None - ): + node, prefix, dp_worker_limit=None): """Set Round Robin interface RX placement on all worker threads on node. @@ -1762,8 +1895,7 @@ class InterfaceUtil: @staticmethod def vpp_round_robin_rx_placement_on_all_duts( - nodes, prefix, dp_core_limit=None - ): + nodes, prefix, dp_core_limit=None): """Set Round Robin interface RX placement on all worker threads on all DUTs. |