X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FInterfaceUtil.py;h=d185137940f8417eb422a4839d9e7cdb777f99d3;hb=909a91c2a2b08a85d700542a77f8b69434f5ded1;hp=34bfc1efe554d045f246154c54a71eeec111b01a;hpb=1577123a3c27541181097cb4186aa8855f20b1cc;p=csit.git diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 34bfc1efe5..d185137940 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -13,39 +13,94 @@ """Interface util library.""" -from socket import AF_INET, AF_INET6, inet_ntop, inet_pton 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.L2Util import L2Util -from resources.libraries.python.PapiExecutor import PapiExecutor +from resources.libraries.python.PapiExecutor import PapiSocketExecutor from resources.libraries.python.parsers.JsonParser import JsonParser from resources.libraries.python.ssh import SSH, exec_cmd_no_error from resources.libraries.python.topology import NodeType, Topology from resources.libraries.python.VPPUtil import VPPUtil -class LinkBondLoadBalance(IntEnum): - """Link bonding load balance.""" - L2 = 0 - 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): @@ -69,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. @@ -128,20 +202,20 @@ 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) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + 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: cmd = 'ip link set {ifc} {state}'.format( ifc=iface_name, state=state) @@ -211,9 +285,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 PapiSocketExecutor(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): @@ -257,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: @@ -303,6 +380,26 @@ class InterfaceUtil(object): :raises TypeError: if the data type of interface is neither basestring nor int. """ + def process_if_dump(if_dump): + """Process interface dump. + + :param if_dump: Interface dump. + :type if_dump: dict + :returns: Processed interface dump. + :rtype: dict + """ + 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: if isinstance(interface, basestring): param = 'interface_name' @@ -315,38 +412,22 @@ class InterfaceUtil(object): param = '' cmd = 'sw_interface_dump' - cmd_reply = 'sw_interface_details' - 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 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'] - - def process_if_dump(if_dump): - """Process interface dump. - - :param if_dump: Interface dump. - :type if_dump: dict - :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']) - return if_dump + 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 item in papi_if_dump: + for 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(dump)) + elif str(dump.get(param)).rstrip('\x00') == str(interface): + data = process_if_dump(dump) break logger.debug('Interface data:\n{if_data}'.format(if_data=data)) @@ -713,35 +794,35 @@ class InterfaceUtil(object): """Create VLAN sub-interface on node. :param node: Node to add VLAN subinterface on. - :param interface: Interface name on which create VLAN subinterface. + :param interface: Interface name or index on which create VLAN + subinterface. :param vlan: VLAN ID of the subinterface to be created. :type node: dict - :type interface: str + :type interface: str on int :type vlan: int :returns: Name and index of created subinterface. :rtype: tuple :raises RuntimeError: if it is unable to create VLAN subinterface on the - node. + node or interface cannot be converted. """ - iface_key = Topology.get_interface_by_name(node, interface) - sw_if_index = Topology.get_interface_sw_index(node, iface_key) + 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 PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + with PapiSocketExecutor(node) as papi_exec: + 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): @@ -760,40 +841,57 @@ 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, vni=int(vni)) 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) + with PapiSocketExecutor(node) as papi_exec: + 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 set_vxlan_bypass(node, interface=None): + """Add the 'ip4-vxlan-bypass' graph node for a given interface. + + By adding the IPv4 vxlan-bypass graph node to an interface, the node + checks for and validate input vxlan packet and bypass ip4-lookup, + ip4-local, ip4-udp-lookup nodes to speedup vxlan packet forwarding. + This node will cause extra overhead to for non-vxlan packets which is + kept at a minimum. + + :param node: Node where to set VXLAN bypass. + :param interface: Numeric index or name string of a specific interface. + :type node: dict + :type interface: int or str + :raises RuntimeError: if it failed to set VXLAN bypass on interface. + """ + sw_if_index = InterfaceUtil.get_interface_index(node, interface) + + cmd = 'sw_interface_set_vxlan_bypass' + args = dict(is_ipv6=0, + sw_if_index=sw_if_index, + enable=1) + err_msg = 'Failed to set VXLAN bypass on interface on host {host}'.\ + format(host=node['host']) + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_replies(err_msg) @staticmethod def vxlan_dump(node, interface=None): @@ -810,21 +908,6 @@ 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'] - def process_vxlan_dump(vxlan_dump): """Process vxlan dump. @@ -835,22 +918,34 @@ class InterfaceUtil(object): """ if vxlan_dump['is_ipv6']: vxlan_dump['src_address'] = \ - inet_ntop(AF_INET6, vxlan_dump['src_address']) + ip_address(unicode(vxlan_dump['src_address'])) vxlan_dump['dst_address'] = \ - inet_ntop(AF_INET6, vxlan_dump['dst_address']) + ip_address(unicode(vxlan_dump['dst_address'])) else: vxlan_dump['src_address'] = \ - inet_ntop(AF_INET, vxlan_dump['src_address'][0:4]) + ip_address(unicode(vxlan_dump['src_address'][0:4])) vxlan_dump['dst_address'] = \ - inet_ntop(AF_INET, vxlan_dump['dst_address'][0:4]) + ip_address(unicode(vxlan_dump['dst_address'][0:4])) return vxlan_dump + 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' + args = dict(sw_if_index=sw_if_index) + err_msg = 'Failed to get VXLAN dump on host {host}'.format( + host=node['host']) + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd, **args).get_details(err_msg) + data = list() if interface is None else dict() - for item in papi_vxlan_dump: + for 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(dump)) + elif dump['sw_if_index'] == sw_if_index: + data = process_vxlan_dump(dump) break logger.debug('VXLAN data:\n{vxlan_data}'.format(vxlan_data=data)) @@ -867,15 +962,6 @@ 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'] - def process_vhost_dump(vhost_dump): """Process vhost dump. @@ -890,67 +976,19 @@ 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])) - - logger.debug('Vhost-user data:\n{vhost_data}'.format(vhost_data=data)) - return data - - @staticmethod - def tap_dump(node, name=None): - """Get all TAP interface data from the given node, or data about - a specific TAP interface. - - TODO: Move to Tap.py - - :param node: VPP node to get data from. - :param name: Optional name of a specific TAP interface. - :type node: dict - :type name: str - :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 - """ - cmd = 'sw_interface_tap_v2_dump' - cmd_reply = 'sw_interface_tap_v2_details' - err_msg = 'Failed to get TAP dump on host {host}'.format( + cmd = 'sw_interface_vhost_user_dump' + 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) + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd).get_details(err_msg) - papi_tap_dump = papi_resp.reply[0]['api_reply'] + for dump in details: + # In-place edits. + process_vhost_dump(dump) - def process_tap_dump(tap_dump): - """Process tap dump. - - :param tap_dump: Tap interface dump. - :type tap_dump: dict - :returns: Processed tap interface dump. - :rtype: dict - """ - tap_dump['dev_name'] = tap_dump['dev_name'].rstrip('\x00') - tap_dump['host_if_name'] = tap_dump['host_if_name'].rstrip('\x00') - tap_dump['host_namespace'] = \ - tap_dump['host_namespace'].rstrip('\x00') - tap_dump['host_mac_addr'] = \ - L2Util.bin_to_mac(tap_dump['host_mac_addr']) - tap_dump['host_ip4_addr'] = \ - inet_ntop(AF_INET, tap_dump['host_ip4_addr']) - tap_dump['host_ip6_addr'] = \ - inet_ntop(AF_INET6, tap_dump['host_ip6_addr']) - return tap_dump - - data = list() if name is None else dict() - for item in papi_tap_dump: - 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]) - break - - logger.debug('TAP data:\n{tap_data}'.format(tap_data=data)) - return data + logger.debug('Vhost-user details:\n{vhost_details}'.format( + vhost_details=details)) + return details @staticmethod def create_subinterface(node, interface, sub_id, outer_vlan_id=None, @@ -978,33 +1016,42 @@ 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 PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + with PapiSocketExecutor(node) as papi_exec: + 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): @@ -1031,44 +1078,45 @@ class InterfaceUtil(object): tunnel=tunnel) 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) + with PapiSocketExecutor(node) as papi_exec: + 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): + def vpp_create_loopback(node, mac=None): """Create loopback interface on VPP node. :param node: Node to create loopback interface on. + :param mac: Optional MAC address for loopback interface. :type node: dict + :type mac: str :returns: SW interface index. :rtype: int :raises RuntimeError: If it is not possible to create loopback on the node. """ cmd = 'create_loopback' - args = dict(mac_address=0) + args = dict(mac_address=L2Util.mac_to_bin(mac) if mac else 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) + with PapiSocketExecutor(node) as papi_exec: + 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) + if mac: + mac = InterfaceUtil.vpp_get_interface_mac(node, ifc_name) + Topology.update_interface_mac_address(node, if_key, mac) - return sw_if_idx + return sw_if_index @staticmethod def vpp_create_bond_interface(node, mode, load_balance=None, mac=None): @@ -1089,49 +1137,51 @@ 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 PapiExecutor(node) as papi_exec: - papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + with PapiSocketExecutor(node) as papi_exec: + 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, - ifc_pfx='eth_bond') - if_key = Topology.get_interface_by_sw_index(node, 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_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 @@ -1139,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 @@ -1157,14 +1207,44 @@ class InterfaceUtil(object): txq_size=0) 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) + with PapiSocketExecutor(node) as papi_exec: + 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, - ifc_pfx='eth_avf') - if_key = Topology.get_interface_by_sw_index(node, 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_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 @@ -1185,62 +1265,54 @@ 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, host=node['host']) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + with PapiSocketExecutor(node) as papi_exec: + 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: + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd).get_details(err_msg) + + for bond in details: + 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: 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 @@ -1255,48 +1327,29 @@ 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'] - - 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 + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd, **args).get_details(err_msg) - data = list() - for item in papi_dump: - data.append(process_slave_dump(item[cmd_reply])) - - 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, @@ -1324,9 +1377,8 @@ class InterfaceUtil(object): is_add=1) 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) + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod def get_interface_classify_table(node, interface): @@ -1350,11 +1402,10 @@ class InterfaceUtil(object): args = dict(sw_if_index=sw_if_index) 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) + with PapiSocketExecutor(node) as papi_exec: + reply = papi_exec.add(cmd, **args).get_reply(err_msg) - return papi_resp + return reply @staticmethod def get_sw_if_index(node, interface_name): @@ -1385,22 +1436,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) - else: - 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'] - def process_vxlan_gpe_dump(vxlan_dump): """Process vxlan_gpe dump. @@ -1411,22 +1446,35 @@ class InterfaceUtil(object): """ if vxlan_dump['is_ipv6']: vxlan_dump['local'] = \ - inet_ntop(AF_INET6, vxlan_dump['local']) + ip_address(unicode(vxlan_dump['local'])) vxlan_dump['remote'] = \ - inet_ntop(AF_INET6, vxlan_dump['remote']) + ip_address(unicode(vxlan_dump['remote'])) else: vxlan_dump['local'] = \ - inet_ntop(AF_INET, vxlan_dump['local'][0:4]) + ip_address(unicode(vxlan_dump['local'][0:4])) vxlan_dump['remote'] = \ - inet_ntop(AF_INET, vxlan_dump['remote'][0:4]) + ip_address(unicode(vxlan_dump['remote'][0:4])) return vxlan_dump + if interface_name is not None: + sw_if_index = InterfaceUtil.get_interface_index( + node, interface_name) + else: + sw_if_index = int(Constants.BITWISE_NON_ZERO) + + cmd = 'vxlan_gpe_tunnel_dump' + args = dict(sw_if_index=sw_if_index) + err_msg = 'Failed to get VXLAN-GPE dump on host {host}'.format( + host=node['host']) + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd, **args).get_details(err_msg) + data = list() if interface_name is None else dict() - for item in papi_vxlan_dump: + for 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(dump)) + elif dump['sw_if_index'] == sw_if_index: + data = process_vxlan_gpe_dump(dump) break logger.debug('VXLAN-GPE data:\n{vxlan_gpe_data}'.format( @@ -1449,13 +1497,12 @@ 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) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg). \ - verify_reply(err_msg=err_msg) + with PapiSocketExecutor(node) as papi_exec: + papi_exec.add(cmd, **args).get_reply(err_msg) @staticmethod def set_linux_interface_mac(node, interface, mac, namespace=None, @@ -1527,12 +1574,12 @@ class InterfaceUtil(object): @staticmethod def init_avf_interface(node, ifc_key, numvfs=1, osi_layer='L2'): - """Init PCI device by creating VFs and bind them to vfio-pci for AVF + """Init PCI device by creating VIFs and bind them to vfio-pci for AVF driver testing on DUT. :param node: DUT node. :param ifc_key: Interface key from topology file. - :param numvfs: Number of VFs to initialize, 0 - disable the VFs. + :param numvfs: Number of VIFs to initialize, 0 - disable the VIFs. :param osi_layer: OSI Layer type to initialize TG with. Default value "L2" sets linux interface spoof off. :type node: dict @@ -1548,10 +1595,11 @@ class InterfaceUtil(object): 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": + if kernel_driver not in ("i40e", "i40evf"): raise RuntimeError( - "AVF needs i40e driver, not {driver} at node {host} ifc {ifc}"\ - .format(driver=kernel_driver, host=node["host"], ifc=ifc_key)) + "AVF needs i40e-compatible 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'\:')) @@ -1565,7 +1613,7 @@ class InterfaceUtil(object): # Bind to kernel driver. DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver) - # Initialize PCI VFs + # Initialize PCI VFs. DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs) vf_ifc_keys = [] @@ -1589,7 +1637,7 @@ class InterfaceUtil(object): 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_ifc_name = '{pf_if_key}_vif'.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, @@ -1600,283 +1648,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. @@ -1887,17 +1658,14 @@ class InterfaceUtil(object): :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: + with PapiSocketExecutor(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, @@ -1918,11 +1686,14 @@ 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) - with PapiExecutor(node) as papi_exec: - papi_exec.add(cmd, **args).get_replies(err_msg).\ - verify_reply(err_msg=err_msg) + 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) @staticmethod def vpp_round_robin_rx_placement(node, prefix): @@ -1936,6 +1707,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'] \