-# Copyright (c) 2017 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
"""Memif interface library."""
-from resources.libraries.python.ssh import SSH
-from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
+from enum import IntEnum
-class Memif(object):
- """Memif interface class."""
+from robot.api import logger
+
+from resources.libraries.python.topology import NodeType, Topology
+from resources.libraries.python.PapiExecutor import PapiSocketExecutor
+
+
+class MemifRole(IntEnum):
+ """Memif interface roles"""
+ MASTER = 0
+ SLAVE = 1
+
+
+class Memif:
+ """Memif interface class"""
def __init__(self):
pass
@staticmethod
- def create_memif_interface(node, socket, mid, role="master"):
+ def _memif_details(node):
+ """Get the memif dump details 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
+ """
+ cmd = u"memif_dump"
+ with PapiSocketExecutor(node) as papi_exec:
+ details = papi_exec.add(cmd).get_details()
+
+ for memif in details:
+ memif[u"hw_addr"] = str(memif[u"hw_addr"])
+ memif[u"role"] = memif[u"role"].value
+ memif[u"mode"] = memif[u"mode"].value
+ memif[u"flags"] = memif[u"flags"].value \
+ if hasattr(memif[u"flags"], u"value") else int(memif[u"flags"])
+
+ logger.debug(f"MEMIF details:\n{details}")
+
+ return details
+
+ @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 = u"memif_socket_filename_add_del"
+ err_msg = f"Failed to create memif socket on host {node[u'host']}"
+ args = dict(
+ is_add=is_add,
+ socket_id=int(sid),
+ socket_filename=str(u"/tmp/" + filename)
+ )
+ with PapiSocketExecutor(node) as papi_exec:
+ return papi_exec.add(cmd, **args).get_reply(err_msg)
+
+ @staticmethod
+ def _memif_create(node, mid, sid, rxq=1, txq=1, role=1):
+ """Create Memif interface on the given node, return its sw_if_index.
+
+ :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: sw_if_index
+ :rtype: int
+ """
+ cmd = u"memif_create"
+ err_msg = f"Failed to create memif interface on host {node[u'host']}"
+ args = dict(
+ role=role,
+ rx_queues=int(rxq),
+ tx_queues=int(txq),
+ socket_id=int(sid),
+ id=int(mid),
+ secret=u""
+ )
+
+ with PapiSocketExecutor(node) as papi_exec:
+ return papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
+
+ @staticmethod
+ def create_memif_interface(
+ node, filename, mid, sid, rxq=1, txq=1, role=u"SLAVE"):
"""Create Memif interface on the given node.
:param node: Given node to create Memif interface on.
- :param socket: Memif interface socket path.
+ :param filename: Memif interface socket filename.
:param mid: Memif interface ID.
- :param role: Memif interface role [master|slave]. Default is master.
+ :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 master.
:type node: dict
- :type socket: str
+ :type filename: str
:type mid: str
+ :type sid: str
+ :type rxq: int
+ :type txq: int
:type role: str
:returns: SW interface index.
:rtype: int
:raises ValueError: If command 'create memif' fails.
"""
+ role = getattr(MemifRole, role.upper()).value
+
+ # Create socket
+ Memif._memif_socket_filename_add_del(node, True, filename, sid)
+
+ # Create memif
+ sw_if_index = Memif._memif_create(
+ node, mid, sid, rxq=rxq, txq=txq, role=role
+ )
+
+ # Update Topology
+ if_key = Topology.add_new_port(node, u"memif")
+ Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
+
+ ifc_name = Memif.vpp_get_memif_interface_name(node, sw_if_index)
+ Topology.update_interface_name(node, if_key, ifc_name)
+
+ ifc_mac = Memif.vpp_get_memif_interface_mac(node, sw_if_index)
+ Topology.update_interface_mac_address(node, if_key, ifc_mac)
- with VatTerminal(node, json_param=False) as vat:
- vat.vat_terminal_exec_cmd_from_template(
- 'memif_create.vat',
- socket=socket, id=mid, role=role)
- if 'sw_if_index' in vat.vat_stdout:
- try:
- return int(vat.vat_stdout.split()[4])
- 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']))
+ Topology.update_interface_memif_socket(
+ node, if_key, u"/tmp/" + filename
+ )
+ Topology.update_interface_memif_id(node, if_key, mid)
+ Topology.update_interface_memif_role(node, if_key, str(role))
+
+ return sw_if_index
@staticmethod
def show_memif(node):
:param node: Given node to show Memif data on.
:type node: dict
"""
- vat = VatExecutor()
- vat.execute_script("memif_dump.vat", node, json_out=False)
+ Memif._memif_details(node)
+
+ @staticmethod
+ def show_memif_on_all_duts(nodes):
+ """Show Memif data on all DUTs.
+
+ :param nodes: Topology nodes.
+ :type nodes: dict
+ """
+ for node in nodes.values():
+ if node[u"type"] == NodeType.DUT:
+ Memif.show_memif(node)
+
+ @staticmethod
+ def vpp_get_memif_interface_name(node, sw_if_index):
+ """Get Memif interface name from Memif interfaces dump.
+
+ :param node: DUT node.
+ :param sw_if_index: DUT node.
+ :type node: dict
+ :type sw_if_index: int
+ :returns: Memif interface name, or None if not found.
+ :rtype: str
+ """
+ details = Memif._memif_details(node)
+
+ for memif in details:
+ if memif[u"sw_if_index"] == sw_if_index:
+ return memif[u"if_name"]
+ return None
@staticmethod
- def clear_memif_socks(node, *socks):
- """Clear Memif sockets for the given node.
+ def vpp_get_memif_interface_mac(node, sw_if_index):
+ """Get Memif interface MAC address from Memif interfaces dump.
- :param node: Given node to clear Memif sockets on.
- :param socks: Memif sockets.
+ :param node: DUT node.
+ :param sw_if_index: DUT node.
:type node: dict
- :type socks: list
+ :type sw_if_index: int
+ :returns: Memif interface MAC address, or None if not found.
+ :rtype: str
"""
- ssh = SSH()
- ssh.connect(node)
+ details = Memif._memif_details(node)
- for sock in socks:
- ssh.exec_command_sudo('rm -f {}'.format(sock))
+ for memif in details:
+ if memif[u"sw_if_index"] == sw_if_index:
+ return memif[u"hw_addr"]
+ return None