VAT-to-PAPI: memif
[csit.git] / resources / libraries / python / Memif.py
1 # Copyright (c) 2019 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Memif interface library."""
15
16 import logging
17
18 from enum import IntEnum
19
20 from resources.libraries.python.topology import NodeType, Topology
21 from resources.libraries.python.PapiExecutor import PapiExecutor
22 from resources.libraries.python.L2Util import L2Util
23
24
25 class MemifRole(IntEnum):
26     """Memif interface roles"""
27     MASTER = 0
28     SLAVE = 1
29
30
31 class Memif(object):
32     """Memif interface class"""
33
34     def __init__(self):
35         pass
36
37     @staticmethod
38     def _memif_dump(node):
39         """Get the memif dump on the given node.
40
41         :param node: Given node to get Memif dump from.
42         :type node: dict
43         :returns: List of memif interfaces extracted from Papi response.
44         :rtype: list
45         """
46         with PapiExecutor(node) as papi_exec:
47             dump = papi_exec.add("memif_dump").get_dump()
48
49         data = list()
50         for item in dump.reply[0]["api_reply"]:
51             item["memif_details"]["if_name"] = \
52                 item["memif_details"]["if_name"].rstrip('\x00')
53             item["memif_details"]["hw_addr"] = \
54                 L2Util.bin_to_mac(item["memif_details"]["hw_addr"])
55             data.append(item)
56
57         logging.debug("MEMIF data:\n{data}".format(data=data))
58
59         return data
60
61     @staticmethod
62     def _memif_socket_filename_add_del(node, is_add, filename, sid):
63         """Create Memif socket on the given node.
64
65         :param node: Given node to create Memif socket on.
66         :param is_add: If True, socket is added, otherwise deleted.
67         :param filename: Memif interface socket filename.
68         :param sid: Socket ID.
69         :type node: dict
70         :type is_add: bool
71         :type filename: str
72         :type sid: str
73         :returns: Verified data from PAPI response. In this case, the response
74             includes only retval.
75         :rtype: dict
76         """
77         cmd = 'memif_socket_filename_add_del'
78         err_msg = 'Failed to create memif socket on host {host}'.format(
79             host=node['host'])
80         args = dict(
81             is_add=int(is_add),
82             socket_id=int(sid),
83             socket_filename=str('/tmp/' + filename)
84         )
85         with PapiExecutor(node) as papi_exec:
86             data = papi_exec.add(cmd, **args).get_replies(err_msg).\
87                 verify_reply(err_msg=err_msg)
88         return data
89
90     @staticmethod
91     def _memif_create(node, mid, sid, rxq=1, txq=1, role=1):
92         """Create Memif interface on the given node.
93
94         :param node: Given node to create Memif interface on.
95         :param mid: Memif interface ID.
96         :param sid: Socket ID.
97         :param rxq: Number of RX queues; 0 means do not set.
98         :param txq: Number of TX queues; 0 means do not set.
99         :param role: Memif interface role [master=0|slave=1]. Default is slave.
100         :type node: dict
101         :type mid: str
102         :type sid: str
103         :type rxq: int
104         :type txq: int
105         :type role: int
106         :returns: Verified data from PAPI response.
107         :rtype: dict
108         """
109         cmd = 'memif_create'
110         err_msg = 'Failed to create memif interface on host {host}'.format(
111             host=node['host'])
112         args = dict(
113             role=role,
114             rx_queues=int(rxq),
115             tx_queues=int(txq),
116             socket_id=int(sid),
117             id=int(mid)
118         )
119         with PapiExecutor(node) as papi_exec:
120             data = papi_exec.add(cmd, **args).get_replies(err_msg).\
121                 verify_reply(err_msg=err_msg)
122         return data
123
124     @staticmethod
125     def create_memif_interface(node, filename, mid, sid, rxq=1, txq=1,
126                                role="SLAVE"):
127         """Create Memif interface on the given node.
128
129         :param node: Given node to create Memif interface on.
130         :param filename: Memif interface socket filename.
131         :param mid: Memif interface ID.
132         :param sid: Socket ID.
133         :param rxq: Number of RX queues; 0 means do not set.
134         :param txq: Number of TX queues; 0 means do not set.
135         :param role: Memif interface role [master=0|slave=1]. Default is master.
136         :type node: dict
137         :type filename: str
138         :type mid: str
139         :type sid: str
140         :type rxq: int
141         :type txq: int
142         :type role: str
143         :returns: SW interface index.
144         :rtype: int
145         :raises ValueError: If command 'create memif' fails.
146         """
147
148         role = getattr(MemifRole, role.upper()).value
149
150         # Create socket
151         Memif._memif_socket_filename_add_del(node, True, filename, sid)
152
153         # Create memif
154         rsp = Memif._memif_create(node, mid, sid, rxq=rxq, txq=txq, role=role)
155
156         # Update Topology
157         if_key = Topology.add_new_port(node, 'memif')
158         Topology.update_interface_sw_if_index(node, if_key, rsp["sw_if_index"])
159
160         ifc_name = Memif.vpp_get_memif_interface_name(node, rsp["sw_if_index"])
161         Topology.update_interface_name(node, if_key, ifc_name)
162
163         ifc_mac = Memif.vpp_get_memif_interface_mac(node, rsp["sw_if_index"])
164         Topology.update_interface_mac_address(node, if_key, ifc_mac)
165
166         Topology.update_interface_memif_socket(node, if_key, '/tmp/' + filename)
167         Topology.update_interface_memif_id(node, if_key, mid)
168         Topology.update_interface_memif_role(node, if_key, str(role))
169
170         return rsp["sw_if_index"]
171
172     @staticmethod
173     def show_memif(node):
174         """Show Memif data for the given node.
175
176         :param node: Given node to show Memif data on.
177         :type node: dict
178         """
179
180         Memif._memif_dump(node)
181
182     @staticmethod
183     def show_memif_on_all_duts(nodes):
184         """Show Memif data on all DUTs.
185
186         :param nodes: Topology nodes.
187         :type nodes: dict
188         """
189         for node in nodes.values():
190             if node['type'] == NodeType.DUT:
191                 Memif.show_memif(node)
192
193     @staticmethod
194     def vpp_get_memif_interface_name(node, sw_if_idx):
195         """Get Memif interface name from Memif interfaces dump.
196
197         :param node: DUT node.
198         :param sw_if_idx: DUT node.
199         :type node: dict
200         :type sw_if_idx: int
201         :returns: Memif interface name, or None if not found.
202         :rtype: str
203         """
204
205         dump = Memif._memif_dump(node)
206
207         for item in dump:
208             if item["memif_details"]["sw_if_index"] == sw_if_idx:
209                 return item["memif_details"]["if_name"]
210         return None
211
212     @staticmethod
213     def vpp_get_memif_interface_mac(node, sw_if_idx):
214         """Get Memif interface MAC address from Memif interfaces dump.
215
216         :param node: DUT node.
217         :param sw_if_idx: DUT node.
218         :type node: dict
219         :type sw_if_idx: int
220         :returns: Memif interface MAC address, or None if not found.
221         :rtype: str
222         """
223
224         dump = Memif._memif_dump(node)
225
226         for item in dump:
227             if item["memif_details"]["sw_if_index"] == sw_if_idx:
228                 return item["memif_details"]["hw_addr"]
229         return None