X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=0b1f06f9bfd14fbf89379f0437266784854fe3c7;hp=5617c472f445507c2162e181db1f065af1b7fa0e;hb=33fb34665214bbbd0a4b3154169b21c2da01f69b;hpb=fe1975eb1ac994df1bd759deda7154bb7dd9d7a7 diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 5617c472f4..0b1f06f9bf 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -13,18 +13,16 @@ """Interface util library.""" -from socket import AF_INET, AF_INET6, inet_ntop, inet_pton +from socket import AF_INET, AF_INET6, inet_ntop from time import sleep from enum import IntEnum -from ipaddress import IPv4Address, IPv6Address -from ipaddress import AddressValueError, NetmaskValueError +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.IPUtil import convert_ipv4_netmask_prefix from resources.libraries.python.L2Util import L2Util from resources.libraries.python.PapiExecutor import PapiExecutor from resources.libraries.python.parsers.JsonParser import JsonParser @@ -64,7 +62,6 @@ class InterfaceUtil(object): :returns: Integer representation of PCI address. :rtype: int """ - pci = list(pci_str.split(':')[0:2]) pci.extend(pci_str.split(':')[2].split('.')) @@ -82,7 +79,6 @@ class InterfaceUtil(object): :returns: SW interface index. :rtype: int """ - try: sw_if_index = int(interface) except ValueError: @@ -115,7 +111,6 @@ class InterfaceUtil(object): :raises ValueError: If the state of interface is unexpected. :raises ValueError: If the node has an unknown node type. """ - if if_type == 'key': if isinstance(interface, basestring): sw_if_index = Topology.get_interface_sw_index(node, interface) @@ -144,8 +139,7 @@ class InterfaceUtil(object): args = dict(sw_if_index=sw_if_index, admin_up_down=admin_up_down) with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + papi_exec.add(cmd, **args).get_reply(err_msg) elif node['type'] == NodeType.TG or node['type'] == NodeType.VM: cmd = 'ip link set {ifc} {state}'.format( ifc=iface_name, state=state) @@ -170,7 +164,6 @@ class InterfaceUtil(object): :raises ValueError: If the node type is "DUT". :raises ValueError: If the node has an unknown node type. """ - if node['type'] == NodeType.DUT: raise ValueError('Node {}: Setting Ethernet MTU for interface ' 'on DUT nodes not supported', node['host']) @@ -192,7 +185,6 @@ class InterfaceUtil(object): :type node: dict :returns: Nothing. """ - for ifc in node['interfaces']: InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500) @@ -207,7 +199,6 @@ class InterfaceUtil(object): :type interface: str or int :type mtu: int """ - if isinstance(interface, basestring): sw_if_index = Topology.get_interface_sw_index(node, interface) else: @@ -218,9 +209,13 @@ class InterfaceUtil(object): host=node['host']) args = dict(sw_if_index=sw_if_index, mtu=int(mtu)) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + try: + with PapiExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) + except AssertionError as err: + # TODO: Make failure tolerance optional. + logger.debug("Setting MTU failed. Expected?\n{err}".format( + err=err)) @staticmethod def vpp_set_interfaces_mtu_on_node(node, mtu=9200): @@ -231,7 +226,6 @@ class InterfaceUtil(object): :type node: dict :type mtu: int """ - for interface in node['interfaces']: InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu) @@ -244,7 +238,6 @@ class InterfaceUtil(object): :type nodes: dict :type mtu: int """ - for node in nodes.values(): if node['type'] == NodeType.DUT: InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu) @@ -262,7 +255,6 @@ class InterfaceUtil(object): :raises RuntimeError: If any interface is not in link-up state after defined number of retries. """ - for _ in xrange(0, retries): not_ready = list() out = InterfaceUtil.vpp_get_interface_data(node) @@ -293,7 +285,6 @@ class InterfaceUtil(object): :type retries: int :returns: Nothing. """ - for node in nodes.values(): if node['type'] == NodeType.DUT: InterfaceUtil.vpp_node_interfaces_ready_wait(node, retries) @@ -314,7 +305,6 @@ class InterfaceUtil(object): :raises TypeError: if the data type of interface is neither basestring nor int. """ - if interface is not None: if isinstance(interface, basestring): param = 'interface_name' @@ -327,15 +317,12 @@ class InterfaceUtil(object): param = '' cmd = 'sw_interface_dump' - cmd_reply = 'sw_interface_details' args = dict(name_filter_valid=0, name_filter='') err_msg = 'Failed to get interface dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) - - papi_if_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd, **args).get_details(err_msg) def process_if_dump(if_dump): """Process interface dump. @@ -353,12 +340,11 @@ class InterfaceUtil(object): return if_dump data = list() if interface is None else dict() - for item in papi_if_dump: + for if_dump in details: if interface is None: - data.append(process_if_dump(item[cmd_reply])) - elif str(item[cmd_reply].get(param)).rstrip('\x00') == \ - str(interface): - data = process_if_dump(item[cmd_reply]) + data.append(process_if_dump(if_dump)) + elif str(if_dump.get(param)).rstrip('\x00') == str(interface): + data = process_if_dump(if_dump) break logger.debug('Interface data:\n{if_data}'.format(if_data=data)) @@ -376,7 +362,6 @@ class InterfaceUtil(object): :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( @@ -396,7 +381,6 @@ class InterfaceUtil(object): :returns: Name of the given interface. :rtype: str """ - if_data = InterfaceUtil.vpp_get_interface_data(node, interface_name) return if_data.get('sw_if_index') @@ -412,7 +396,6 @@ class InterfaceUtil(object): :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( @@ -420,56 +403,6 @@ class InterfaceUtil(object): return if_data.get('l2_address') - @staticmethod - def vpp_get_interface_ip_addresses(node, interface, ip_version): - """Get list of IP addresses from an interface on a VPP node. - - TODO: Move to IPUtils - - :param node: VPP node to get data from. - :param interface: Name of an interface on the VPP node. - :param ip_version: IP protocol version (ipv4 or ipv6). - :type node: dict - :type interface: str - :type ip_version: str - :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 - """ - - 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 - - is_ipv6 = 1 if ip_version == 'ipv6' else 0 - - cmd = 'ip_address_dump' - cmd_reply = 'ip_address_details' - args = dict(sw_if_index=sw_if_index, - is_ipv6=is_ipv6) - err_msg = 'Failed to get L2FIB dump on host {host}'.format( - host=node['host']) - with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) - - data = list() - for item in papi_resp.reply[0]['api_reply']: - item[cmd_reply]['ip'] = inet_ntop(AF_INET6, item[cmd_reply]['ip']) \ - if is_ipv6 else inet_ntop(AF_INET, item[cmd_reply]['ip'][0:4]) - data.append(item[cmd_reply]) - - if ip_version == 'ipv4': - for item in data: - item['netmask'] = convert_ipv4_netmask_prefix( - item['prefix_length']) - return data - @staticmethod def tg_set_interface_driver(node, pci_addr, driver): """Set interface driver on the TG node. @@ -586,7 +519,6 @@ class InterfaceUtil(object): :param node: Node selected from DICT__nodes. :type node: dict """ - interface_list = InterfaceUtil.vpp_get_interface_data(node) interface_dict = dict() for ifc in interface_list: @@ -789,7 +721,6 @@ class InterfaceUtil(object): :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) @@ -799,16 +730,14 @@ class InterfaceUtil(object): err_msg = 'Failed to create VLAN sub-interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['sw_if_index'] if_key = Topology.add_new_port(node, 'vlan_subif') - 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_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}.{vlan}'.format(ifc=interface, vlan=vlan), sw_if_idx + return '{ifc}.{vlan}'.format(ifc=interface, vlan=vlan), sw_if_index @staticmethod def create_vxlan_interface(node, vni, source_ip, destination_ip): @@ -827,24 +756,15 @@ class InterfaceUtil(object): :raises RuntimeError: if it is unable to create VxLAN interface on the node. """ - - try: - src_address = IPv6Address(unicode(source_ip)) - dst_address = IPv6Address(unicode(destination_ip)) - af_inet = AF_INET6 - is_ipv6 = 1 - except (AddressValueError, NetmaskValueError): - src_address = IPv4Address(unicode(source_ip)) - dst_address = IPv4Address(unicode(destination_ip)) - af_inet = AF_INET - is_ipv6 = 0 + src_address = ip_address(unicode(source_ip)) + dst_address = ip_address(unicode(destination_ip)) cmd = 'vxlan_add_del_tunnel' args = dict(is_add=1, - is_ipv6=is_ipv6, + is_ipv6=1 if src_address.version == 6 else 0, instance=Constants.BITWISE_NON_ZERO, - src_address=inet_pton(af_inet, str(src_address)), - dst_address=inet_pton(af_inet, str(dst_address)), + src_address=src_address.packed, + dst_address=dst_address.packed, mcast_sw_if_index=Constants.BITWISE_NON_ZERO, encap_vrf_id=0, decap_next_index=Constants.BITWISE_NON_ZERO, @@ -852,16 +772,14 @@ class InterfaceUtil(object): err_msg = 'Failed to create VXLAN tunnel interface on host {host}'.\ format(host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['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_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_idx + return sw_if_index @staticmethod def vxlan_dump(node, interface=None): @@ -878,21 +796,17 @@ class InterfaceUtil(object): :raises TypeError: if the data type of interface is neither basestring nor int. """ - if interface is not None: sw_if_index = InterfaceUtil.get_interface_index(node, interface) else: sw_if_index = int(Constants.BITWISE_NON_ZERO) cmd = 'vxlan_tunnel_dump' - cmd_reply = 'vxlan_tunnel_details' args = dict(sw_if_index=sw_if_index) err_msg = 'Failed to get VXLAN dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) - - papi_vxlan_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd, **args).get_details(err_msg) def process_vxlan_dump(vxlan_dump): """Process vxlan dump. @@ -915,11 +829,11 @@ class InterfaceUtil(object): return vxlan_dump data = list() if interface is None else dict() - for item in papi_vxlan_dump: + for vxlan_dump in details: if interface is None: - data.append(process_vxlan_dump(item[cmd_reply])) - elif item[cmd_reply]['sw_if_index'] == sw_if_index: - data = process_vxlan_dump(item[cmd_reply]) + data.append(process_vxlan_dump(vxlan_dump)) + elif vxlan_dump['sw_if_index'] == sw_if_index: + data = process_vxlan_dump(vxlan_dump) break logger.debug('VXLAN data:\n{vxlan_data}'.format(vxlan_data=data)) @@ -936,15 +850,11 @@ class InterfaceUtil(object): :returns: List of dictionaries with all vhost-user interfaces. :rtype: list """ - cmd = 'sw_interface_vhost_user_dump' - cmd_reply = 'sw_interface_vhost_user_details' err_msg = 'Failed to get vhost-user dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd).get_dump(err_msg) - - papi_vxlan_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd).get_details(err_msg) def process_vhost_dump(vhost_dump): """Process vhost dump. @@ -960,12 +870,13 @@ class InterfaceUtil(object): vhost_dump['sock_filename'].rstrip('\x00') return vhost_dump - data = list() - for item in papi_vxlan_dump: - data.append(process_vhost_dump(item[cmd_reply])) + for vhost_dump in details: + # In-place edits. + process_vhost_dump(vhost_dump) - logger.debug('Vhost-user data:\n{vhost_data}'.format(vhost_data=data)) - return data + logger.debug('Vhost-user details:\n{vhost_details}'.format( + vhost_details=details)) + return details @staticmethod def tap_dump(node, name=None): @@ -982,15 +893,11 @@ class InterfaceUtil(object): a List of dictionaries containing all TAP data for the given node. :rtype: dict or list """ - cmd = 'sw_interface_tap_v2_dump' - cmd_reply = 'sw_interface_tap_v2_details' err_msg = 'Failed to get TAP dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd).get_dump(err_msg) - - papi_tap_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd).get_details(err_msg) def process_tap_dump(tap_dump): """Process tap dump. @@ -1013,11 +920,11 @@ class InterfaceUtil(object): return tap_dump data = list() if name is None else dict() - for item in papi_tap_dump: + for tap_dump in details: if name is None: - data.append(process_tap_dump(item[cmd_reply])) - elif item[cmd_reply].get('dev_name').rstrip('\x00') == name: - data = process_tap_dump(item[cmd_reply]) + data.append(process_tap_dump(tap_dump)) + elif tap_dump.get('dev_name').rstrip('\x00') == name: + data = process_tap_dump(tap_dump) break logger.debug('TAP data:\n{tap_data}'.format(tap_data=data)) @@ -1047,7 +954,6 @@ class InterfaceUtil(object): :rtype: tuple :raises RuntimeError: If it is not possible to create sub-interface. """ - subif_types = type_subif.split() cmd = 'create_subif' @@ -1067,16 +973,14 @@ class InterfaceUtil(object): err_msg = 'Failed to create sub-interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_subif_idx = papi_resp['sw_if_index'] 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_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}.{s_id}'.format(ifc=interface, s_id=sub_id), sw_subif_idx + return '{ifc}.{s_id}'.format(ifc=interface, s_id=sub_id), sw_if_index @staticmethod def create_gre_tunnel_interface(node, source_ip, destination_ip): @@ -1092,7 +996,6 @@ class InterfaceUtil(object): :rtype: tuple :raises RuntimeError: If unable to create GRE tunnel interface. """ - cmd = 'gre_tunnel_add_del' tunnel = dict(type=0, instance=Constants.BITWISE_NON_ZERO, @@ -1105,16 +1008,14 @@ class InterfaceUtil(object): err_msg = 'Failed to create GRE tunnel interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['sw_if_index'] if_key = Topology.add_new_port(node, 'gre_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_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_idx + return ifc_name, sw_if_index @staticmethod def vpp_create_loopback(node): @@ -1127,22 +1028,19 @@ class InterfaceUtil(object): :raises RuntimeError: If it is not possible to create loopback on the node. """ - cmd = 'create_loopback' args = dict(mac_address=0) err_msg = 'Failed to create loopback interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['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_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_idx + return sw_if_index @staticmethod def vpp_create_bond_interface(node, mode, load_balance=None, mac=None): @@ -1162,7 +1060,6 @@ class InterfaceUtil(object): :raises RuntimeError: If it is not possible to create bond interface on the node. """ - cmd = 'bond_create' args = dict(id=int(Constants.BITWISE_NON_ZERO), use_custom_mac=0 if mac is None else 1, @@ -1175,39 +1072,37 @@ class InterfaceUtil(object): err_msg = 'Failed to create bond interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['sw_if_index'] - InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx, + 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_idx) + 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_idx=None, ifc_pfx=None): + def add_eth_interface(node, ifc_name=None, sw_if_index=None, ifc_pfx=None): """Add ethernet interface to current topology. :param node: DUT node from topology. :param ifc_name: Name of the interface. - :param sw_if_idx: SW interface index. + :param sw_if_index: SW interface index. :param ifc_pfx: Interface key prefix. :type node: dict :type ifc_name: str - :type sw_if_idx: int + :type sw_if_index: int :type ifc_pfx: str """ - if_key = Topology.add_new_port(node, ifc_pfx) - if ifc_name and sw_if_idx is None: - sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(node, ifc_name) - Topology.update_interface_sw_if_index(node, if_key, sw_if_idx) - if sw_if_idx and ifc_name is None: - ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx) + 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_idx) + ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index) Topology.update_interface_mac_address(node, if_key, ifc_mac) @staticmethod @@ -1225,7 +1120,6 @@ class InterfaceUtil(object): :raises RuntimeError: If it is not possible to create AVF interface on the node. """ - cmd = 'avf_create' args = dict(pci_addr=InterfaceUtil.pci_to_int(vf_pci_addr), enable_elog=0, @@ -1235,13 +1129,11 @@ class InterfaceUtil(object): err_msg = 'Failed to create AVF interface on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) - sw_if_idx = papi_resp['sw_if_index'] - InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx, + 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_idx) + if_key = Topology.get_interface_by_sw_index(node, sw_if_index) return if_key @@ -1258,7 +1150,6 @@ class InterfaceUtil(object): :raises RuntimeError: If it is not possible to enslave physical interface to bond interface on the node. """ - cmd = 'bond_enslave' args = dict( sw_if_index=Topology.get_interface_sw_index(node, interface), @@ -1270,56 +1161,46 @@ class InterfaceUtil(object): bond=bond_if, host=node['host']) with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod - def vpp_show_bond_data_on_node(node, details=False): + def vpp_show_bond_data_on_node(node, verbose=False): """Show (detailed) bond information on VPP node. :param node: DUT node from topology. - :param details: If detailed information is required or not. + :param verbose: If detailed information is required or not. :type node: dict - :type details: bool + :type verbose: bool """ - cmd = 'sw_interface_bond_dump' - cmd_reply = 'sw_interface_bond_details' err_msg = 'Failed to get bond interface dump on host {host}'.format( host=node['host']) data = ('Bond data on node {host}:\n'.format(host=node['host'])) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd).get_dump(err_msg) - - papi_dump = papi_resp.reply[0]['api_reply'] - for item in papi_dump: - data += ('{b}\n'.format(b=item[cmd_reply]['interface_name']. - rstrip('\x00'))) - data += (' mode: {m}\n'. - format(m=LinkBondMode(item[cmd_reply]['mode']).name. - lower())) - data += (' load balance: {lb}\n'. - format(lb=LinkBondLoadBalance(item[cmd_reply]['lb']).name. - lower())) - data += (' number of active slaves: {n}\n'. - format(n=item[cmd_reply]['active_slaves'])) - if details: + 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=LinkBondMode( + bond['mode']).name.lower())) + data += (' load balance: {lb}\n'.format(lb=LinkBondLoadBalance( + bond['lb']).name.lower())) + data += (' number of active slaves: {n}\n'.format( + n=bond['active_slaves'])) + if verbose: slave_data = InterfaceUtil.vpp_bond_slave_dump( node, Topology.get_interface_by_sw_index( - node, item[cmd_reply]['sw_if_index'])) + node, bond['sw_if_index'])) for slave in slave_data: if not slave['is_passive']: data += (' {s}\n'.format(s=slave['interface_name'])) - data += (' number of slaves: {n}\n'. - format(n=item[cmd_reply]['slaves'])) - if details: + data += (' number of slaves: {n}\n'.format(n=bond['slaves'])) + if verbose: for slave in slave_data: data += (' {s}\n'.format(s=slave['interface_name'])) - data += (' interface id: {i}\n'. - format(i=item[cmd_reply]['id'])) - data += (' sw_if_index: {i}\n'. - format(i=item[cmd_reply]['sw_if_index'])) + data += (' interface id: {i}\n'.format(i=bond['id'])) + data += (' sw_if_index: {i}\n'.format(i=bond['sw_if_index'])) logger.info(data) @staticmethod @@ -1334,16 +1215,13 @@ class InterfaceUtil(object): :rtype: dict """ cmd = 'sw_interface_slave_dump' - cmd_reply = 'sw_interface_slave_details' args = dict(sw_if_index=Topology.get_interface_sw_index( node, interface)) err_msg = 'Failed to get slave dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) - - papi_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd, **args).get_details(err_msg) def process_slave_dump(slave_dump): """Process slave dump. @@ -1357,25 +1235,25 @@ class InterfaceUtil(object): rstrip('\x00') return slave_dump - data = list() - for item in papi_dump: - data.append(process_slave_dump(item[cmd_reply])) + for slave_dump in details: + # In-place edits. + process_slave_dump(slave_dump) - logger.debug('Slave data:\n{slave_data}'.format(slave_data=data)) - return data + logger.debug('Slave data:\n{slave_data}'.format(slave_data=details)) + return details @staticmethod - def vpp_show_bond_data_on_all_nodes(nodes, details=False): + 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 details: If detailed information is required or not. + :param verbose: If detailed information is required or not. :type nodes: dict - :type details: bool + :type verbose: bool """ for node_data in nodes.values(): if node_data['type'] == NodeType.DUT: - InterfaceUtil.vpp_show_bond_data_on_node(node_data, details) + InterfaceUtil.vpp_show_bond_data_on_node(node_data, verbose) @staticmethod def vpp_enable_input_acl_interface(node, interface, ip_version, @@ -1391,7 +1269,6 @@ class InterfaceUtil(object): :type ip_version: str :type table_index: int """ - cmd = 'input_acl_set_interface' args = dict( sw_if_index=InterfaceUtil.get_interface_index(node, interface), @@ -1405,8 +1282,7 @@ class InterfaceUtil(object): err_msg = 'Failed to enable input acl on interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod def get_interface_classify_table(node, interface): @@ -1431,43 +1307,9 @@ class InterfaceUtil(object): err_msg = 'Failed to get classify table name by interface {ifc}'.format( ifc=interface) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg). \ - verify_reply(err_msg=err_msg) + reply = papi_exec.add(cmd, **args).get_reply(err_msg) - return papi_resp - - @staticmethod - def get_interface_vrf_table(node, interface, ip_version='ipv4'): - """Get vrf ID for the given interface. - - TODO: Move to proper IP library when implementing CSIT-1459. - - :param node: VPP node. - :param interface: Name or sw_if_index of a specific interface. - :type node: dict - :param ip_version: IP protocol version (ipv4 or ipv6). - :type interface: str or int - :type ip_version: str - :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 - - is_ipv6 = 1 if ip_version == 'ipv6' else 0 - - cmd = 'sw_interface_get_table' - args = dict(sw_if_index=sw_if_index, - is_ipv6=is_ipv6) - err_msg = 'Failed to get VRF id assigned to interface {ifc}'.format( - ifc=interface) - with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg). \ - verify_reply(err_msg=err_msg) - - return papi_resp['vrf_id'] + return reply @staticmethod def get_sw_if_index(node, interface_name): @@ -1480,7 +1322,6 @@ class InterfaceUtil(object): :returns: sw_if_index of the given interface. :rtype: str """ - interface_data = InterfaceUtil.vpp_get_interface_data( node, interface=interface_name) return interface_data.get('sw_if_index') @@ -1499,7 +1340,6 @@ class InterfaceUtil(object): interfaces. :rtype: dict or list """ - if interface_name is not None: sw_if_index = InterfaceUtil.get_interface_index( node, interface_name) @@ -1507,14 +1347,11 @@ class InterfaceUtil(object): sw_if_index = int(Constants.BITWISE_NON_ZERO) cmd = 'vxlan_gpe_tunnel_dump' - cmd_reply = 'vxlan_gpe_tunnel_details' args = dict(sw_if_index=sw_if_index) err_msg = 'Failed to get VXLAN-GPE dump on host {host}'.format( host=node['host']) with PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_dump(err_msg) - - papi_vxlan_dump = papi_resp.reply[0]['api_reply'] + details = papi_exec.add(cmd, **args).get_details(err_msg) def process_vxlan_gpe_dump(vxlan_dump): """Process vxlan_gpe dump. @@ -1537,40 +1374,17 @@ class InterfaceUtil(object): return vxlan_dump data = list() if interface_name is None else dict() - for item in papi_vxlan_dump: + for vxlan_dump in details: if interface_name is None: - data.append(process_vxlan_gpe_dump(item[cmd_reply])) - elif item[cmd_reply]['sw_if_index'] == sw_if_index: - data = process_vxlan_gpe_dump(item[cmd_reply]) + data.append(process_vxlan_gpe_dump(vxlan_dump)) + elif vxlan_dump['sw_if_index'] == sw_if_index: + data = process_vxlan_gpe_dump(vxlan_dump) break logger.debug('VXLAN-GPE data:\n{vxlan_gpe_data}'.format( vxlan_gpe_data=data)) return data - @staticmethod - def vpp_ip_source_check_setup(node, if_name): - """Setup Reverse Path Forwarding source check on interface. - - TODO: Move to proper IP library when implementing CSIT-1459. - - :param node: Node to setup RPF source check. - :param if_name: Interface name to setup RPF source check. - :type node: dict - :type if_name: str - """ - - cmd = 'ip_source_check_interface_add_del' - args = dict( - sw_if_index=InterfaceUtil.get_interface_index(node, if_name), - is_add=1, - loose=0) - err_msg = 'Failed to enable source check on interface {ifc}'.format( - ifc=if_name) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg). \ - verify_reply(err_msg=err_msg) - @staticmethod def assign_interface_to_fib_table(node, interface, table_id, ipv6=False): """Assign VPP interface to specific VRF/FIB table. @@ -1584,7 +1398,6 @@ class InterfaceUtil(object): :type table_id: int :type ipv6: bool """ - cmd = 'sw_interface_set_table' args = dict( sw_if_index=InterfaceUtil.get_interface_index(node, interface), @@ -1593,8 +1406,7 @@ class InterfaceUtil(object): err_msg = 'Failed to assign interface {ifc} to FIB table'.format( ifc=interface) with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg). \ - verify_reply(err_msg=err_msg) + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod def set_linux_interface_mac(node, interface, mac, namespace=None, @@ -1680,15 +1492,17 @@ class InterfaceUtil(object): :type osi_layer: str :returns: Virtual Function topology interface keys. :rtype: list + :raises RuntimeError: If a reason preventing initialization is found. """ - 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) + if kernel_driver != "i40e": + raise RuntimeError( + "AVF needs i40e driver, not {driver} at node {host} ifc {ifc}"\ + .format(driver=kernel_driver, host=node["host"], ifc=ifc_key)) current_driver = DUTSetup.get_pci_dev_driver( node, pf_pci_addr.replace(':', r'\:')) @@ -1737,286 +1551,6 @@ class InterfaceUtil(object): return vf_ifc_keys - @staticmethod - def vpp_create_multiple_vxlan_ipv4_tunnels( - node, node_vxlan_if, node_vlan_if, op_node, op_node_if, - n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit, - bd_id_start): - """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on - VPP node. - - Put each pair of VXLAN tunnel interface and VLAN sub-interface to - separate bridge-domain. - - :param node: VPP node to create VXLAN tunnel interfaces. - :param node_vxlan_if: VPP node interface key to create VXLAN tunnel - interfaces. - :param node_vlan_if: VPP node interface key to create VLAN - sub-interface. - :param op_node: Opposite VPP node for VXLAN tunnel interfaces. - :param op_node_if: Opposite VPP node interface key for VXLAN tunnel - interfaces. - :param n_tunnels: Number of tunnel interfaces to create. - :param vni_start: VNI start ID. - :param src_ip_start: VXLAN tunnel source IP address start. - :param dst_ip_start: VXLAN tunnel destination IP address start. - :param ip_step: IP address incremental step. - :param ip_limit: IP address limit. - :param bd_id_start: Bridge-domain ID start. - :type node: dict - :type node_vxlan_if: str - :type node_vlan_if: str - :type op_node: dict - :type op_node_if: str - :type n_tunnels: int - :type vni_start: int - :type src_ip_start: str - :type dst_ip_start: str - :type ip_step: int - :type ip_limit: str - :type bd_id_start: int - """ - # configure IPs, create VXLAN interfaces and VLAN sub-interfaces - vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces( - node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start, - src_ip_start, dst_ip_start, ip_step, ip_limit) - - # update topology with VXLAN interfaces and VLAN sub-interfaces data - # and put interfaces up - InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up( - node, vxlan_count, node_vlan_if) - - # configure bridge domains, ARPs and routes - InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain( - node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start, - ip_step, bd_id_start) - - @staticmethod - def vpp_create_vxlan_and_vlan_interfaces( - node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start, - src_ip_start, dst_ip_start, ip_step, ip_limit): - """ - Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP - node. - - :param node: VPP node. - :param node_vxlan_if: VPP node interface key to create VXLAN tunnel - interfaces. - :param node_vlan_if: VPP node interface key to create VLAN - sub-interface. - :param vxlan_count: Number of tunnel interfaces to create. - :param vni_start: VNI start ID. - :param src_ip_start: VXLAN tunnel source IP address start. - :param dst_ip_start: VXLAN tunnel destination IP address start. - :param ip_step: IP address incremental step. - :param ip_limit: IP address limit. - :type node: dict - :type node_vxlan_if: str - :type node_vlan_if: str - :type vxlan_count: int - :type vni_start: int - :type src_ip_start: str - :type dst_ip_start: str - :type ip_step: int - :type ip_limit: str - :returns: Number of created VXLAN interfaces. - :rtype: int - """ - - try: - src_address_start = IPv6Address(unicode(src_ip_start)) - dst_address_start = IPv6Address(unicode(dst_ip_start)) - ip_address_limit = IPv6Address(unicode(ip_limit)) - af_inet = AF_INET6 - is_ipv6 = 1 - except (AddressValueError, NetmaskValueError): - src_address_start = IPv4Address(unicode(src_ip_start)) - dst_address_start = IPv4Address(unicode(dst_ip_start)) - ip_address_limit = IPv4Address(unicode(ip_limit)) - af_inet = AF_INET - is_ipv6 = 0 - - with PapiExecutor(node) as papi_exec: - for i in xrange(0, vxlan_count): - src_ip = src_address_start + i * ip_step - dst_ip = dst_address_start + i * ip_step - if src_ip > ip_address_limit or dst_ip > ip_address_limit: - logger.warn("Can't do more iterations - IP address limit " - "has been reached.") - vxlan_count = i - break - cmd = 'sw_interface_add_del_address' - args = dict( - sw_if_index=InterfaceUtil.get_interface_index( - node, node_vxlan_if), - is_add=1, - is_ipv6=0, - del_all=0, - address_length=128 if is_ipv6 else 32, - address=inet_pton(af_inet, str(src_ip))) - papi_exec.add(cmd, **args) - cmd = 'vxlan_add_del_tunnel' - args = dict( - is_add=1, - is_ipv6=0, - instance=Constants.BITWISE_NON_ZERO, - src_address=inet_pton(af_inet, str(src_ip)), - dst_address=inet_pton(af_inet, str(dst_ip)), - mcast_sw_if_index=Constants.BITWISE_NON_ZERO, - encap_vrf_id=0, - decap_next_index=Constants.BITWISE_NON_ZERO, - vni=int(vni_start)+i) - papi_exec.add(cmd, **args) - cmd = 'create_vlan_subif' - args = dict( - sw_if_index=InterfaceUtil.get_interface_index( - node, node_vlan_if), - vlan_id=i+1) - papi_exec.add(cmd, **args) - papi_exec.get_replies().verify_replies() - - return vxlan_count - - @staticmethod - def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if): - """ - Update topology with VXLAN interfaces and VLAN sub-interfaces data - and put interfaces up. - - :param node: VPP node. - :param vxlan_count: Number of tunnel interfaces. - :param node_vlan_if: VPP node interface key where VLAN sub-interfaces - have been created. - :type node: dict - :type vxlan_count: int - :type node_vlan_if: str - """ - - if_data = InterfaceUtil.vpp_get_interface_data(node) - - with PapiExecutor(node) as papi_exec: - for i in xrange(0, vxlan_count): - vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel') - vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i) - vxlan_found = False - vxlan_subif_idx = None - vlan_subif_key = Topology.add_new_port(node, 'vlan_subif') - vlan_subif_name = '{if_name}.{vlan}'.format( - if_name=Topology.get_interface_name( - node, node_vlan_if), vlan=i+1) - vlan_found = False - vlan_idx = None - for data in if_data: - if not vxlan_found \ - and data['interface_name'] == vxlan_subif_name: - vxlan_subif_idx = data['sw_if_index'] - vxlan_found = True - elif not vlan_found \ - and data['interface_name'] == vlan_subif_name: - vlan_idx = data['sw_if_index'] - vlan_found = True - if vxlan_found and vlan_found: - break - Topology.update_interface_sw_if_index( - node, vxlan_subif_key, vxlan_subif_idx) - Topology.update_interface_name( - node, vxlan_subif_key, vxlan_subif_name) - cmd = 'sw_interface_set_flags' - args1 = dict(sw_if_index=vxlan_subif_idx, - admin_up_down=1) - Topology.update_interface_sw_if_index( - node, vlan_subif_key, vlan_idx) - Topology.update_interface_name( - node, vlan_subif_key, vlan_subif_name) - args2 = dict(sw_if_index=vlan_idx, - admin_up_down=1) - papi_exec.add(cmd, **args1).add(cmd, **args2) - papi_exec.get_replies().verify_replies() - - @staticmethod - def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain( - node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start, - ip_step, bd_id_start): - """ - Configure ARPs and routes for VXLAN interfaces and put each pair of - VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain. - - :param node: VPP node. - :param node_vxlan_if: VPP node interface key where VXLAN tunnel - interfaces have been created. - :param vxlan_count: Number of tunnel interfaces. - :param op_node: Opposite VPP node for VXLAN tunnel interfaces. - :param op_node_if: Opposite VPP node interface key for VXLAN tunnel - interfaces. - :param dst_ip_start: VXLAN tunnel destination IP address start. - :param ip_step: IP address incremental step. - :param bd_id_start: Bridge-domain ID start. - :type node: dict - :type node_vxlan_if: str - :type vxlan_count: int - :type op_node: dict - :type op_node_if: - :type dst_ip_start: str - :type ip_step: int - :type bd_id_start: int - """ - - try: - dst_address_start = IPv6Address(unicode(dst_ip_start)) - af_inet = AF_INET6 - is_ipv6 = 1 - except (AddressValueError, NetmaskValueError): - dst_address_start = IPv4Address(unicode(dst_ip_start)) - af_inet = AF_INET - is_ipv6 = 0 - - with PapiExecutor(node) as papi_exec: - for i in xrange(0, vxlan_count): - dst_ip = dst_address_start + i * ip_step - neighbor = dict( - sw_if_index=Topology.get_interface_sw_index( - node, node_vxlan_if), - flags=0, - mac_address=str( - Topology.get_interface_mac(op_node, op_node_if)), - ip_address=str(dst_ip)) - cmd = 'ip_neighbor_add_del' - args = dict( - is_add=1, - neighbor=neighbor) - papi_exec.add(cmd, **args) - cmd = 'ip_add_del_route' - args = dict( - next_hop_sw_if_index=Topology.get_interface_sw_index( - node, node_vxlan_if), - table_id=0, - is_add=1, - is_ipv6=is_ipv6, - next_hop_weight=1, - next_hop_proto=1 if is_ipv6 else 0, - dst_address_length=128 if is_ipv6 else 32, - dst_address=inet_pton(af_inet, str(dst_ip)), - next_hop_address=inet_pton(af_inet, str(dst_ip))) - papi_exec.add(cmd, **args) - cmd = 'sw_interface_set_l2_bridge' - args = dict( - rx_sw_if_index=Topology.get_interface_sw_index( - node, 'vxlan_tunnel{nr}'.format(nr=i+1)), - bd_id=int(bd_id_start+i), - shg=0, - port_type=0, - enable=1) - papi_exec.add(cmd, **args) - args = dict( - rx_sw_if_index=Topology.get_interface_sw_index( - node, 'vlan_subif{nr}'.format(nr=i+1)), - bd_id=int(bd_id_start+i), - shg=0, - port_type=0, - enable=1) - papi_exec.add(cmd, **args) - papi_exec.get_replies().verify_replies() - @staticmethod def vpp_sw_interface_rx_placement_dump(node): """Dump VPP interface RX placement on node. @@ -2026,19 +1560,15 @@ class InterfaceUtil(object): :returns: Thread mapping information as a list of dictionaries. :rtype: list """ - cmd = 'sw_interface_rx_placement_dump' - cmd_reply = 'sw_interface_rx_placement_details' err_msg = "Failed to run '{cmd}' PAPI command on host {host}!".format( cmd=cmd, host=node['host']) with PapiExecutor(node) as papi_exec: for ifc in node['interfaces'].values(): if ifc['vpp_sw_index'] is not None: papi_exec.add(cmd, sw_if_index=ifc['vpp_sw_index']) - papi_resp = papi_exec.get_dump(err_msg) - thr_mapping = [s[cmd_reply] for r in papi_resp.reply - for s in r['api_reply']] - return sorted(thr_mapping, key=lambda k: k['sw_if_index']) + details = papi_exec.get_details(err_msg) + return sorted(details, key=lambda k: k['sw_if_index']) @staticmethod def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id, @@ -2056,15 +1586,13 @@ class InterfaceUtil(object): :raises RuntimeError: If failed to run command on host or if no API reply received. """ - 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) with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod def vpp_round_robin_rx_placement(node, prefix): @@ -2078,6 +1606,8 @@ class InterfaceUtil(object): """ worker_id = 0 worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1 + if not worker_cnt: + return for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node): for interface in node['interfaces'].values(): if placement['sw_if_index'] == interface['vpp_sw_index'] \