X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=7fc7f857233820092131f5cdc3fd77adaaf2812a;hb=9db603df1076b5ee56ef6326fd0e396b166ed5b1;hp=c5223d5496037358445ba490f977287a27bae492;hpb=cdf557ef070d004617ede4fc5a47dd6064d1c946;p=csit.git diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index c5223d5496..7fc7f85723 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -24,8 +24,9 @@ from resources.libraries.python.ssh import exec_cmd_no_error from resources.libraries.python.topology import NodeType, Topology from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal from resources.libraries.python.VatJsonUtil import VatJsonUtil +from resources.libraries.python.VPPUtil import VPPUtil from resources.libraries.python.parsers.JsonParser import JsonParser - +from resources.libraries.python.CpuUtils import CpuUtils class InterfaceUtil(object): """General utilities for managing interfaces""" @@ -68,9 +69,9 @@ class InterfaceUtil(object): if node['type'] == NodeType.DUT: if state == 'up': - state = 'admin-up' + state = 'admin-up link-up' elif state == 'down': - state = 'admin-down' + state = 'admin-down link-down' else: raise ValueError('Unexpected interface state: {}'.format(state)) VatExecutor.cmd_from_template(node, 'set_if_state.vat', @@ -170,7 +171,7 @@ class InterfaceUtil(object): InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu) @staticmethod - def vpp_node_interfaces_ready_wait(node, timeout=10): + def vpp_node_interfaces_ready_wait(node, timeout=30): """Wait until all interfaces with admin-up are in link-up state. :param node: Node to wait on. @@ -205,7 +206,7 @@ class InterfaceUtil(object): sleep(1) @staticmethod - def vpp_nodes_interfaces_ready_wait(nodes, timeout=10): + def vpp_nodes_interfaces_ready_wait(nodes, timeout=30): """Wait until all interfaces with admin-up are in link-up state for listed nodes. @@ -219,7 +220,7 @@ class InterfaceUtil(object): InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout) @staticmethod - def all_vpp_interfaces_ready_wait(nodes, timeout=10): + def all_vpp_interfaces_ready_wait(nodes, timeout=30): """Wait until all interfaces with admin-up are in link-up state for all nodes in the topology. @@ -581,7 +582,10 @@ class InterfaceUtil(object): try: numa_node = int(out) if numa_node < 0: - raise ValueError + if CpuUtils.cpu_node_count(node) == 1: + numa_node = 0 + else: + raise ValueError except ValueError: logger.trace('Reading numa location failed for: {0}'\ .format(if_pci)) @@ -783,11 +787,10 @@ class InterfaceUtil(object): "tap_dump.vat") if name is None: return response[0] - else: - for item in response[0]: - if name == item['dev_name']: - return item - return {} + for item in response[0]: + if name == item['dev_name']: + return item + return {} @staticmethod def create_subinterface(node, interface, sub_id, outer_vlan_id=None, @@ -933,33 +936,36 @@ class InterfaceUtil(object): the node. """ hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac) - lb = '' if load_balance is None \ - else 'lb {lb}'.format(lb=load_balance) + ldb = '' if load_balance is None \ + else 'lb {ldb}'.format(ldb=load_balance) output = VatExecutor.cmd_from_template( - node, 'create_bond_interface.vat', mode=mode, lb=lb, mac=hw_addr) + node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr) if output[0].get('retval') == 0: sw_if_idx = output[0].get('sw_if_index') - InterfaceUtil.add_bond_eth_interface(node, sw_if_idx=sw_if_idx) + InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx, + ifc_pfx='eth_bond') if_key = Topology.get_interface_by_sw_index(node, sw_if_idx) return if_key else: - raise RuntimeError('Create bond interface failed on node "{n}"' - .format(n=node['host'])) + raise RuntimeError('Create bond interface failed on "{host}"'. + format(host=node['host'])) @staticmethod - def add_bond_eth_interface(node, ifc_name=None, sw_if_idx=None): - """Add BondEthernet interface to current topology. + def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None): + """Add ethernet interface to current topology. :param node: DUT node from topology. - :param ifc_name: Name of the BondEthernet interface. + :param ifc_name: Name of the interface. :param sw_if_idx: SW interface index. + :param ifc_pfx: Interface key prefix. :type node: dict :type ifc_name: str :type sw_if_idx: int + :type ifc_pfx: str """ - if_key = Topology.add_new_port(node, 'eth_bond') + if_key = Topology.add_new_port(node, ifc_pfx) vat_executor = VatExecutor() vat_executor.execute_script_json_out("dump_interfaces.vat", node) @@ -976,6 +982,34 @@ class InterfaceUtil(object): interface_dump_json, sw_if_idx) Topology.update_interface_mac_address(node, if_key, ifc_mac) + @staticmethod + def vpp_create_avf_interface(node, vf_pci_addr): + """Create AVF interface on VPP node. + + :param node: DUT node from topology. + :param vf_pci_addr: Virtual Function PCI address. + :type node: dict + :type vf_pci_addr: str + :returns: Interface key (name) in topology. + :rtype: str + :raises RuntimeError: If it is not possible to create AVF interface on + the node. + """ + with VatTerminal(node, json_param=False) as vat: + vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat', + vf_pci_addr=vf_pci_addr) + output = vat.vat_stdout + + if output is not None: + sw_if_idx = int(output.split()[4]) + InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx, + ifc_pfx='eth_avf') + if_key = Topology.get_interface_by_sw_index(node, sw_if_idx) + return if_key + else: + raise RuntimeError('Create AVF interface failed on {host}'. + format(host=node['host'])) + @staticmethod def vpp_enslave_physical_interface(node, interface, bond_interface): """Enslave physical interface to bond interface on VPP node. @@ -1210,21 +1244,141 @@ class InterfaceUtil(object): .format(node)) @staticmethod - def set_linux_interface_mac(node, interface, mac, namespace=None): + def set_linux_interface_mac(node, interface, mac, namespace=None, + vf_id=None): """Set MAC address for interface in linux. :param node: Node where to execute command. :param interface: Interface in namespace. :param mac: MAC to be assigned to interface. :param namespace: Execute command in namespace. Optional + :param vf_id: Virtual Function id. Optional :type node: dict :type interface: str :type mac: str :type namespace: str + :type vf_id: int """ - if namespace is not None: - cmd = 'ip netns exec {} ip link set {} address {}'.format( - namespace, interface, mac) - else: - cmd = 'ip link set {} address {}'.format(interface, mac) + mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \ + if vf_id is not None else 'address {mac}'.format(mac=mac) + ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else '' + + cmd = ('{ns} ip link set {interface} {mac}'. + format(ns=ns_str, interface=interface, mac=mac_str)) + exec_cmd_no_error(node, cmd, sudo=True) + + @staticmethod + def set_linux_interface_trust_on(node, interface, namespace=None, + vf_id=None): + """Set trust on (promisc) for interface in linux. + + :param node: Node where to execute command. + :param interface: Interface in namespace. + :param namespace: Execute command in namespace. Optional + :param vf_id: Virtual Function id. Optional + :type node: dict + :type interface: str + :type namespace: str + :type vf_id: int + """ + trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \ + if vf_id is not None else 'trust on' + ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else '' + + cmd = ('{ns} ip link set dev {interface} {trust}'. + format(ns=ns_str, interface=interface, trust=trust_str)) + exec_cmd_no_error(node, cmd, sudo=True) + + @staticmethod + def set_linux_interface_spoof_off(node, interface, namespace=None, + vf_id=None): + """Set spoof off for interface in linux. + + :param node: Node where to execute command. + :param interface: Interface in namespace. + :param namespace: Execute command in namespace. Optional + :param vf_id: Virtual Function id. Optional + :type node: dict + :type interface: str + :type namespace: str + :type vf_id: int + """ + spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \ + if vf_id is not None else 'spoof off' + ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else '' + + cmd = ('{ns} ip link set dev {interface} {spoof}'. + format(ns=ns_str, interface=interface, spoof=spoof_str)) exec_cmd_no_error(node, cmd, sudo=True) + + @staticmethod + def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'): + """Init PCI device by creating VFs and bind them to vfio-pci for AVF + driver testing on DUT. + + :param node: DUT node. + :param iface_key: Interface key from topology file. + :param numvfs: Number of VFs to initialize, 0 - disable the VFs. + :param topology_type: Topology type. + :type node: dict + :iface_key: str + :type numvfs: int + :typ topology_type: str + :returns: Virtual Function topology interface keys. + :rtype: list + """ + ssh = SSH() + ssh.connect(node) + + # Read PCI address and driver. + pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key) + pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":") + uio_driver = Topology.get_uio_driver(node) + kernel_driver = Topology.get_interface_driver(node, ifc_key) + current_driver = DUTSetup.get_pci_dev_driver(node,\ + pf_pci_addr.replace(':', r'\:')) + + VPPUtil.stop_vpp_service(node) + if current_driver != kernel_driver: + # PCI device must be re-bound to kernel driver before creating VFs. + DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True) + # Stop VPP to prevent deadlock. + # Unbind from current driver. + DUTSetup.pci_driver_unbind(node, pf_pci_addr) + # Bind to kernel driver. + DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver) + + # Initialize PCI VFs + DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs) + + vf_ifc_keys = [] + # Set MAC address and bind each virtual function to uio driver. + for vf_id in range(numvfs): + vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2], + pf_mac_addr[3], pf_mac_addr[4], + pf_mac_addr[5], "{:02x}".format(vf_id)]) + + pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\ + format(pci=pf_pci_addr) + InterfaceUtil.set_linux_interface_trust_on(node, pf_dev, + vf_id=vf_id) + if topology_type == 'L2': + InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev, + vf_id=vf_id) + InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr, + vf_id=vf_id) + + DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id) + DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver) + + # Add newly created ports into topology file + vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key) + vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id) + vf_ifc_key = Topology.add_new_port(node, vf_ifc_name) + Topology.update_interface_name(node, vf_ifc_key, + vf_ifc_name+str(vf_id+1)) + Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr) + Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr) + vf_ifc_keys.append(vf_ifc_key) + + return vf_ifc_keys