X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=e2dc2f1c31e26b38b765e99377c476b7cf12795b;hb=56440df4a2d9404aefe5d47ad9db9128fdb33b69;hp=0f18f8f8077b825ea331dba893ed5f77f5c776ff;hpb=f31b70ee422ed0dc4e5d9b60061a1c2cfc904684;p=csit.git diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 0f18f8f807..e2dc2f1c31 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -20,8 +20,8 @@ from ipaddress import ip_address from robot.api import logger from resources.libraries.python.Constants import Constants -from resources.libraries.python.CpuUtils import CpuUtils from resources.libraries.python.DUTSetup import DUTSetup +from resources.libraries.python.IPAddress import IPAddress from resources.libraries.python.L2Util import L2Util from resources.libraries.python.PapiExecutor import PapiSocketExecutor from resources.libraries.python.parsers.JsonParser import JsonParser @@ -113,8 +113,6 @@ class RdmaMode(IntEnum): class InterfaceUtil: """General utilities for managing interfaces""" - __UDEV_IF_RULES_FILE = u"/etc/udev/rules.d/10-network.rules" - @staticmethod def pci_to_int(pci_str): """Convert PCI address from string format (0000:18:0a.0) to @@ -493,6 +491,27 @@ class InterfaceUtil: return if_data.get(u"l2_address") + @staticmethod + def vpp_set_interface_mac(node, interface, mac): + """Set MAC address for the given interface. + + :param node: VPP node to set interface MAC. + :param interface: Numeric index or name string of a specific interface. + :param mac: Required MAC address. + :type node: dict + :type interface: int or str + :type mac: str + """ + cmd = u"sw_interface_set_mac_address" + args = dict( + sw_if_index=InterfaceUtil.get_interface_index(node, interface), + mac_address=L2Util.mac_to_bin(mac) + ) + err_msg = f"Failed to set MAC address of interface {interface}" \ + f"on host {node[u'host']}" + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) + @staticmethod def tg_set_interface_driver(node, pci_addr, driver): """Set interface driver on the TG node. @@ -541,45 +560,6 @@ class InterfaceUtil: """ return DUTSetup.get_pci_dev_driver(node, pci_addr) - @staticmethod - def tg_set_interfaces_udev_rules(node): - """Set udev rules for interfaces. - - Create udev rules file in /etc/udev/rules.d where are rules for each - interface used by TG node, based on MAC interface has specific name. - So after unbind and bind again to kernel driver interface has same - name as before. This must be called after TG has set name for each - port in topology dictionary. - udev rule example - SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f", - NAME="eth1" - - :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) - - cmd = f"rm -f {InterfaceUtil.__UDEV_IF_RULES_FILE}" - ret_code, _, _ = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'") - - for interface in node[u"interfaces"].values(): - rule = u'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \ - u'==\\"' + interface[u"mac_address"] + u'\\", NAME=\\"' + \ - interface[u"name"] + u'\\"' - cmd = f"sh -c \"echo '{rule}'\" >> " \ - f"{InterfaceUtil.__UDEV_IF_RULES_FILE}'" - - ret_code, _, _ = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise RuntimeError(f"'{cmd}' failed on '{node[u'host']}'") - - cmd = u"/etc/init.d/udev restart" - ssh.exec_command_sudo(cmd) - @staticmethod def tg_set_interfaces_default_driver(node): """Set interfaces default driver specified in topology yaml file. @@ -667,7 +647,7 @@ class InterfaceUtil: InterfaceUtil.update_nic_interface_names(node) @staticmethod - def update_tg_interface_data_on_node(node, skip_tg_udev=False): + def update_tg_interface_data_on_node(node): """Update interface name for TG/linux node in DICT__nodes. .. note:: @@ -679,9 +659,7 @@ class InterfaceUtil: "00:00:00:00:00:00": "lo" :param node: Node selected from DICT__nodes. - :param skip_tg_udev: Skip udev rename on TG node. :type node: dict - :type skip_tg_udev: bool :raises RuntimeError: If getting of interface name and MAC fails. """ # First setup interface driver specified in yaml file @@ -706,10 +684,6 @@ class InterfaceUtil: continue interface[u"name"] = name - # Set udev rules for interfaces - if not skip_tg_udev: - InterfaceUtil.tg_set_interfaces_udev_rules(node) - @staticmethod def iface_update_numa_node(node): """For all interfaces from topology file update numa node based on @@ -721,14 +695,6 @@ class InterfaceUtil: :raises ValueError: If numa node ia less than 0. :raises RuntimeError: If update of numa node failed. """ - def check_cpu_node_count(node_n, val): - val = int(val) - if val < 0: - if CpuUtils.cpu_node_count(node_n) == 1: - val = 0 - else: - raise ValueError - return val ssh = SSH() for if_key in Topology.get_node_interfaces(node): if_pci = Topology.get_interface_pci_addr(node, if_key) @@ -738,7 +704,7 @@ class InterfaceUtil: ret, out, _ = ssh.exec_command(cmd) if ret == 0: try: - numa_node = check_cpu_node_count(node, out) + numa_node = 0 if int(out) < 0 else int(out) except ValueError: logger.trace( f"Reading numa location failed for: {if_pci}" @@ -751,26 +717,9 @@ class InterfaceUtil: else: raise RuntimeError(f"Update numa node failed for: {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[u"type"] == NodeType.DUT: - InterfaceUtil.iface_update_numa_node(node) - elif node[u"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, skip_tg_udev=False, numa_node=False): + nodes, skip_tg=False, skip_vpp=False): """Update interface names on all nodes in DICT__nodes. This method updates the topology dictionary by querying interface lists @@ -778,25 +727,17 @@ class InterfaceUtil: :param nodes: Nodes in the topology. :param skip_tg: Skip TG node. - :param skip_tg_udev: Skip udev rename on TG node. - :param numa_node: Retrieve numa_node location. + :param skip_vpp: Skip VPP node. :type nodes: dict :type skip_tg: bool - :type skip_tg_udev: bool - :type numa_node: bool + :type skip_vpp: bool """ - for node_data in nodes.values(): - if node_data[u"type"] == NodeType.DUT: - InterfaceUtil.update_vpp_interface_data_on_node(node_data) - elif node_data[u"type"] == NodeType.TG and not skip_tg: - InterfaceUtil.update_tg_interface_data_on_node( - node_data, skip_tg_udev) - - if numa_node: - if node_data[u"type"] == NodeType.DUT: - InterfaceUtil.iface_update_numa_node(node_data) - elif node_data[u"type"] == NodeType.TG and not skip_tg: - InterfaceUtil.iface_update_numa_node(node_data) + for node in nodes.values(): + if node[u"type"] == NodeType.DUT and not skip_vpp: + InterfaceUtil.update_vpp_interface_data_on_node(node) + elif node[u"type"] == NodeType.TG and not skip_tg: + InterfaceUtil.update_tg_interface_data_on_node(node) + InterfaceUtil.iface_update_numa_node(node) @staticmethod def create_vlan_subinterface(node, interface, vlan): @@ -850,16 +791,16 @@ class InterfaceUtil: :raises RuntimeError: if it is unable to create VxLAN interface on the node. """ - src_address = ip_address(source_ip) - dst_address = ip_address(destination_ip) - cmd = u"vxlan_add_del_tunnel" args = dict( - is_add=1, - is_ipv6=1 if src_address.version == 6 else 0, + is_add=True, instance=Constants.BITWISE_NON_ZERO, - src_address=src_address.packed, - dst_address=dst_address.packed, + 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=Constants.BITWISE_NON_ZERO, @@ -897,9 +838,9 @@ class InterfaceUtil: cmd = u"sw_interface_set_vxlan_bypass" args = dict( - is_ipv6=0, + is_ipv6=False, sw_if_index=sw_if_index, - enable=1 + enable=True ) err_msg = f"Failed to set VXLAN bypass on interface " \ f"on host {node[u'host']}" @@ -929,16 +870,8 @@ class InterfaceUtil: :returns: Processed vxlan interface dump. :rtype: dict """ - if vxlan_dump[u"is_ipv6"]: - vxlan_dump[u"src_address"] = \ - ip_address(vxlan_dump[u"src_address"]) - vxlan_dump[u"dst_address"] = \ - ip_address(vxlan_dump[u"dst_address"]) - else: - vxlan_dump[u"src_address"] = \ - ip_address(vxlan_dump[u"src_address"][0:4]) - vxlan_dump[u"dst_address"] = \ - ip_address(vxlan_dump[u"dst_address"][0:4]) + 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: @@ -1183,16 +1116,21 @@ class InterfaceUtil: ) @staticmethod - def vpp_create_avf_interface(node, if_key, num_rx_queues=None): + 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 @@ -1208,8 +1146,8 @@ class InterfaceUtil: 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 + rxq_size=rxq_size, + txq_size=txq_size ) err_msg = f"Failed to create AVF interface on host {node[u'host']}" with PapiSocketExecutor(node) as papi_exec: @@ -1224,37 +1162,49 @@ class InterfaceUtil: @staticmethod def vpp_create_rdma_interface( - node, if_key, num_rx_queues=None, mode=u"auto"): + 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 avf level debug" + ) + cmd = u"rdma_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=1024, - txq_size=1024, - mode=getattr(RdmaMode,f"RDMA_API_MODE_{mode.upper()}").value, + rxq_size=rxq_size, + txq_size=txq_size, + mode=getattr(RdmaMode, f"RDMA_API_MODE_{mode.upper()}").value, ) 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 @@ -1425,6 +1375,8 @@ class InterfaceUtil: def get_sw_if_index(node, interface_name): """Get sw_if_index for the given interface from actual interface dump. + FIXME: Delete and redirect callers to vpp_get_interface_sw_index. + :param node: VPP node to get interface data from. :param interface_name: Name of the specific interface. :type node: dict