X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=d185137940f8417eb422a4839d9e7cdb777f99d3;hb=909a91c2a2b08a85d700542a77f8b69434f5ded1;hp=982a345ef2131efb665e50fba29c2f333c1391a3;hpb=e6dd772435e4736170aaa43a779840196e714254;p=csit.git diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 982a345ef2..d185137940 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -30,20 +30,77 @@ from resources.libraries.python.topology import NodeType, Topology from resources.libraries.python.VPPUtil import VPPUtil -class LinkBondLoadBalance(IntEnum): - """Link bonding load balance.""" - L2 = 0 # pylint: disable=invalid-name - L34 = 1 - L23 = 2 +class InterfaceStatusFlags(IntEnum): + """Interface status flags.""" + IF_STATUS_API_FLAG_ADMIN_UP = 1 + IF_STATUS_API_FLAG_LINK_UP = 2 + + +class MtuProto(IntEnum): + """MTU protocol.""" + MTU_PROTO_API_L3 = 0 + MTU_PROTO_API_IP4 = 1 + MTU_PROTO_API_IP6 = 2 + MTU_PROTO_API_MPLS = 3 + MTU_PROTO_API_N = 4 + + +class LinkDuplex(IntEnum): + """Link duplex""" + LINK_DUPLEX_API_UNKNOWN = 0 + LINK_DUPLEX_API_HALF = 1 + LINK_DUPLEX_API_FULL = 2 + + +class SubInterfaceFlags(IntEnum): + """Sub-interface flags.""" + SUB_IF_API_FLAG_NO_TAGS = 1 + SUB_IF_API_FLAG_ONE_TAG = 2 + SUB_IF_API_FLAG_TWO_TAGS = 4 + SUB_IF_API_FLAG_DOT1AD = 8 + SUB_IF_API_FLAG_EXACT_MATCH = 16 + SUB_IF_API_FLAG_DEFAULT = 32 + SUB_IF_API_FLAG_OUTER_VLAN_ID_ANY = 64 + SUB_IF_API_FLAG_INNER_VLAN_ID_ANY = 128 + SUB_IF_API_FLAG_DOT1AH = 256 + + +class RxMode(IntEnum): + """RX mode""" + RX_MODE_API_UNKNOWN = 0 + RX_MODE_API_POLLING = 1 + RX_MODE_API_INTERRUPT = 2 + RX_MODE_API_ADAPTIVE = 3 + RX_MODE_API_DEFAULT = 4 + + +class IfType(IntEnum): + """Interface type""" + # A hw interface + IF_API_TYPE_HARDWARE = 0 + # A sub-interface + IF_API_TYPE_SUB = 1 + IF_API_TYPE_P2P = 2 + IF_API_TYPE_PIPE = 3 + + +class LinkBondLoadBalanceAlgo(IntEnum): + """Link bonding load balance algorithm.""" + BOND_API_LB_ALGO_L2 = 0 + BOND_API_LB_ALGO_L34 = 1 + BOND_API_LB_ALGO_L23 = 2 + BOND_API_LB_ALGO_RR = 3 + BOND_API_LB_ALGO_BC = 4 + BOND_API_LB_ALGO_AB = 5 class LinkBondMode(IntEnum): - """Link bonding load balance.""" - ROUND_ROBIN = 1 - ACTIVE_BACKUP = 2 - XOR = 3 - BROADCAST = 4 - LACP = 5 + """Link bonding mode.""" + BOND_API_MODE_ROUND_ROBIN = 1 + BOND_API_MODE_ACTIVE_BACKUP = 2 + BOND_API_MODE_XOR = 3 + BOND_API_MODE_BROADCAST = 4 + BOND_API_MODE_LACP = 5 class InterfaceUtil(object): @@ -67,6 +124,25 @@ class InterfaceUtil(object): return (int(pci[0], 16) | int(pci[1], 16) << 16 | int(pci[2], 16) << 24 | int(pci[3], 16) << 29) + @staticmethod + def pci_to_eth(node, pci_str): + """Convert PCI address to Linux ethernet name. + + :param pci_str: PCI address. + :type pci_str: str + :returns: Ethernet name. + :rtype: str + """ + cmd = ('basename /sys/bus/pci/devices/{pci_str}/net/*'. + format(pci_str=pci_str)) + try: + stdout, _ = exec_cmd_no_error(node, cmd) + except RuntimeError: + raise RuntimeError("Cannot convert {pci_str} to ethernet name!". + format(pci_str=pci_str)) + + return stdout.strip() + @staticmethod def get_interface_index(node, interface): """Get interface sw_if_index from topology file. @@ -126,17 +202,18 @@ class InterfaceUtil(object): if node['type'] == NodeType.DUT: if state == 'up': - admin_up_down = 1 + flags = InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value elif state == 'down': - admin_up_down = 0 + flags = 0 else: raise ValueError('Unexpected interface state: {state}'.format( state=state)) cmd = 'sw_interface_set_flags' err_msg = 'Failed to set interface state on host {host}'.format( host=node['host']) - args = dict(sw_if_index=sw_if_index, - admin_up_down=admin_up_down) + args = dict( + sw_if_index=int(sw_if_index), + flags=flags) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg) elif node['type'] == NodeType.TG or node['type'] == NodeType.VM: @@ -258,13 +335,12 @@ class InterfaceUtil(object): not_ready = list() out = InterfaceUtil.vpp_get_interface_data(node) for interface in out: - if interface.get('admin_up_down') == 1: - if interface.get('link_up_down') != 1: - not_ready.append(interface.get('interface_name')) + if interface.get('flags') == 1: + not_ready.append(interface.get('interface_name')) if not not_ready: break else: - logger.debug('Interfaces still in link-down state:\n{ifs} ' + logger.debug('Interfaces still not in link-up state:\n{ifs} ' '\nWaiting...'.format(ifs=not_ready)) sleep(1) else: @@ -312,11 +388,16 @@ class InterfaceUtil(object): :returns: Processed interface dump. :rtype: dict """ - if_dump['interface_name'] = if_dump['interface_name'].rstrip('\x00') - if_dump['tag'] = if_dump['tag'].rstrip('\x00') - if_dump['l2_address'] = L2Util.bin_to_mac(if_dump['l2_address']) - if_dump['b_dmac'] = L2Util.bin_to_mac(if_dump['b_dmac']) - if_dump['b_smac'] = L2Util.bin_to_mac(if_dump['b_smac']) + if_dump['l2_address'] = str(if_dump['l2_address']) + if_dump['b_dmac'] = str(if_dump['b_dmac']) + if_dump['b_smac'] = str(if_dump['b_smac']) + if_dump['flags'] = if_dump['flags'].value + if_dump['type'] = if_dump['type'].value + if_dump['link_duplex'] = if_dump['link_duplex'].value + if_dump['sub_if_flags'] = if_dump['sub_if_flags'].value \ + if hasattr(if_dump['sub_if_flags'], 'value') \ + else int(if_dump['sub_if_flags']) + return if_dump if interface is not None: @@ -331,12 +412,15 @@ class InterfaceUtil(object): param = '' cmd = 'sw_interface_dump' - args = dict(name_filter_valid=0, - name_filter='') + args = dict( + name_filter_valid=False, + name_filter='' + ) err_msg = 'Failed to get interface dump on host {host}'.format( host=node['host']) with PapiSocketExecutor(node) as papi_exec: details = papi_exec.add(cmd, **args).get_details(err_msg) + logger.debug('Received data:\n{d!r}'.format(d=details)) data = list() if interface is None else dict() for dump in details: @@ -724,8 +808,10 @@ class InterfaceUtil(object): sw_if_index = InterfaceUtil.get_interface_index(node, interface) cmd = 'create_vlan_subif' - args = dict(sw_if_index=sw_if_index, - vlan_id=int(vlan)) + args = dict( + sw_if_index=sw_if_index, + vlan_id=int(vlan) + ) err_msg = 'Failed to create VLAN sub-interface on host {host}'.format( host=node['host']) with PapiSocketExecutor(node) as papi_exec: @@ -930,20 +1016,31 @@ class InterfaceUtil(object): """ subif_types = type_subif.split() + flags = 0 + if 'no_tags' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_NO_TAGS + if 'one_tag' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_ONE_TAG + if 'two_tags' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_TWO_TAGS + if 'dot1ad' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_DOT1AD + if 'exact_match' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_EXACT_MATCH + if 'default_sub' in subif_types: + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_DEFAULT + if type_subif == 'default_sub': + flags = flags | SubInterfaceFlags.SUB_IF_API_FLAG_INNER_VLAN_ID_ANY\ + | SubInterfaceFlags.SUB_IF_API_FLAG_OUTER_VLAN_ID_ANY + 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, + sub_if_flags=flags.value if hasattr(flags, '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) + 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: @@ -996,7 +1093,7 @@ class InterfaceUtil(object): """Create loopback interface on VPP node. :param node: Node to create loopback interface on. - :param mac: Optional MAC address for Loopback interface. + :param mac: Optional MAC address for loopback interface. :type node: dict :type mac: str :returns: SW interface index. @@ -1040,21 +1137,24 @@ class InterfaceUtil(object): 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) + args = dict( + id=int(Constants.BITWISE_NON_ZERO), + use_custom_mac=False if mac is None else True, + mac_address=L2Util.mac_to_bin(mac) if mac else None, + mode=getattr(LinkBondMode, 'BOND_API_MODE_{md}'.format( + md=mode.replace('-', '_').upper())).value, + lb=0 if load_balance is None else getattr( + LinkBondLoadBalanceAlgo, 'BOND_API_LB_ALGO_{lb}'.format( + lb=load_balance.upper())).value, + numa_only=False + ) 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') + 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 @@ -1089,7 +1189,7 @@ class InterfaceUtil(object): """Create AVF interface on VPP node. :param node: DUT node from topology. - :param vf_pci_addr: Virtual Function PCI address. + :param vf_pci_addr: PCI address binded to i40evf driver. :param num_rx_queues: Number of RX queues. :type node: dict :type vf_pci_addr: str @@ -1110,8 +1210,40 @@ class InterfaceUtil(object): 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') + 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_create_rdma_interface(node, pci_addr, num_rx_queues=None): + """Create RDMA interface on VPP node. + + :param node: DUT node from topology. + :param pci_addr: PCI address binded to rdma-core driver. + :param num_rx_queues: Number of RX queues. + :type node: dict + :type 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 RDMA interface on + the node. + """ + cmd = 'rdma_create' + 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=0, + txq_size=0) + err_msg = 'Failed to create RDMA 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_rdma') if_key = Topology.get_interface_by_sw_index(node, sw_if_index) return if_key @@ -1133,8 +1265,9 @@ class InterfaceUtil(object): 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) + is_passive=False, + is_long_timeout=False + ) err_msg = 'Failed to enslave physical interface {ifc} to bond ' \ 'interface {bond} on host {host}'.format(ifc=interface, bond=bond_if, @@ -1160,9 +1293,11 @@ class InterfaceUtil(object): 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 += ('{b}\n'.format(b=bond['interface_name'])) + data += (' mode: {m}\n'.format( + m=bond['mode'].name.replace('BOND_API_MODE_', '').lower())) + data += (' load balance: {lb}\n'.format( + lb=bond['lb'].name.replace('BOND_API_LB_ALGO_', '').lower())) data += (' number of active slaves: {n}\n'.format( n=bond['active_slaves'])) if verbose: @@ -1191,18 +1326,6 @@ class InterfaceUtil(object): :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)) @@ -1212,10 +1335,6 @@ class InterfaceUtil(object): 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 @@ -1378,7 +1497,7 @@ class InterfaceUtil(object): cmd = 'sw_interface_set_table' args = dict( sw_if_index=InterfaceUtil.get_interface_index(node, interface), - is_ipv6=1 if ipv6 else 0, + is_ipv6=ipv6, vrf_id=int(table_id)) err_msg = 'Failed to assign interface {ifc} to FIB table'.format( ifc=interface) @@ -1567,8 +1686,12 @@ class InterfaceUtil(object): cmd = 'sw_interface_set_rx_placement' err_msg = "Failed to set interface RX placement to worker on host " \ "{host}!".format(host=node['host']) - args = dict(sw_if_index=sw_if_index, queue_id=queue_id, - worker_id=worker_id) + args = dict( + sw_if_index=sw_if_index, + queue_id=queue_id, + worker_id=worker_id, + is_main=False + ) with PapiSocketExecutor(node) as papi_exec: papi_exec.add(cmd, **args).get_reply(err_msg)