From fb2fb651fa600a94c2e02891db2676c66490e875 Mon Sep 17 00:00:00 2001 From: Jan Gelety Date: Fri, 12 Jul 2019 14:53:24 +0200 Subject: [PATCH] CSIT-1473: Migrate Tap library from VAT to PAPI Change-Id: Ibf4a4839c2e8b799b03eebd9dffae891d8f00dd4 Signed-off-by: Jan Gelety --- resources/api/vpp/supported_crcs.yaml | 4 + resources/libraries/python/InterfaceUtil.py | 211 +++++++++++----------------- resources/libraries/python/Tap.py | 209 ++++++++++++--------------- 3 files changed, 174 insertions(+), 250 deletions(-) diff --git a/resources/api/vpp/supported_crcs.yaml b/resources/api/vpp/supported_crcs.yaml index d0c7cc7463..677efd9d98 100644 --- a/resources/api/vpp/supported_crcs.yaml +++ b/resources/api/vpp/supported_crcs.yaml @@ -174,8 +174,12 @@ sw_interface_set_table_reply: '0xe8d4e804' # dev sw_interface_set_vxlan_bypass: '0xe74ca095' # dev sw_interface_set_vxlan_bypass_reply: '0xe8d4e804' # dev + sw_interface_tap_v2_dump: '0x51077d14' # dev + sw_interface_tap_v2_details: '0x5ee87a5f' # dev sw_interface_vhost_user_details: '0x91ff3307' # dev sw_interface_vhost_user_dump: '0x51077d14' # dev + tap_create_v2: '0x8fa99320' # dev + tap_create_v2_reply: '0xfda5941f' # dev vxlan_add_del_tunnel: '0x00f4bdd0' # virl vxlan_add_del_tunnel_reply: '0xfda5941f' # virl vxlan_tunnel_details: '0xce38e127' # virl diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 34ccd7cadc..7024e85dc8 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -13,7 +13,6 @@ """Interface util library.""" -from socket import AF_INET, AF_INET6, inet_ntop from time import sleep from enum import IntEnum @@ -305,6 +304,21 @@ 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['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 + if interface is not None: if isinstance(interface, basestring): param = 'interface_name' @@ -324,27 +338,12 @@ class InterfaceUtil(object): with PapiSocketExecutor(node) as papi_exec: details = papi_exec.add(cmd, **args).get_details(err_msg) - 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 - data = list() if interface is None else dict() - for if_dump in details: + for dump in details: if interface is None: - data.append(process_if_dump(if_dump)) - elif str(if_dump.get(param)).rstrip('\x00') == str(interface): - data = process_if_dump(if_dump) + 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)) @@ -823,18 +822,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' - 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) - def process_vxlan_dump(vxlan_dump): """Process vxlan dump. @@ -845,22 +832,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 vxlan_dump in details: + for dump in details: if interface is None: - data.append(process_vxlan_dump(vxlan_dump)) - elif vxlan_dump['sw_if_index'] == sw_if_index: - data = process_vxlan_dump(vxlan_dump) + 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)) @@ -877,12 +876,6 @@ class InterfaceUtil(object): :returns: List of dictionaries with all vhost-user interfaces. :rtype: list """ - cmd = 'sw_interface_vhost_user_dump' - err_msg = 'Failed to get vhost-user dump on host {host}'.format( - host=node['host']) - with PapiSocketExecutor(node) as papi_exec: - details = papi_exec.add(cmd).get_details(err_msg) - def process_vhost_dump(vhost_dump): """Process vhost dump. @@ -897,65 +890,19 @@ class InterfaceUtil(object): vhost_dump['sock_filename'].rstrip('\x00') return vhost_dump - for vhost_dump in details: - # In-place edits. - process_vhost_dump(vhost_dump) - - logger.debug('Vhost-user details:\n{vhost_details}'.format( - vhost_details=details)) - return details - - @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' - 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 PapiSocketExecutor(node) as papi_exec: details = papi_exec.add(cmd).get_details(err_msg) - 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 tap_dump in details: - if name is None: - data.append(process_tap_dump(tap_dump)) - elif tap_dump.get('dev_name').rstrip('\x00') == name: - data = process_tap_dump(tap_dump) - break + for dump in details: + # In-place edits. + process_vhost_dump(dump) - 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, @@ -1246,15 +1193,6 @@ class InterfaceUtil(object): :returns: Bond slave interface data. :rtype: dict """ - cmd = 'sw_interface_slave_dump' - 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 PapiSocketExecutor(node) as papi_exec: - details = papi_exec.add(cmd, **args).get_details(err_msg) - def process_slave_dump(slave_dump): """Process slave dump. @@ -1267,9 +1205,18 @@ class InterfaceUtil(object): rstrip('\x00') return slave_dump - for slave_dump in details: + cmd = 'sw_interface_slave_dump' + 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 PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd, **args).get_details(err_msg) + + for dump in details: # In-place edits. - process_slave_dump(slave_dump) + process_slave_dump(dump) logger.debug('Slave data:\n{slave_data}'.format(slave_data=details)) return details @@ -1372,19 +1319,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' - 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) - def process_vxlan_gpe_dump(vxlan_dump): """Process vxlan_gpe dump. @@ -1395,22 +1329,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 vxlan_dump in details: + for dump in details: if interface_name is None: - data.append(process_vxlan_gpe_dump(vxlan_dump)) - elif vxlan_dump['sw_if_index'] == sw_if_index: - data = process_vxlan_gpe_dump(vxlan_dump) + 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( diff --git a/resources/libraries/python/Tap.py b/resources/libraries/python/Tap.py index 2a1d7efbc8..103eeffd9e 100644 --- a/resources/libraries/python/Tap.py +++ b/resources/libraries/python/Tap.py @@ -13,8 +13,13 @@ """Tap utilities library.""" -from resources.libraries.python.VatExecutor import VatTerminal +from ipaddress import ip_address +from robot.api import logger + +from resources.libraries.python.Constants import Constants +from resources.libraries.python.L2Util import L2Util from resources.libraries.python.InterfaceUtil import InterfaceUtil +from resources.libraries.python.PapiExecutor import PapiSocketExecutor from resources.libraries.python.topology import Topology @@ -29,147 +34,115 @@ class Tap(object): :param tap_name: Tap interface name for linux tap. :param mac: Optional MAC address for VPP tap. :type node: dict - :type tap_name: str + :type tap_name: str or unicode :type mac: str :returns: Returns a interface index. :rtype: int """ - command = 'create' - if mac is not None: - args = 'tapname {} mac {}'.format(tap_name, mac) - else: - args = 'tapname {}'.format(tap_name) - with VatTerminal(node) as vat: - resp = vat.vat_terminal_exec_cmd_from_template('tap.vat', - tap_command=command, - tap_arguments=args) - sw_if_index = resp[0]['sw_if_index'] + if isinstance(tap_name, unicode): + tap_name = str(tap_name) + cmd = 'tap_create_v2' + args = dict( + id=Constants.BITWISE_NON_ZERO, + use_random_mac=0 if mac else 1, + mac_address=L2Util.mac_to_bin(mac) if mac else 6 * b'\x00', + host_namespace=64 * b'\x00', + host_mac_addr=6 * b'\x00', + host_if_name_set=1, + host_if_name=tap_name + (64 - len(tap_name)) * b'\x00', + host_bridge=64 * b'\x00', + host_ip4_addr=4 * b'\x00', + host_ip6_addr=16 * b'\x00', + host_ip4_gw=4 * b'\x00', + host_ip6_gw=16 * b'\x00' + ) + err_msg = 'Failed to create tap interface {tap} on host {host}'.format( + tap=tap_name, host=node['host']) + + with PapiSocketExecutor(node) as papi_exec: + sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg) + if_key = Topology.add_new_port(node, 'tap') Topology.update_interface_sw_if_index(node, if_key, sw_if_index) - ifc_name = Tap.vpp_get_tap_interface_name(node, sw_if_index) - Topology.update_interface_name(node, if_key, ifc_name) + Topology.update_interface_name(node, if_key, tap_name) if mac is None: - mac = Tap.vpp_get_tap_interface_mac(node, sw_if_index) + mac = Tap.vpp_get_tap_interface_mac(node, tap_name) Topology.update_interface_mac_address(node, if_key, mac) - Topology.update_interface_tap_dev_name(node, if_key, tap_name) + tap_dev_name = Tap.vpp_get_tap_dev_name(node, tap_name) + Topology.update_interface_tap_dev_name(node, if_key, tap_dev_name) return sw_if_index @staticmethod - def modify_tap_interface(node, sw_if_index, tap_name, mac=None): - """Modify tap interface like linux interface name or VPP MAC. - - :param node: Node to modify tap on. - :param sw_if_index: Index of tap interface to be modified. - :param tap_name: Tap interface name for linux tap. - :param mac: Optional MAC address for VPP tap. - :type node: dict - :type sw_if_index: int - :type tap_name: str - :type mac: str - :returns: Returns a interface index. - :rtype: int - """ - command = 'modify' - if mac is not None: - args = 'sw_if_index {} tapname {} mac {}'.format( - sw_if_index, tap_name, mac) - else: - args = 'sw_if_index {} tapname {}'.format(sw_if_index, tap_name) - with VatTerminal(node) as vat: - resp = vat.vat_terminal_exec_cmd_from_template('tap.vat', - tap_command=command, - tap_arguments=args) - if_key = Topology.get_interface_by_sw_index(node, sw_if_index) - Topology.update_interface_tap_dev_name(node, if_key, tap_name) - if mac: - Topology.update_interface_mac_address(node, if_key, mac) - - return resp[0]['sw_if_index'] - - @staticmethod - def delete_tap_interface(node, sw_if_index): - """Delete tap interface. - - :param node: Node to delete tap on. - :param sw_if_index: Index of tap interface to be deleted. - :type node: dict - :type sw_if_index: int - :raises RuntimeError: Deletion was not successful. - """ - command = 'delete' - args = 'sw_if_index {}'.format(sw_if_index) - with VatTerminal(node) as vat: - resp = vat.vat_terminal_exec_cmd_from_template('tap.vat', - tap_command=command, - tap_arguments=args) - if int(resp[0]['retval']) != 0: - raise RuntimeError( - 'Could not remove tap interface: {}'.format(resp)) - if_key = Topology.get_interface_sw_index(node, sw_if_index) - Topology.remove_port(node, if_key) - - @staticmethod - def check_tap_present(node, tap_name): - """Check whether specific tap interface exists. + def vpp_get_tap_dev_name(node, host_if_name): + """Get VPP tap interface name from hardware interfaces dump. - :param node: Node to check tap on. - :param tap_name: Tap interface name for linux tap. + :param node: DUT node. + :param host_if_name: Tap host interface name. :type node: dict - :type tap_name: str - :raises RuntimeError: Specified interface was not found. + :type host_if_name: str + :returns: VPP tap interface dev_name. + :rtype: str """ - tap_if = InterfaceUtil.tap_dump(node, tap_name) - if not tap_if: - raise RuntimeError( - 'Tap interface :{} does not exist'.format(tap_name)) + return Tap.tap_dump(node, host_if_name).get('dev_name') @staticmethod - def vpp_get_tap_interface_name(node, sw_if_index): - """Get VPP tap interface name from hardware interfaces dump. + def vpp_get_tap_interface_mac(node, interface_name): + """Get tap interface MAC address from interfaces dump. :param node: DUT node. - :param sw_if_index: DUT node. + :param interface_name: Tap interface name. :type node: dict - :type sw_if_index: int - :returns: VPP tap interface name. + :type interface_name: str + :returns: Tap interface MAC address. :rtype: str """ - with VatTerminal(node, json_param=False) as vat: - response = vat.vat_terminal_exec_cmd_from_template( - 'show_hardware_detail.vat') - - for line in str(response[0]).splitlines(): - if line.startswith('tap-'): - line_split = line.split() - if line_split[1] == sw_if_index: - return line_split[0] - - return None + return InterfaceUtil.vpp_get_interface_mac(node, interface_name) @staticmethod - def vpp_get_tap_interface_mac(node, sw_if_index): - """Get tap interface MAC address from hardware interfaces dump. + def tap_dump(node, name=None): + """Get all TAP interface data from the given node, or data about + a specific TAP interface. - :param node: DUT node. - :param sw_if_index: DUT node. + :param node: VPP node to get data from. + :param name: Optional name of a specific TAP interface. :type node: dict - :type sw_if_index: int - :returns: Tap interface MAC address. - :rtype: str + :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 """ - with VatTerminal(node, json_param=False) as vat: - response = vat.vat_terminal_exec_cmd_from_template( - 'show_hardware_detail.vat') - - tap_if_match = False - for line in str(response[0]).splitlines(): - if tap_if_match: - line_split = line.split() - return line_split[-1] - if line.startswith('tap-'): - line_split = line.split() - if line_split[1] == sw_if_index: - tap_if_match = True - - return None + 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'] = ip_address(tap_dump['host_ip4_addr']) + tap_dump['host_ip6_addr'] = ip_address(tap_dump['host_ip6_addr']) + return tap_dump + + cmd = 'sw_interface_tap_v2_dump' + err_msg = 'Failed to get TAP dump on host {host}'.format( + host=node['host']) + with PapiSocketExecutor(node) as papi_exec: + details = papi_exec.add(cmd).get_details(err_msg) + + data = list() if name is None else dict() + for dump in details: + if name is None: + data.append(process_tap_dump(dump)) + elif dump.get('host_if_name').rstrip('\x00') == name: + data = process_tap_dump(dump) + break + + logger.debug('TAP data:\n{tap_data}'.format(tap_data=data)) + return data -- 2.16.6