From ff78ad6f40a08f47edc55080f83d5955cc281763 Mon Sep 17 00:00:00 2001 From: Tibor Frank Date: Thu, 16 May 2019 13:47:50 +0200 Subject: [PATCH] VAT-to-PAPI: memif Change-Id: I9e3f1a2a2a1c11a355cd66c940beb663ecc7d7a4 Signed-off-by: Tibor Frank --- resources/libraries/python/Memif.py | 309 ++++++++++++--------------- resources/libraries/robot/shared/memif.robot | 10 +- 2 files changed, 140 insertions(+), 179 deletions(-) diff --git a/resources/libraries/python/Memif.py b/resources/libraries/python/Memif.py index 40178986d8..71c476fb9e 100644 --- a/resources/libraries/python/Memif.py +++ b/resources/libraries/python/Memif.py @@ -13,20 +13,117 @@ """Memif interface library.""" -from resources.libraries.python.ssh import SSH -from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal +import logging + +from enum import IntEnum + from resources.libraries.python.topology import NodeType, Topology +from resources.libraries.python.PapiExecutor import PapiExecutor +from resources.libraries.python.L2Util import L2Util + + +class MemifRole(IntEnum): + """Memif interface roles""" + MASTER = 0 + SLAVE = 1 class Memif(object): - """Memif interface class.""" + """Memif interface class""" def __init__(self): pass + @staticmethod + def _memif_dump(node): + """Get the memif dump on the given node. + + :param node: Given node to get Memif dump from. + :type node: dict + :returns: List of memif interfaces extracted from Papi response. + :rtype: list + """ + with PapiExecutor(node) as papi_exec: + dump = papi_exec.add("memif_dump").get_dump() + + data = list() + for item in dump.reply[0]["api_reply"]: + item["memif_details"]["if_name"] = \ + item["memif_details"]["if_name"].rstrip('\x00') + item["memif_details"]["hw_addr"] = \ + L2Util.bin_to_mac(item["memif_details"]["hw_addr"]) + data.append(item) + + logging.debug("MEMIF data:\n{data}".format(data=data)) + + return data + + @staticmethod + def _memif_socket_filename_add_del(node, is_add, filename, sid): + """Create Memif socket on the given node. + + :param node: Given node to create Memif socket on. + :param is_add: If True, socket is added, otherwise deleted. + :param filename: Memif interface socket filename. + :param sid: Socket ID. + :type node: dict + :type is_add: bool + :type filename: str + :type sid: str + :returns: Verified data from PAPI response. In this case, the response + includes only retval. + :rtype: dict + """ + cmd = 'memif_socket_filename_add_del' + err_msg = 'Failed to create memif socket on host {host}'.format( + host=node['host']) + args = dict( + is_add=int(is_add), + socket_id=int(sid), + socket_filename=str('/tmp/' + filename) + ) + with PapiExecutor(node) as papi_exec: + data = papi_exec.add(cmd, **args).get_replies(err_msg).\ + verify_reply(err_msg=err_msg) + return data + + @staticmethod + def _memif_create(node, mid, sid, rxq=1, txq=1, role=1): + """Create Memif interface on the given node. + + :param node: Given node to create Memif interface on. + :param mid: Memif interface ID. + :param sid: Socket ID. + :param rxq: Number of RX queues; 0 means do not set. + :param txq: Number of TX queues; 0 means do not set. + :param role: Memif interface role [master=0|slave=1]. Default is slave. + :type node: dict + :type mid: str + :type sid: str + :type rxq: int + :type txq: int + :type role: int + :returns: Verified data from PAPI response. + :rtype: dict + """ + cmd = 'memif_create' + err_msg = 'Failed to create memif interface on host {host}'.format( + host=node['host']) + args = dict( + role=role, + rx_queues=int(rxq), + tx_queues=int(txq), + socket_id=int(sid), + id=int(mid) + ) + with PapiExecutor(node) as papi_exec: + data = papi_exec.add(cmd, **args).get_replies(err_msg).\ + verify_reply(err_msg=err_msg) + return data + @staticmethod def create_memif_interface(node, filename, mid, sid, rxq=1, txq=1, - role='slave'): + role="SLAVE"): """Create Memif interface on the given node. :param node: Given node to create Memif interface on. @@ -35,7 +132,7 @@ class Memif(object): :param sid: Socket ID. :param rxq: Number of RX queues; 0 means do not set. :param txq: Number of TX queues; 0 means do not set. - :param role: Memif interface role [master|slave]. Default is master. + :param role: Memif interface role [master=0|slave=1]. Default is master. :type node: dict :type filename: str :type mid: str @@ -48,48 +145,29 @@ class Memif(object): :raises ValueError: If command 'create memif' fails. """ - rx_q = 'rx-queues {rxq}'.format(rxq=rxq) if rxq else '' - tx_q = 'tx-queues {txq}'.format(txq=txq) if txq else '' - - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template( - 'memif_socket_filename_add_del.vat', - add_del='add', id=sid, filename='/tmp/'+filename) - vat.vat_terminal_exec_cmd_from_template( - 'memif_create.vat', id=mid, socket=sid, rx_q=rx_q, tx_q=tx_q, - role=role) - if 'sw_if_index' in vat.vat_stdout: - try: - sw_if_idx = int(vat.vat_stdout.split()[4]) - if_key = Topology.add_new_port(node, 'memif') - Topology.update_interface_sw_if_index( - node, if_key, sw_if_idx) - ifc_name = Memif.vpp_get_memif_interface_name( - node, sw_if_idx) - Topology.update_interface_name(node, if_key, ifc_name) - ifc_mac = Memif.vpp_get_memif_interface_mac(node, sw_if_idx) - Topology.update_interface_mac_address(node, if_key, ifc_mac) - Topology.update_interface_memif_socket(node, if_key, - '/tmp/'+filename) - Topology.update_interface_memif_id(node, if_key, mid) - Topology.update_interface_memif_role(node, if_key, role) - return sw_if_idx - except KeyError: - raise ValueError('Create Memif interface failed on node ' - '{}'.format(node['host'])) - else: - raise ValueError('Create Memif interface failed on node ' - '{}'.format(node['host'])) + role = getattr(MemifRole, role.upper()).value - @staticmethod - def dump_memif(node): - """Dump Memif data for the given node. + # Create socket + Memif._memif_socket_filename_add_del(node, True, filename, sid) - :param node: Given node to show Memif data on. - :type node: dict - """ - vat = VatExecutor() - vat.execute_script("memif_dump.vat", node, json_out=False) + # Create memif + rsp = Memif._memif_create(node, mid, sid, rxq=rxq, txq=txq, role=role) + + # Update Topology + if_key = Topology.add_new_port(node, 'memif') + Topology.update_interface_sw_if_index(node, if_key, rsp["sw_if_index"]) + + ifc_name = Memif.vpp_get_memif_interface_name(node, rsp["sw_if_index"]) + Topology.update_interface_name(node, if_key, ifc_name) + + ifc_mac = Memif.vpp_get_memif_interface_mac(node, rsp["sw_if_index"]) + Topology.update_interface_mac_address(node, if_key, ifc_mac) + + Topology.update_interface_memif_socket(node, if_key, '/tmp/' + filename) + Topology.update_interface_memif_id(node, if_key, mid) + Topology.update_interface_memif_role(node, if_key, str(role)) + + return rsp["sw_if_index"] @staticmethod def show_memif(node): @@ -98,8 +176,8 @@ class Memif(object): :param node: Given node to show Memif data on. :type node: dict """ - vat = VatExecutor() - vat.execute_script("show_memif.vat", node, json_out=False) + + Memif._memif_dump(node) @staticmethod def show_memif_on_all_duts(nodes): @@ -112,66 +190,6 @@ class Memif(object): if node['type'] == NodeType.DUT: Memif.show_memif(node) - @staticmethod - def clear_memif_socks(node, *socks): - """Clear Memif sockets for the given node. - - :param node: Given node to clear Memif sockets on. - :param socks: Memif sockets. - :type node: dict - :type socks: list - """ - ssh = SSH() - ssh.connect(node) - - for sock in socks: - ssh.exec_command_sudo('rm -f {}'.format(sock)) - - @staticmethod - def parse_memif_dump_data(memif_data): - """Convert Memif data to dictionary. - - :param memif_data: Dump of Memif interfaces data. - :type memif_data: str - :returns: Memif interfaces data in dictionary. - :rtype: dict - :raises RuntimeError: If there is no memif interface name found in - provided data. - """ - memif_name = None - memif_dict = dict() - memif_data = str(memif_data) - values = dict() - - clutter = ['vat#'] - for garbage in clutter: - memif_data = memif_data.replace(garbage, '') - - for line in memif_data.splitlines(): - if not line or line.startswith('Sending'): - continue - elif line.startswith('memif'): - if memif_name: - memif_dict[memif_name] = values - line_split = line.split(':', 1) - memif_name = str(line_split[0]) - values = dict() - line = line_split[1] - line_split = line.split() - for i in range(0, len(line_split), 2): - key = str(line_split[i]) - try: - value = line_split[i+1] - except IndexError: - value = None - values[key] = value - if memif_name: - memif_dict[memif_name] = values - else: - raise RuntimeError('No memif interface name found') - - return memif_dict - @staticmethod def vpp_get_memif_interface_name(node, sw_if_idx): """Get Memif interface name from Memif interfaces dump. @@ -183,12 +201,12 @@ class Memif(object): :returns: Memif interface name, or None if not found. :rtype: str """ - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template('memif_dump.vat') - memif_data = Memif.parse_memif_dump_data(vat.vat_stdout) - for item in memif_data: - if memif_data[item]['sw_if_index'] == str(sw_if_idx): - return item + + dump = Memif._memif_dump(node) + + for item in dump: + if item["memif_details"]["sw_if_index"] == sw_if_idx: + return item["memif_details"]["if_name"] return None @staticmethod @@ -202,67 +220,10 @@ class Memif(object): :returns: Memif interface MAC address, or None if not found. :rtype: str """ - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template('memif_dump.vat') - memif_data = Memif.parse_memif_dump_data(vat.vat_stdout) - for item in memif_data: - if memif_data[item]['sw_if_index'] == str(sw_if_idx): - return memif_data[item].get('mac', None) - return None - - @staticmethod - def vpp_get_memif_interface_socket(node, sw_if_idx): - """Get Memif interface socket path from Memif interfaces dump. - - :param node: DUT node. - :param sw_if_idx: DUT node. - :type node: dict - :type sw_if_idx: int - :returns: Memif interface socket path, or None if not found. - :rtype: str - """ - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template('memif_dump.vat') - memif_data = Memif.parse_memif_dump_data(vat.vat_stdout) - for item in memif_data: - if memif_data[item]['sw_if_index'] == str(sw_if_idx): - return memif_data[item].get('socket', None) - return None - - @staticmethod - def vpp_get_memif_interface_id(node, sw_if_idx): - """Get Memif interface ID from Memif interfaces dump. - - :param node: DUT node. - :param sw_if_idx: DUT node. - :type node: dict - :type sw_if_idx: int - :returns: Memif interface ID, or None if not found. - :rtype: int - """ - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template('memif_dump.vat') - memif_data = Memif.parse_memif_dump_data(vat.vat_stdout) - for item in memif_data: - if memif_data[item]['sw_if_index'] == str(sw_if_idx): - return int(memif_data[item].get('id', None)) - return None - @staticmethod - def vpp_get_memif_interface_role(node, sw_if_idx): - """Get Memif interface role from Memif interfaces dump. + dump = Memif._memif_dump(node) - :param node: DUT node. - :param sw_if_idx: DUT node. - :type node: dict - :type sw_if_idx: int - :returns: Memif interface role, or None if not found. - :rtype: int - """ - with VatTerminal(node, json_param=False) as vat: - vat.vat_terminal_exec_cmd_from_template('memif_dump.vat') - memif_data = Memif.parse_memif_dump_data(vat.vat_stdout) - for item in memif_data: - if memif_data[item]['sw_if_index'] == str(sw_if_idx): - return memif_data[item].get('role', None) + for item in dump: + if item["memif_details"]["sw_if_index"] == sw_if_idx: + return item["memif_details"]["hw_addr"] return None diff --git a/resources/libraries/robot/shared/memif.robot b/resources/libraries/robot/shared/memif.robot index 482a4cf77b..0b092c2f6a 100644 --- a/resources/libraries/robot/shared/memif.robot +++ b/resources/libraries/robot/shared/memif.robot @@ -33,7 +33,7 @@ | | ... | default value: ${1} | | ... | - txq - TX queues; 0 means do not set (Optional). Type: integer, | | ... | default value: ${1} -| | ... | - role - Memif role (Optional). Type: string, default value: slave +| | ... | - role - Memif role (Optional). Type: string, default value: SLAVE | | ... | - dcr_uuid - UUID string (including prefix - underscore character) of | | ... | DUT1 /tmp volume created outside of the DUT1 docker in case of | | ... | vpp-device test. ${EMPTY} value means that /tmp directory is inside @@ -49,13 +49,13 @@ | | ... | \| ${nodes['DUT1']} \| sock1 \| sock2 \| 1 \| | | ... | \| Set up memif interfaces on DUT node \ | | ... | \| ${nodes['DUT2']} \| sock1 \| sock2 \| 1 \ -| | ... | \| dut2_memif_if1 \| dut2_memif_if2 \| 1 \| 1 \| slave \| +| | ... | \| dut2_memif_if1 \| dut2_memif_if2 \| 1 \| 1 \| SLAVE \| | | ... | \| ${nodes['DUT2']} \| sock1 \| sock2 \| 1 \| rxq=0 \| txq=0 \ | | ... | \| dcr_uuid=_a5730a0a-2ba1-4fe9-91bd-79b9828e968e \| | | ... | | [Arguments] | ${dut_node} | ${filename1} | ${filename2} | ${mid}=${1} | | ... | ${memif_if1}=memif_if1 | ${memif_if2}=memif_if2 | ${rxq}=${1} -| | ... | ${txq}=${1} | ${role}=slave | ${dcr_uuid}=${EMPTY} +| | ... | ${txq}=${1} | ${role}=SLAVE | ${dcr_uuid}=${EMPTY} | | ... | | ${sid_1}= | Evaluate | (${mid}*2)-1 | | ${sid_2}= | Evaluate | (${mid}*2) @@ -91,10 +91,10 @@ | | ... | | ... | \| Set up single memif interface on DUT node \ | | ... | \| ${nodes['DUT1']} \| sock1 \| 1 \| dut1_memif_if1 \| 1 \| 1 \ -| | ... | \| slave \| +| | ... | \| SLAVE \| | | ... | | [Arguments] | ${dut_node} | ${filename} | ${mid}=${1} | ${sid}=${1} -| | ... | ${memif_if}=memif_if1 | ${rxq}=${1} | ${txq}=${1} | ${role}=slave +| | ... | ${memif_if}=memif_if1 | ${rxq}=${1} | ${txq}=${1} | ${role}=SLAVE | | ... | | ${memif}= | Create memif interface | ${dut_node} | ${filename}${mid}-${sid} | | ... | ${mid} | ${sid} | rxq=${rxq} | txq=${txq} | role=${role} -- 2.16.6