+ raise AssertionError(err_msg)
+
+ InterfaceUtil.add_eth_interface(
+ node, sw_if_index=sw_if_index, ifc_pfx=u"eth_avf",
+ host_if_key=if_key
+ )
+
+ 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"):
+ """Create RDMA 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 rdma-core driver.
+ :param num_rx_queues: Number of RX queues.
+ :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: RDMA interface mode - auto/ibv/dv.
+ :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 RDMA interface on
+ the node.
+ """
+ PapiSocketExecutor.run_cli_cmd(
+ node, u"set logging class rdma level debug"
+ )
+
+ cmd = u"rdma_create_v2"
+ 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(RdmaMode, f"RDMA_API_MODE_{mode.upper()}").value,
+ # Note: Set True for non-jumbo packets.
+ no_multi_seg=False,
+ max_pktlen=0,
+ )
+ err_msg = f"Failed to create RDMA 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_rdma",
+ host_if_key=if_key
+ )
+
+ return Topology.get_interface_by_sw_index(node, sw_if_index)
+
+ @staticmethod
+ def vpp_add_bond_member(node, interface, bond_if):
+ """Add member interface to bond interface on VPP node.
+
+ :param node: DUT node from topology.
+ :param interface: Physical interface key from topology file.
+ :param bond_if: Load balance
+ :type node: dict
+ :type interface: str
+ :type bond_if: str
+ :raises RuntimeError: If it is not possible to add member to bond
+ interface on the node.
+ """
+ cmd = u"bond_add_member"
+ args = dict(
+ sw_if_index=Topology.get_interface_sw_index(node, interface),
+ bond_sw_if_index=Topology.get_interface_sw_index(node, bond_if),
+ is_passive=False,
+ is_long_timeout=False
+ )
+ err_msg = f"Failed to add member {interface} to bond interface " \
+ f"{bond_if} on host {node[u'host']}"
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def vpp_show_bond_data_on_node(node, verbose=False):
+ """Show (detailed) bond information on VPP node.
+
+ :param node: DUT node from topology.
+ :param verbose: If detailed information is required or not.
+ :type node: dict
+ :type verbose: bool
+ """
+ cmd = u"sw_bond_interface_dump"
+ err_msg = f"Failed to get bond interface dump on host {node[u'host']}"
+
+ data = f"Bond data on node {node[u'host']}:\n"
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd).get_details(err_msg)
+
+ for bond in details:
+ data += f"{bond[u'interface_name']}\n"
+ data += u" mode: {m}\n".format(
+ m=bond[u"mode"].name.replace(u"BOND_API_MODE_", u"").lower()
+ )
+ data += u" load balance: {lb}\n".format(
+ lb=bond[u"lb"].name.replace(u"BOND_API_LB_ALGO_", u"").lower()
+ )
+ data += f" number of active members: {bond[u'active_members']}\n"
+ if verbose:
+ member_data = InterfaceUtil.vpp_bond_member_dump(
+ node, Topology.get_interface_by_sw_index(
+ node, bond[u"sw_if_index"]
+ )
+ )
+ for member in member_data:
+ if not member[u"is_passive"]:
+ data += f" {member[u'interface_name']}\n"
+ data += f" number of members: {bond[u'members']}\n"
+ if verbose:
+ for member in member_data:
+ data += f" {member[u'interface_name']}\n"
+ data += f" interface id: {bond[u'id']}\n"
+ data += f" sw_if_index: {bond[u'sw_if_index']}\n"
+ logger.info(data)
+
+ @staticmethod
+ def vpp_bond_member_dump(node, interface):
+ """Get bond interface slave(s) data on VPP node.
+
+ :param node: DUT node from topology.
+ :param interface: Physical interface key from topology file.
+ :type node: dict
+ :type interface: str
+ :returns: Bond slave interface data.
+ :rtype: dict
+ """
+ cmd = u"sw_member_interface_dump"
+ args = dict(
+ sw_if_index=Topology.get_interface_sw_index(node, interface)
+ )
+ err_msg = f"Failed to get slave dump on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd, **args).get_details(err_msg)
+
+ logger.debug(f"Member data:\n{details}")
+ return details
+
+ @staticmethod
+ def vpp_show_bond_data_on_all_nodes(nodes, verbose=False):
+ """Show (detailed) bond information on all VPP nodes in DICT__nodes.
+
+ :param nodes: Nodes in the topology.
+ :param verbose: If detailed information is required or not.
+ :type nodes: dict
+ :type verbose: bool
+ """
+ for node_data in nodes.values():
+ if node_data[u"type"] == NodeType.DUT:
+ InterfaceUtil.vpp_show_bond_data_on_node(node_data, verbose)