+ :param node: VPP node to get interface data from.
+ :param interface: Numeric index or name string of a specific interface.
+ If None, information about all VxLAN interfaces is returned.
+ :type node: dict
+ :type interface: int or str
+ :returns: Dictionary containing data for the given VxLAN interface or if
+ interface=None, the list of dictionaries with all VxLAN interfaces.
+ :rtype: dict or list
+ :raises TypeError: if the data type of interface is neither basestring
+ nor int.
+ """
+ def process_vxlan_dump(vxlan_dump):
+ """Process vxlan dump.
+
+ :param vxlan_dump: Vxlan interface dump.
+ :type vxlan_dump: dict
+ :returns: Processed vxlan interface dump.
+ :rtype: dict
+ """
+ vxlan_dump[u"src_address"] = str(vxlan_dump[u"src_address"])
+ vxlan_dump[u"dst_address"] = str(vxlan_dump[u"dst_address"])
+ return vxlan_dump
+
+ if interface is not None:
+ sw_if_index = InterfaceUtil.get_interface_index(node, interface)
+ else:
+ sw_if_index = int(Constants.BITWISE_NON_ZERO)
+
+ cmd = u"vxlan_tunnel_dump"
+ args = dict(
+ sw_if_index=sw_if_index
+ )
+ err_msg = f"Failed to get VXLAN dump on host {node[u'host']}"
+
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd, **args).get_details(err_msg)
+
+ data = list() if interface is None else dict()
+ for dump in details:
+ if interface is None:
+ data.append(process_vxlan_dump(dump))
+ elif dump[u"sw_if_index"] == sw_if_index:
+ data = process_vxlan_dump(dump)
+ break
+
+ logger.debug(f"VXLAN data:\n{data}")
+ return data
+
+ @staticmethod
+ def create_subinterface(
+ node, interface, sub_id, outer_vlan_id=None, inner_vlan_id=None,
+ type_subif=None):
+ """Create sub-interface on node. It is possible to set required
+ sub-interface type and VLAN tag(s).
+
+ :param node: Node to add sub-interface.
+ :param interface: Interface name on which create sub-interface.
+ :param sub_id: ID of the sub-interface to be created.
+ :param outer_vlan_id: Optional outer VLAN ID.
+ :param inner_vlan_id: Optional inner VLAN ID.
+ :param type_subif: Optional type of sub-interface. Values supported by
+ VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
+ [default_sub]
+ :type node: dict
+ :type interface: str or int
+ :type sub_id: int
+ :type outer_vlan_id: int
+ :type inner_vlan_id: int
+ :type type_subif: str
+ :returns: Name and index of created sub-interface.
+ :rtype: tuple
+ :raises RuntimeError: If it is not possible to create sub-interface.
+ """
+ subif_types = type_subif.split()
+
+ flags = 0
+ if u"no_tags" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_NO_TAGS
+ if u"one_tag" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_ONE_TAG
+ if u"two_tags" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_TWO_TAGS
+ if u"dot1ad" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_DOT1AD
+ if u"exact_match" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_EXACT_MATCH
+ if u"default_sub" in subif_types:
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_DEFAULT
+ if type_subif == u"default_sub":
+ flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_INNER_VLAN_ID_ANY\
+ | SubInterfaceFlags.SUB_IF_API_FLAG_OUTER_VLAN_ID_ANY
+
+ cmd = u"create_subif"
+ args = dict(
+ sw_if_index=InterfaceUtil.get_interface_index(node, interface),
+ sub_id=int(sub_id),
+ sub_if_flags=flags.value if hasattr(flags, u"value")
+ else int(flags),
+ 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 = f"Failed to create sub-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)
+
+ if_key = Topology.add_new_port(node, u"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 f"{interface}.{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 = u"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 = f"Failed to create GRE tunnel interface " \
+ f"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)
+
+ if_key = Topology.add_new_port(node, u"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 create_gtpu_tunnel_interface(node, teid, source_ip, destination_ip):
+ """Create GTPU interface and return sw if index of created interface.
+
+ :param node: Node where to create GTPU interface.
+ :param teid: GTPU Tunnel Endpoint Identifier.
+ :param source_ip: Source IP of a GTPU Tunnel End Point.
+ :param destination_ip: Destination IP of a GTPU Tunnel End Point.
+ :type node: dict
+ :type teid: int
+ :type source_ip: str
+ :type destination_ip: str
+ :returns: SW IF INDEX of created interface.
+ :rtype: int
+ :raises RuntimeError: if it is unable to create GTPU interface on the
+ node.
+ """
+ cmd = u"gtpu_add_del_tunnel"
+ args = dict(
+ is_add=True,
+ src_address=IPAddress.create_ip_address_object(
+ ip_address(source_ip)
+ ),
+ dst_address=IPAddress.create_ip_address_object(
+ ip_address(destination_ip)
+ ),
+ mcast_sw_if_index=Constants.BITWISE_NON_ZERO,
+ encap_vrf_id=0,
+ decap_next_index=2,
+ teid=teid
+ )
+ err_msg = f"Failed to create GTPU tunnel interface " \
+ f"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)
+
+ if_key = Topology.add_new_port(node, u"gtpu_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 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 = u"create_loopback_instance"
+ args = dict(
+ mac_address=L2Util.mac_to_bin(mac) if mac else 0,
+ is_specified=False,
+ user_instance=0,
+ )
+ err_msg = f"Failed to create loopback 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)
+
+ if_key = Topology.add_new_port(node, u"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, gso=False):
+ """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). Default: None.
+ :param mac: MAC address to assign to the bond interface (optional).
+ Default: None.
+ :param gso: Enable GSO support (optional). Default: False.
+ :type node: dict
+ :type mode: str
+ :type load_balance: str
+ :type mac: str
+ :type gso: bool
+ :returns: Interface key (name) in topology.
+ :rtype: str
+ :raises RuntimeError: If it is not possible to create bond interface on
+ the node.
+ """
+ cmd = u"bond_create2"
+ args = dict(
+ id=int(Constants.BITWISE_NON_ZERO),
+ use_custom_mac=bool(mac is not None),
+ mac_address=L2Util.mac_to_bin(mac) if mac else None,
+ mode=getattr(
+ LinkBondMode,
+ f"BOND_API_MODE_{mode.replace(u'-', u'_').upper()}"
+ ).value,
+ lb=0 if load_balance is None else getattr(
+ LinkBondLoadBalanceAlgo,
+ f"BOND_API_LB_ALGO_{load_balance.upper()}"
+ ).value,
+ numa_only=False,
+ enable_gso=gso
+ )
+ err_msg = f"Failed to create bond 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.add_eth_interface(
+ node, sw_if_index=sw_if_index, ifc_pfx=u"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,
+ host_if_key=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.
+ :param host_if_key: Host interface key from topology file.
+ :type node: dict
+ :type ifc_name: str
+ :type sw_if_index: int
+ :type ifc_pfx: str
+ :type host_if_key: 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)
+ if host_if_key is not None:
+ Topology.set_interface_numa_node(
+ node, if_key, Topology.get_interface_numa_node(
+ node, host_if_key
+ )
+ )
+ Topology.update_interface_pci_address(
+ node, if_key, Topology.get_interface_pci_addr(node, host_if_key)
+ )
+
+ @staticmethod
+ def vpp_create_avf_interface(
+ node, if_key, num_rx_queues=None, rxq_size=0, txq_size=0):
+ """Create AVF interface on VPP node.
+
+ :param node: DUT node from topology.
+ :param if_key: Interface key from topology file of interface
+ to be bound to i40evf 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).
+ :type node: dict
+ :type if_key: str
+ :type num_rx_queues: int
+ :type rxq_size: int
+ :type txq_size: int
+ :returns: AVF interface key (name) in topology.
+ :rtype: str
+ :raises RuntimeError: If it is not possible to create AVF interface on
+ the node.
+ """
+ PapiSocketExecutor.run_cli_cmd(
+ node, u"set logging class avf level debug"
+ )
+
+ cmd = u"avf_create"
+ vf_pci_addr = Topology.get_interface_pci_addr(node, if_key)
+ 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=rxq_size,
+ txq_size=txq_size
+ )
+ err_msg = f"Failed to create AVF interface on host {node[u'host']}"
+
+ # FIXME: Remove once the fw/driver is upgraded.
+ for _ in range(10):
+ with PapiSocketExecutor(node) as papi_exec:
+ try:
+ sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(
+ err_msg
+ )
+ break
+ except AssertionError:
+ logger.error(err_msg)
+ else:
+ 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_v3"
+ 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,
+ # TODO: Apply desired RSS flags.
+ )
+ 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)
+
+ @staticmethod
+ def vpp_enable_input_acl_interface(
+ node, interface, ip_version, table_index):
+ """Enable input acl on interface.
+
+ :param node: VPP node to setup interface for input acl.
+ :param interface: Interface to setup input acl.
+ :param ip_version: Version of IP protocol.
+ :param table_index: Classify table index.
+ :type node: dict
+ :type interface: str or int
+ :type ip_version: str
+ :type table_index: int
+ """
+ cmd = u"input_acl_set_interface"
+ args = dict(
+ sw_if_index=InterfaceUtil.get_interface_index(node, interface),
+ ip4_table_index=table_index if ip_version == u"ip4"
+ else Constants.BITWISE_NON_ZERO,
+ ip6_table_index=table_index if ip_version == u"ip6"
+ else Constants.BITWISE_NON_ZERO,
+ l2_table_index=table_index if ip_version == u"l2"
+ else Constants.BITWISE_NON_ZERO,
+ is_add=1)
+ err_msg = f"Failed to enable input acl on interface {interface}"
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def get_interface_classify_table(node, interface):
+ """Get name of classify table for the given interface.
+
+ TODO: Move to Classify.py.
+
+ :param node: VPP node to get data from.
+ :param interface: Name or sw_if_index of a specific interface.
+ :type node: dict
+ :type interface: str or int
+ :returns: Classify table name.
+ :rtype: str
+ """
+ if isinstance(interface, str):
+ sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)