X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=503715c6dd7309e50516534859cbaf6d8a037607;hp=9537b2ba1de545d81f72a19e576c478bd59491f3;hb=7bfb36dfd9284bbca10881e31e14108c7d468b7c;hpb=f45cd0ceb17f33376a04edf9b4fb5a37d9ebfb89 diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 9537b2ba1d..503715c6dd 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -45,7 +45,10 @@ class InterfaceUtil(object): :type interface: str or int :type state: str :type if_type: str - :return: nothing + :returns: Nothing. + :raises ValueError: If the interface type is unknown. + :raises ValueError: If the state of interface is unexpected. + :raises ValueError: If the node has an unknown node type. """ if if_type == "key": @@ -75,8 +78,8 @@ class InterfaceUtil(object): cmd = 'ip link set {} {}'.format(iface_name, state) exec_cmd_no_error(node, cmd, sudo=True) else: - raise Exception('Node {} has unknown NodeType: "{}"'. - format(node['host'], node['type'])) + raise ValueError('Node {} has unknown NodeType: "{}"' + .format(node['host'], node['type'])) @staticmethod def set_interface_ethernet_mtu(node, iface_key, mtu): @@ -85,23 +88,25 @@ class InterfaceUtil(object): Function can be used only for TGs. :param node: Node where the interface is. - :param interface: Interface key from topology file. + :param iface_key: Interface key from topology file. :param mtu: MTU to set. :type node: dict :type iface_key: str :type mtu: int - :return: nothing + :returns: Nothing. + :raises ValueError: If the node type is "DUT". + :raises ValueError: If the node has an unknown node type. """ if node['type'] == NodeType.DUT: - ValueError('Node {}: Setting Ethernet MTU for interface ' - 'on DUT nodes not supported', node['host']) + raise ValueError('Node {}: Setting Ethernet MTU for interface ' + 'on DUT nodes not supported', node['host']) elif node['type'] == NodeType.TG: iface_name = Topology.get_interface_name(node, iface_key) cmd = 'ip link set {} mtu {}'.format(iface_name, mtu) exec_cmd_no_error(node, cmd, sudo=True) else: - raise ValueError('Node {} has unknown NodeType: "{}"'. - format(node['host'], node['type'])) + raise ValueError('Node {} has unknown NodeType: "{}"' + .format(node['host'], node['type'])) @staticmethod def set_default_ethernet_mtu_on_all_interfaces_on_node(node): @@ -111,7 +116,7 @@ class InterfaceUtil(object): :param node: Node where to set default MTU. :type node: dict - :return: nothing + :returns: Nothing. """ for ifc in node['interfaces']: InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500) @@ -124,6 +129,7 @@ class InterfaceUtil(object): :param timeout: Waiting timeout in seconds (optional, default 10s). :type node: dict :type timeout: int + :returns: Nothing. :raises: RuntimeError if the timeout period value has elapsed. """ if_ready = False @@ -159,7 +165,7 @@ class InterfaceUtil(object): :param timeout: Seconds to wait per node for all interfaces to come up. :type nodes: list :type timeout: int - :raises: RuntimeError if the timeout period value has elapsed. + :returns: Nothing. """ for node in nodes: InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout) @@ -173,7 +179,7 @@ class InterfaceUtil(object): :param timeout: Seconds to wait per node for all interfaces to come up. :type nodes: dict :type timeout: int - :raises: RuntimeError if the timeout period value has elapsed. + :returns: Nothing. """ for node in nodes.values(): if node['type'] == NodeType.DUT: @@ -189,9 +195,11 @@ class InterfaceUtil(object): :param interface: Numeric index or name string of a specific interface. :type node: dict :type interface: int or str - :return: List of dictionaries containing data for each interface, or a + :returns: List of dictionaries containing data for each interface, or a single dictionary for the specified interface. :rtype: list or dict + :raises TypeError: if the data type of interface is neither basestring + nor int. """ with VatTerminal(node) as vat: response = vat.vat_terminal_exec_cmd_from_template( @@ -212,6 +220,54 @@ class InterfaceUtil(object): return dict() return data + @staticmethod + def vpp_get_interface_name(node, sw_if_index): + """Get interface name for the given SW interface index from actual + interface dump. + + :param node: VPP node to get interface data from. + :param sw_if_index: SW interface index of the specific interface. + :type node: dict + :type sw_if_index: int + :returns: Name of the given interface. + :rtype: str + """ + + if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index) + if if_data['sup_sw_if_index'] != if_data['sw_if_index']: + if_data = InterfaceUtil.vpp_get_interface_data( + node, if_data['sup_sw_if_index']) + try: + if_name = if_data["interface_name"] + except KeyError: + if_name = None + return if_name + + @staticmethod + def vpp_get_interface_mac(node, interface=None): + """Get MAC address for the given interface from actual interface dump. + + :param node: VPP node to get interface data from. + :param interface: Numeric index or name string of a specific interface. + :type node: dict + :type interface: int or str + :returns: MAC address. + :rtype: str + """ + + if_data = InterfaceUtil.vpp_get_interface_data(node, interface) + if if_data['sup_sw_if_index'] != if_data['sw_if_index']: + if_data = InterfaceUtil.vpp_get_interface_data( + node, if_data['sup_sw_if_index']) + mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]] + mac_data_nice = [] + for item in mac_data: + if len(item) == 1: + item = '0' + item + mac_data_nice.append(item) + mac = ":".join(mac_data_nice) + return mac + @staticmethod def vpp_get_interface_ip_addresses(node, interface, ip_version): """Get list of IP addresses from an interface on a VPP node. @@ -222,12 +278,20 @@ class InterfaceUtil(object): :type node: dict :type interface: str :type ip_version: str - :return: List of dictionaries, each containing IP address, subnet + :returns: List of dictionaries, each containing IP address, subnet prefix length and also the subnet mask for ipv4 addresses. Note: A single interface may have multiple IP addresses assigned. :rtype: list """ - sw_if_index = InterfaceUtil.get_sw_if_index(node, interface) + + try: + sw_if_index = Topology.convert_interface_reference( + node, interface, "sw_if_index") + except RuntimeError: + if isinstance(interface, basestring): + sw_if_index = InterfaceUtil.get_sw_if_index(node, interface) + else: + raise with VatTerminal(node) as vat: response = vat.vat_terminal_exec_cmd_from_template( @@ -252,6 +316,9 @@ class InterfaceUtil(object): :type node: dict :type pci_addr: str :type driver: str + :returns: None. + :raises RuntimeError: If unbinding from the current driver fails. + :raises RuntimeError: If binding to the new driver fails. """ old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr) if old_driver == driver: @@ -262,19 +329,20 @@ class InterfaceUtil(object): # Unbind from current driver if old_driver is not None: - cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format( - pci_addr, old_driver) + cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\ + .format(pci_addr, old_driver) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, - node['host'])) + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) # Bind to the new driver - cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format( - pci_addr, driver) + cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\ + .format(pci_addr, driver) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) @staticmethod def tg_get_interface_driver(node, pci_addr): @@ -284,8 +352,10 @@ class InterfaceUtil(object): :param pci_addr: PCI address of the interface. :type node: dict :type pci_addr: str - :return: Interface driver or None if not found. + :returns: Interface driver or None if not found. :rtype: str + :raises RuntimeError: If it is not possible to get the interface driver + information from the node. .. note:: # lspci -vmmks 0000:00:05.0 @@ -301,20 +371,35 @@ class InterfaceUtil(object): ssh = SSH() ssh.connect(node) - cmd = 'lspci -vmmks {0}'.format(pci_addr) - - (ret_code, stdout, _) = ssh.exec_command(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) - - for line in stdout.splitlines(): - if len(line) == 0: - continue - (name, value) = line.split("\t", 1) - if name == 'Driver:': - return value + for i in range(3): + logger.trace('Try {}: Get interface driver'.format(i)) + cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"' + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) - return None + cmd = 'lspci -vmmks {0}'.format(pci_addr) + (ret_code, stdout, _) = ssh.exec_command(cmd) + if int(ret_code) != 0: + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) + + for line in stdout.splitlines(): + if len(line) == 0: + continue + try: + (name, value) = line.split("\t", 1) + except ValueError: + if name != "Driver:": + pass + else: + return None + if name == 'Driver:': + return value if value else None + else: + raise RuntimeError('Get interface driver for: {0}' + .format(pci_addr)) @staticmethod def tg_set_interfaces_udev_rules(node): @@ -331,6 +416,7 @@ class InterfaceUtil(object): :param node: Node to set udev rules on (must be TG node). :type node: dict + :raises RuntimeError: If setting of udev rules fails. """ ssh = SSH() ssh.connect(node) @@ -338,7 +424,8 @@ class InterfaceUtil(object): cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) for interface in node['interfaces'].values(): rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \ @@ -348,8 +435,8 @@ class InterfaceUtil(object): rule, InterfaceUtil.__UDEV_IF_RULES_FILE) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, - node['host'])) + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) cmd = '/etc/init.d/udev restart' ssh.exec_command_sudo(cmd) @@ -385,12 +472,54 @@ class InterfaceUtil(object): VatJsonUtil.update_vpp_interface_data_from_json(node, interface_dump_json) + @staticmethod + def update_nic_interface_names(node): + """Update interface names based on nic type and PCI address. + + This method updates interface names in the same format as VPP does. + + :param node: Node dictionary. + :type node: dict + """ + for ifc in node['interfaces'].values(): + if_pci = ifc['pci_address'].replace('.', ':').split(':') + bus = '{:x}'.format(int(if_pci[1], 16)) + dev = '{:x}'.format(int(if_pci[2], 16)) + fun = '{:x}'.format(int(if_pci[3], 16)) + loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun) + if ifc['model'] == 'Intel-XL710': + ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc) + elif ifc['model'] == 'Intel-X710': + ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc) + elif ifc['model'] == 'Intel-X520-DA2': + ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc) + elif ifc['model'] == 'Cisco-VIC-1385': + ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc) + elif ifc['model'] == 'Cisco-VIC-1227': + ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc) + else: + ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc) + + @staticmethod + def update_nic_interface_names_on_all_duts(nodes): + """Update interface names based on nic type and PCI address on all DUTs. + + This method updates interface names in the same format as VPP does. + + :param nodes: Topology nodes. + :type nodes: dict + """ + for node in nodes.values(): + if node['type'] == NodeType.DUT: + InterfaceUtil.update_nic_interface_names(node) + @staticmethod def update_tg_interface_data_on_node(node): """Update interface name for TG/linux node in DICT__nodes. :param node: Node selected from DICT__nodes. :type node: dict + :raises RuntimeError: If getting of interface name and MAC fails. .. note:: # for dev in `ls /sys/class/net/`; @@ -414,7 +543,7 @@ class InterfaceUtil(object): (ret_code, stdout, _) = ssh.exec_command(cmd) if int(ret_code) != 0: - raise Exception('Get interface name and MAC failed') + raise RuntimeError('Get interface name and MAC failed') tmp = "{" + stdout.rstrip().replace('\n', ',') + "}" interfaces = JsonParser().parse_data(tmp) for interface in node['interfaces'].values(): @@ -427,7 +556,59 @@ class InterfaceUtil(object): InterfaceUtil.tg_set_interfaces_udev_rules(node) @staticmethod - def update_all_interface_data_on_all_nodes(nodes, skip_tg=False): + def iface_update_numa_node(node): + """For all interfaces from topology file update numa node based on + information from the node. + + :param node: Node from topology. + :type node: dict + :returns: Nothing. + :raises ValueError: If numa node ia less than 0. + :raises RuntimeError: If update of numa node failes. + """ + ssh = SSH() + for if_key in Topology.get_node_interfaces(node): + if_pci = Topology.get_interface_pci_addr(node, if_key) + ssh.connect(node) + cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci) + for _ in range(3): + (ret, out, _) = ssh.exec_command(cmd) + if ret == 0: + try: + numa_node = int(out) + if numa_node < 0: + raise ValueError + except ValueError: + logger.trace('Reading numa location failed for: {0}'\ + .format(if_pci)) + else: + Topology.set_interface_numa_node(node, if_key, + numa_node) + break + else: + raise RuntimeError('Update numa node failed for: {0}'\ + .format(if_pci)) + + @staticmethod + def update_all_numa_nodes(nodes, skip_tg=False): + """For all nodes and all their interfaces from topology file update numa + node information based on information from the node. + + :param nodes: Nodes in the topology. + :param skip_tg: Skip TG node + :type nodes: dict + :type skip_tg: bool + :returns: Nothing. + """ + for node in nodes.values(): + if node['type'] == NodeType.DUT: + InterfaceUtil.iface_update_numa_node(node) + elif node['type'] == NodeType.TG and not skip_tg: + InterfaceUtil.iface_update_numa_node(node) + + @staticmethod + def update_all_interface_data_on_all_nodes(nodes, skip_tg=False, + numa_node=False): """Update interface names on all nodes in DICT__nodes. This method updates the topology dictionary by querying interface lists @@ -435,8 +616,10 @@ class InterfaceUtil(object): :param nodes: Nodes in the topology. :param skip_tg: Skip TG node + :param numa_node: Retrieve numa_node location. :type nodes: dict :type skip_tg: bool + :type numa_node: bool """ for node_data in nodes.values(): if node_data['type'] == NodeType.DUT: @@ -444,6 +627,12 @@ class InterfaceUtil(object): elif node_data['type'] == NodeType.TG and not skip_tg: InterfaceUtil.update_tg_interface_data_on_node(node_data) + if numa_node: + if node_data['type'] == NodeType.DUT: + InterfaceUtil.iface_update_numa_node(node_data) + elif node_data['type'] == NodeType.TG and not skip_tg: + InterfaceUtil.iface_update_numa_node(node_data) + @staticmethod def create_vlan_subinterface(node, interface, vlan): """Create VLAN subinterface on node. @@ -454,8 +643,10 @@ class InterfaceUtil(object): :type node: dict :type interface: str :type vlan: int - :return: Name and index of created subinterface. + :returns: Name and index of created subinterface. :rtype: tuple + :raises RuntimeError: if it is unable to create VLAN subinterface on the + node. """ iface_key = Topology.get_interface_by_name(node, interface) sw_if_index = Topology.get_interface_sw_index(node, iface_key) @@ -464,10 +655,14 @@ class InterfaceUtil(object): sw_if_index=sw_if_index, vlan=vlan) if output[0]["retval"] == 0: - sw_subif_index = output[0]["sw_if_index"] + sw_subif_idx = output[0]["sw_if_index"] logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} ' - 'created on node {}'.format(sw_subif_index, + 'created on node {}'.format(sw_subif_idx, vlan, node['host'])) + if_key = Topology.add_new_port(node, "vlan_subif") + Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx) + ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx) + Topology.update_interface_name(node, if_key, ifc_name) else: raise RuntimeError('Unable to create VLAN subinterface on node {}' .format(node['host'])) @@ -475,7 +670,7 @@ class InterfaceUtil(object): with VatTerminal(node, False) as vat: vat.vat_terminal_exec_cmd('exec show interfaces') - return '{}.{}'.format(interface, vlan), sw_subif_index + return '{}.{}'.format(interface, vlan), sw_subif_idx @staticmethod def create_vxlan_interface(node, vni, source_ip, destination_ip): @@ -492,8 +687,10 @@ class InterfaceUtil(object): :type vni: int :type source_ip: str :type destination_ip: str - :return: SW IF INDEX of created interface. + :returns: SW IF INDEX of created interface. :rtype: int + :raises RuntimeError: if it is unable to create VxLAN interface on the + node. """ output = VatExecutor.cmd_from_template(node, "vxlan_create.vat", src=source_ip, @@ -502,9 +699,14 @@ class InterfaceUtil(object): output = output[0] if output["retval"] == 0: - return output["sw_if_index"] + sw_if_idx = output["sw_if_index"] + if_key = Topology.add_new_port(node, "vxlan_tunnel") + Topology.update_interface_sw_if_index(node, if_key, sw_if_idx) + ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx) + Topology.update_interface_name(node, if_key, ifc_name) + return sw_if_idx else: - raise RuntimeError('Unable to create VXLAN interface on node {0}' + raise RuntimeError("Unable to create VXLAN interface on node {0}" .format(node)) @staticmethod @@ -516,9 +718,11 @@ class InterfaceUtil(object): If None, information about all VxLAN interfaces is returned. :type node: dict :type interface: int or str - :return: Dictionary containing data for the given VxLAN interface or if + :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. """ param = "sw_if_index" if interface is None: @@ -529,7 +733,7 @@ class InterfaceUtil(object): elif isinstance(interface, int): sw_if_index = interface else: - raise Exception("Wrong interface format {0}".format(interface)) + raise TypeError("Wrong interface format {0}".format(interface)) with VatTerminal(node) as vat: response = vat.vat_terminal_exec_cmd_from_template( @@ -548,7 +752,7 @@ class InterfaceUtil(object): :param node: VPP node to get interface data from. :type node: dict - :return: List of dictionaries with all vhost-user interfaces. + :returns: List of dictionaries with all vhost-user interfaces. :rtype: list """ with VatTerminal(node) as vat: @@ -566,7 +770,7 @@ class InterfaceUtil(object): :param name: Optional name of a specific TAP interface. :type node: dict :type name: str - :return: Dictionary of information about a specific TAP interface, or + :returns: Dictionary of information about a specific TAP interface, or a List of dictionaries containing all TAP data for the given node. :rtype: dict or list """ @@ -600,7 +804,7 @@ class InterfaceUtil(object): :type outer_vlan_id: int :type inner_vlan_id: int :type type_subif: str - :return: Name and index of created sub-interface. + :returns: Name and index of created sub-interface. :rtype: tuple :raises RuntimeError: If it is not possible to create sub-interface. """ @@ -628,9 +832,13 @@ class InterfaceUtil(object): type_subif=type_subif) if output[0]["retval"] == 0: - sw_subif_index = output[0]["sw_if_index"] + sw_subif_idx = output[0]["sw_if_index"] logger.trace('Created subinterface with index {}' - .format(sw_subif_index)) + .format(sw_subif_idx)) + if_key = Topology.add_new_port(node, "subinterface") + Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx) + ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx) + Topology.update_interface_name(node, if_key, ifc_name) else: raise RuntimeError('Unable to create sub-interface on node {}' .format(node['host'])) @@ -639,7 +847,7 @@ class InterfaceUtil(object): vat.vat_terminal_exec_cmd('exec show interfaces') name = '{}.{}'.format(interface, sub_id) - return name, sw_subif_index + return name, sw_subif_idx @staticmethod def create_gre_tunnel_interface(node, source_ip, destination_ip): @@ -651,7 +859,7 @@ class InterfaceUtil(object): :type node: dict :type source_ip: str :type destination_ip: str - :return: Name and index of created GRE tunnel interface. + :returns: Name and index of created GRE tunnel interface. :rtype: tuple :raises RuntimeError: If unable to create GRE tunnel interface. """ @@ -661,14 +869,19 @@ class InterfaceUtil(object): output = output[0] if output["retval"] == 0: - sw_if_index = output["sw_if_index"] + sw_if_idx = output["sw_if_index"] vat_executor = VatExecutor() vat_executor.execute_script_json_out("dump_interfaces.vat", node) interface_dump_json = vat_executor.get_script_stdout() name = VatJsonUtil.get_interface_name_from_json( - interface_dump_json, sw_if_index) - return name, sw_if_index + interface_dump_json, sw_if_idx) + + if_key = Topology.add_new_port(node, "gre_tunnel") + Topology.update_interface_sw_if_index(node, if_key, sw_if_idx) + Topology.update_interface_name(node, if_key, name) + + return name, sw_if_idx else: raise RuntimeError('Unable to create GRE tunnel on node {}.' .format(node)) @@ -679,12 +892,19 @@ class InterfaceUtil(object): :param node: Node to create loopback interface on. :type node: dict - :return: SW interface index. + :returns: SW interface index. :rtype: int + :raises RuntimeError: If it is not possible to create loopback on the + node. """ out = VatExecutor.cmd_from_template(node, "create_loopback.vat") if out[0].get('retval') == 0: - return out[0].get('sw_if_index') + sw_if_idx = out[0].get('sw_if_index') + if_key = Topology.add_new_port(node, "loopback") + Topology.update_interface_sw_if_index(node, if_key, sw_if_idx) + ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx) + Topology.update_interface_name(node, if_key, ifc_name) + return sw_if_idx else: raise RuntimeError('Create loopback failed on node "{}"' .format(node['host'])) @@ -722,7 +942,7 @@ class InterfaceUtil(object): :param interface: Name or sw_if_index of a specific interface. :type node: dict :type interface: str or int - :return: Classify table name. + :returns: Classify table name. :rtype: str """ if isinstance(interface, basestring): @@ -733,10 +953,32 @@ class InterfaceUtil(object): with VatTerminal(node) as vat: data = vat.vat_terminal_exec_cmd_from_template( "classify_interface_table.vat", - sw_if_index=sw_if_index - ) + sw_if_index=sw_if_index) return data[0] + @staticmethod + def get_interface_vrf_table(node, interface): + """Get vrf ID for the given interface. + + :param node: VPP node. + :param interface: Name or sw_if_index of a specific interface. + :type node: dict + :type interface: str or int + :returns: vrf ID of the specified interface. + :rtype: int + """ + + if isinstance(interface, basestring): + sw_if_index = InterfaceUtil.get_sw_if_index(node, interface) + else: + sw_if_index = interface + + with VatTerminal(node) as vat: + data = vat.vat_terminal_exec_cmd_from_template( + "interface_vrf_dump.vat", + sw_if_index=sw_if_index) + return data[0]["vrf_id"] + @staticmethod def get_sw_if_index(node, interface_name): """Get sw_if_index for the given interface from actual interface dump. @@ -745,7 +987,7 @@ class InterfaceUtil(object): :param interface_name: Name of the specific interface. :type node: dict :type interface_name: str - :return: sw_if_index of the given interface. + :returns: sw_if_index of the given interface. :rtype: str """ @@ -767,8 +1009,8 @@ class InterfaceUtil(object): information about all VxLAN GPE interfaces is returned. :type node: dict :type interface_name: str - :return: Dictionary containing data for the given VxLAN GPE interface or - if interface=None, the list of dictionaries with all VxLAN GPE + :returns: Dictionary containing data for the given VxLAN GPE interface + or if interface=None, the list of dictionaries with all VxLAN GPE interfaces. :rtype: dict or list """ @@ -820,25 +1062,33 @@ class InterfaceUtil(object): interface_name=interface) @staticmethod - def assign_interface_to_fib_table(node, interface, table_id): + def assign_interface_to_fib_table(node, interface, table_id, ipv6=False): """Assign VPP interface to specific VRF/FIB table. :param node: VPP node where the FIB and interface are located. :param interface: Interface to be assigned to FIB. :param table_id: VRF table ID. + :param ipv6: Assign to IPv6 table. Default False. :type node: dict :type interface: str or int :type table_id: int + :type ipv6: bool """ if isinstance(interface, basestring): sw_if_index = Topology.get_interface_sw_index(node, interface) else: sw_if_index = interface + ipv6 = 'ipv6' if ipv6 else '' + with VatTerminal(node) as vat: - vat.vat_terminal_exec_cmd_from_template("set_fib_to_interface.vat", - sw_index=sw_if_index, - vrf=table_id) + ret = vat.vat_terminal_exec_cmd_from_template( + "set_fib_to_interface.vat", + sw_index=sw_if_index, vrf=table_id, ipv6=ipv6) + + if ret[0]["retval"] != 0: + raise RuntimeError('Unable to assign interface to FIB node {}.' + .format(node)) @staticmethod def set_linux_interface_mac(node, interface, mac, namespace=None):