+ subif_types = type_subif.split()
+
+ cmd = 'create_subif'
+ args = dict(
+ sw_if_index=InterfaceUtil.get_interface_index(node, interface),
+ sub_id=int(sub_id),
+ no_tags=1 if 'no_tags' in subif_types else 0,
+ one_tag=1 if 'one_tag' in subif_types else 0,
+ two_tags=1 if 'two_tags' in subif_types else 0,
+ dot1ad=1 if 'dot1ad' in subif_types else 0,
+ exact_match=1 if 'exact_match' in subif_types else 0,
+ default_sub=1 if 'default_sub' in subif_types else 0,
+ outer_vlan_id_any=1 if type_subif == 'default_sub' else 0,
+ inner_vlan_id_any=1 if type_subif == 'default_sub' else 0,
+ outer_vlan_id=int(outer_vlan_id) if outer_vlan_id else 0,
+ inner_vlan_id=int(inner_vlan_id) if inner_vlan_id else 0)
+ err_msg = 'Failed to create sub-interface on host {host}'.format(
+ host=node['host'])
+ with PapiSocketExecutor(node) as papi_exec:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ if_key = Topology.add_new_port(node, 'subinterface')
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
+ Topology.update_interface_name(node, if_key, ifc_name)
+
+ return '{ifc}.{s_id}'.format(ifc=interface, s_id=sub_id), sw_if_index
+
+ @staticmethod
+ def create_gre_tunnel_interface(node, source_ip, destination_ip):
+ """Create GRE tunnel interface on node.
+
+ :param node: VPP node to add tunnel interface.
+ :param source_ip: Source of the GRE tunnel.
+ :param destination_ip: Destination of the GRE tunnel.
+ :type node: dict
+ :type source_ip: str
+ :type destination_ip: str
+ :returns: Name and index of created GRE tunnel interface.
+ :rtype: tuple
+ :raises RuntimeError: If unable to create GRE tunnel interface.
+ """
+ cmd = 'gre_tunnel_add_del'
+ tunnel = dict(type=0,
+ instance=Constants.BITWISE_NON_ZERO,
+ src=str(source_ip),
+ dst=str(destination_ip),
+ outer_fib_id=0,
+ session_id=0)
+ args = dict(is_add=1,
+ tunnel=tunnel)
+ err_msg = 'Failed to create GRE tunnel interface on host {host}'.format(
+ host=node['host'])
+ with PapiSocketExecutor(node) as papi_exec:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ if_key = Topology.add_new_port(node, 'gre_tunnel')
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
+ Topology.update_interface_name(node, if_key, ifc_name)
+
+ return ifc_name, sw_if_index
+
+ @staticmethod
+ def vpp_create_loopback(node, mac=None):
+ """Create loopback interface on VPP node.
+
+ :param node: Node to create loopback interface on.
+ :param mac: Optional MAC address for Loopback interface.
+ :type node: dict
+ :type mac: str
+ :returns: SW interface index.
+ :rtype: int
+ :raises RuntimeError: If it is not possible to create loopback on the
+ node.
+ """
+ cmd = 'create_loopback'
+ args = dict(mac_address=L2Util.mac_to_bin(mac) if mac else 0)
+ err_msg = 'Failed to create loopback interface on host {host}'.format(
+ host=node['host'])
+ with PapiSocketExecutor(node) as papi_exec:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ if_key = Topology.add_new_port(node, 'loopback')
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
+ Topology.update_interface_name(node, if_key, ifc_name)
+ if mac:
+ mac = InterfaceUtil.vpp_get_interface_mac(node, ifc_name)
+ Topology.update_interface_mac_address(node, if_key, mac)
+
+ return sw_if_index
+
+ @staticmethod
+ def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
+ """Create bond interface on VPP node.
+
+ :param node: DUT node from topology.
+ :param mode: Link bonding mode.
+ :param load_balance: Load balance (optional, valid for xor and lacp
+ modes, otherwise ignored).
+ :param mac: MAC address to assign to the bond interface (optional).
+ :type node: dict
+ :type mode: str
+ :type load_balance: str
+ :type mac: str
+ :returns: Interface key (name) in topology.
+ :rtype: str
+ :raises RuntimeError: If it is not possible to create bond interface on
+ the node.
+ """
+ cmd = 'bond_create'
+ args = dict(id=int(Constants.BITWISE_NON_ZERO),
+ use_custom_mac=0 if mac is None else 1,
+ mac_address=0 if mac is None else L2Util.mac_to_bin(mac),
+ mode=getattr(LinkBondMode, '{md}'.format(
+ md=mode.replace('-', '_').upper())).value,
+ lb=0 if load_balance is None else getattr(
+ LinkBondLoadBalance, '{lb}'.format(
+ lb=load_balance.upper())).value)
+ err_msg = 'Failed to create bond interface on host {host}'.format(
+ host=node['host'])
+ with PapiSocketExecutor(node) as papi_exec:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ InterfaceUtil.add_eth_interface(node, sw_if_index=sw_if_index,
+ ifc_pfx='eth_bond')
+ if_key = Topology.get_interface_by_sw_index(node, sw_if_index)
+
+ return if_key
+
+ @staticmethod
+ def add_eth_interface(node, ifc_name=None, sw_if_index=None, ifc_pfx=None):
+ """Add ethernet interface to current topology.
+
+ :param node: DUT node from topology.
+ :param ifc_name: Name of the interface.
+ :param sw_if_index: SW interface index.
+ :param ifc_pfx: Interface key prefix.
+ :type node: dict
+ :type ifc_name: str
+ :type sw_if_index: int
+ :type ifc_pfx: str
+ """
+ if_key = Topology.add_new_port(node, ifc_pfx)
+
+ if ifc_name and sw_if_index is None:
+ sw_if_index = InterfaceUtil.vpp_get_interface_sw_index(
+ node, ifc_name)
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
+ if sw_if_index and ifc_name is None:
+ ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
+ Topology.update_interface_name(node, if_key, ifc_name)
+ ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
+ Topology.update_interface_mac_address(node, if_key, ifc_mac)
+
+ @staticmethod
+ def vpp_create_avf_interface(node, vf_pci_addr, num_rx_queues=None):
+ """Create AVF interface on VPP node.
+
+ :param node: DUT node from topology.
+ :param vf_pci_addr: Virtual Function PCI address.
+ :param num_rx_queues: Number of RX queues.
+ :type node: dict
+ :type vf_pci_addr: str
+ :type num_rx_queues: int
+ :returns: Interface key (name) in topology.
+ :rtype: str
+ :raises RuntimeError: If it is not possible to create AVF interface on
+ the node.
+ """
+ cmd = 'avf_create'
+ args = dict(pci_addr=InterfaceUtil.pci_to_int(vf_pci_addr),
+ enable_elog=0,
+ rxq_num=int(num_rx_queues) if num_rx_queues else 0,
+ rxq_size=0,
+ txq_size=0)
+ err_msg = 'Failed to create AVF interface on host {host}'.format(
+ host=node['host'])
+ with PapiSocketExecutor(node) as papi_exec:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ InterfaceUtil.add_eth_interface(node, sw_if_index=sw_if_index,
+ ifc_pfx='eth_avf')
+ if_key = Topology.get_interface_by_sw_index(node, sw_if_index)
+
+ return if_key
+
+ @staticmethod
+ def vpp_enslave_physical_interface(node, interface, bond_if):
+ """Enslave physical 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 enslave physical
+ interface to bond interface on the node.
+ """
+ cmd = 'bond_enslave'
+ 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=0,
+ is_long_timeout=0)
+ err_msg = 'Failed to enslave physical interface {ifc} to bond ' \
+ 'interface {bond} on host {host}'.format(ifc=interface,
+ bond=bond_if,
+ host=node['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 = 'sw_interface_bond_dump'
+ err_msg = 'Failed to get bond interface dump on host {host}'.format(
+ host=node['host'])
+
+ data = ('Bond data on node {host}:\n'.format(host=node['host']))
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd).get_details(err_msg)
+
+ for bond in details:
+ data += ('{b}\n'.format(b=bond['interface_name'].rstrip('\x00')))
+ data += (' mode: {m}\n'.format(m=bond['mode']).lower())
+ data += (' load balance: {lb}\n'.format(lb=bond['lb']).lower())
+ data += (' number of active slaves: {n}\n'.format(
+ n=bond['active_slaves']))
+ if verbose:
+ slave_data = InterfaceUtil.vpp_bond_slave_dump(
+ node, Topology.get_interface_by_sw_index(
+ node, bond['sw_if_index']))
+ for slave in slave_data:
+ if not slave['is_passive']:
+ data += (' {s}\n'.format(s=slave['interface_name']))
+ data += (' number of slaves: {n}\n'.format(n=bond['slaves']))
+ if verbose:
+ for slave in slave_data:
+ data += (' {s}\n'.format(s=slave['interface_name']))
+ data += (' interface id: {i}\n'.format(i=bond['id']))
+ data += (' sw_if_index: {i}\n'.format(i=bond['sw_if_index']))
+ logger.info(data)
+
+ @staticmethod
+ def vpp_bond_slave_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
+ """
+ def process_slave_dump(slave_dump):
+ """Process slave dump.
+
+ :param slave_dump: Slave interface dump.
+ :type slave_dump: dict
+ :returns: Processed slave interface dump.
+ :rtype: dict
+ """
+ slave_dump['interface_name'] = slave_dump['interface_name'].\
+ rstrip('\x00')
+ return slave_dump
+
+ cmd = 'sw_interface_slave_dump'
+ args = dict(sw_if_index=Topology.get_interface_sw_index(
+ node, interface))
+ err_msg = 'Failed to get slave dump on host {host}'.format(
+ host=node['host'])
+
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd, **args).get_details(err_msg)
+
+ for dump in details:
+ # In-place edits.
+ process_slave_dump(dump)
+
+ logger.debug('Slave data:\n{slave_data}'.format(slave_data=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['type'] == NodeType.DUT:
+ InterfaceUtil.vpp_show_bond_data_on_node(node_data, verbose)