aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/Memif.py
blob: 2128d30428bd8451b85efdb820deceeb2d093c41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } 
# Copyright (c) 2019 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:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Memif interface library."""


from enum import IntEnum

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 _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 filename: Memif interface socket filename.
        :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 master.
        :type node: dict
        :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)

        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):
        """Show Memif data for the given node.

        :param node: Given node to show Memif data on.
        :type node: dict
        """
        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 vpp_get_memif_interface_mac(node, sw_if_index):
        """Get Memif interface MAC address 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 MAC address, 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"hw_addr"]
        return None
">_ls_name = ls_name self._key_id = key_id self._key = key @property def ls_name(self): return self._ls_name @property def key_id(self): return self._key_id @property def key(self): return self._key def add_vpp_config(self): self.test.vapi.lisp_local_mapping( ls_name=self._ls_name, eid_type=self._eid.eid_type, eid=str(self._eid), prefix_len=self._eid.prefix_length, vni=self._vni, key_id=self._key_id, key=self._key) self._test.registry.register(self, self.test.logger) def remove_vpp_config(self): self.test.vapi.lisp_local_mapping( ls_name=self._ls_name, eid_type=self._eid.eid_type, eid=str(self._eid), prefix_len=self._eid.prefix_length, vni=self._vni, is_add=0) def object_id(self): return 'lisp-eid-local-mapping-%s[%d]' % (self._eid, self._vni) class VppRemoteMapping(VppLispMapping): def __init__(self, test, eid, rlocs=None, vni=0, priority=1, weight=1): super(VppRemoteMapping, self).__init__(test, eid, vni, priority, weight) self._rlocs = rlocs @property def rlocs(self): return self._rlocs def add_vpp_config(self): self.test.vapi.lisp_remote_mapping( rlocs=self._rlocs, eid_type=self._eid.eid_type, eid=str(self._eid), eid_prefix_len=self._eid.prefix_length, vni=self._vni, rlocs_num=len(self._rlocs)) self._test.registry.register(self, self.test.logger) def remove_vpp_config(self): self.test.vapi.lisp_remote_mapping( eid_type=self._eid.eid_type, eid=str(self._eid), eid_prefix_len=self._eid.prefix_length, vni=self._vni, is_add=0, rlocs_num=0) def object_id(self): return 'lisp-eid-remote-mapping-%s[%d]' % (self._eid, self._vni) class VppLispAdjacency(VppObject): """ Represents LISP adjacency in VPP """ def __init__(self, test, leid, reid, vni=0): self._leid = LispEID(leid) self._reid = LispEID(reid) if self._leid.eid_type != self._reid.eid_type: raise Exception('remote and local EID are different types!') self._vni = vni self._test = test @property def test(self): return self._test @property def leid(self): return self._leid @property def reid(self): return self._reid @property def vni(self): return self._vni def add_vpp_config(self): self.test.vapi.lisp_adjacency( leid=str(self._leid), reid=str(self._reid), eid_type=self._leid.eid_type, leid_len=self._leid.prefix_length, reid_len=self._reid.prefix_length, vni=self._vni) self._test.registry.register(self, self.test.logger) def eid_equal(self, eid, eid_type, eid_data, prefix_len): if eid.eid_type != eid_type: return False if eid_type == LispEIDType.IP4 or eid_type == LispEIDType.IP6: if eid.prefix_length != prefix_len: return False if str(eid) != eid_data[0:eid.data_length]: return False return True def query_vpp_config(self): res = self.test.vapi.lisp_adjacencies_get(vni=self._vni) for adj in res.adjacencies: if self.eid_equal(self._leid, adj.eid_type, adj.leid, adj.leid_prefix_len) and \ self.eid_equal(self._reid, adj.eid_type, adj.reid, adj.reid_prefix_len): return True return False def remove_vpp_config(self): self.test.vapi.lisp_adjacency( leid=str(self._leid), reid=str(self._reid), eid_type=self._leid.eid_type, leid_len=self._leid.prefix_length, reid_len=self._reid.prefix_length, vni=self._vni, is_add=0) def object_id(self): return 'lisp-adjacency-%s-%s[%d]' % (self._leid, self._reid, self._vni)