Update VPP_STABLE_VER files
[csit.git] / resources / libraries / python / VhostUser.py
1 # Copyright (c) 2021 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 """Vhost-user interfaces library."""
15
16 from enum import IntEnum
17
18 from robot.api import logger
19
20 from resources.libraries.python.CpuUtils import CpuUtils
21 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
22 from resources.libraries.python.topology import NodeType, Topology
23 from resources.libraries.python.InterfaceUtil import InterfaceUtil
24 from resources.libraries.python.ssh import exec_cmd_no_error
25
26
27 class VirtioFeaturesFlags(IntEnum):
28     """Virtio Features Flags."""
29     VIRTIO_NET_F_API_CSUM = 0
30     VIRTIO_NET_F_API_GUEST_CSUM = 1
31     VIRTIO_NET_F_API_GSO = 6
32     VIRTIO_NET_F_API_GUEST_TSO4 = 7
33     VIRTIO_NET_F_API_GUEST_TSO6 = 8
34     VIRTIO_NET_F_API_GUEST_UFO = 10
35     VIRTIO_NET_F_API_HOST_TSO4 = 11
36     VIRTIO_NET_F_API_HOST_TSO6 = 12
37     VIRTIO_NET_F_API_HOST_UFO = 14
38     VIRTIO_NET_F_API_MRG_RXBUF = 15
39     VIRTIO_NET_F_API_CTRL_VQ = 17
40     VIRTIO_NET_F_API_GUEST_ANNOUNCE = 21
41     VIRTIO_NET_F_API_MQ = 22
42     VIRTIO_F_API_ANY_LAYOUT = 27
43     VIRTIO_F_API_INDIRECT_DESC = 28
44
45
46 class VhostUser:
47     """Vhost-user interfaces L1 library."""
48
49     @staticmethod
50     def vpp_create_vhost_user_interface(
51             node, socket, is_server=False, virtio_feature_mask=None):
52         """Create Vhost-user interface on VPP node.
53
54         :param node: Node to create Vhost-user interface on.
55         :param socket: Vhost-user interface socket path.
56         :param is_server: Server side of connection. Default: False
57         :param virtio_feature_mask: Mask of virtio features to be enabled.
58         :type node: dict
59         :type socket: str
60         :type is_server: bool
61         :type virtio_feature_mask: int
62         :returns: SW interface index.
63         :rtype: int
64         """
65         cmd = u"create_vhost_user_if_v2"
66         err_msg = f"Failed to create Vhost-user interface " \
67             f"on host {node[u'host']}"
68         if virtio_feature_mask is None:
69             enable_gso = False
70         else:
71             enable_gso = VirtioFeatureMask.is_feature_enabled(
72                 virtio_feature_mask, VirtioFeaturesFlags.VIRTIO_NET_F_API_GSO
73             )
74         args = dict(
75             is_server=bool(is_server),
76             sock_filename=str(socket),
77             enable_gso=bool(enable_gso)
78         )
79
80         with PapiSocketExecutor(node) as papi_exec:
81             sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
82
83         # Update the Topology:
84         if_key = Topology.add_new_port(node, u"vhost")
85         Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
86
87         ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
88         Topology.update_interface_name(node, if_key, ifc_name)
89
90         ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
91         Topology.update_interface_mac_address(node, if_key, ifc_mac)
92
93         Topology.update_interface_vhost_socket(node, if_key, socket)
94
95         return sw_if_index
96
97     @staticmethod
98     def get_vhost_user_if_name_by_sock(node, socket):
99         """Get Vhost-user interface name by socket.
100
101         :param node: Node to get Vhost-user interface name on.
102         :param socket: Vhost-user interface socket path.
103         :type node: dict
104         :type socket: str
105         :returns: Interface name or None if not found.
106         :rtype: str
107         """
108         for interface in node[u"interfaces"].values():
109             if interface.get(u"socket") == socket:
110                 return interface.get(u"name")
111         return None
112
113     @staticmethod
114     def get_vhost_user_mac_by_sw_index(node, sw_if_index):
115         """Get Vhost-user l2_address for the given interface from actual
116         interface dump.
117
118         :param node: VPP node to get interface data from.
119         :param sw_if_index: SW index of the specific interface.
120         :type node: dict
121         :type sw_if_index: str
122         :returns: l2_address of the given interface.
123         :rtype: str
124         """
125         return InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
126
127     @staticmethod
128     def show_vpp_vhost_on_all_duts(nodes):
129         """Show Vhost-user on all DUTs.
130
131         :param nodes: VPP nodes.
132         :type nodes: dict
133         """
134         for node in nodes.values():
135             if node[u"type"] == NodeType.DUT:
136                 VhostUser.vhost_user_dump(node)
137
138     @staticmethod
139     def vhost_user_dump(node):
140         """Get vhost-user data for the given node.
141
142         :param node: VPP node to get interface data from.
143         :type node: dict
144         :returns: List of dictionaries with all vhost-user interfaces.
145         :rtype: list
146         """
147         cmd = u"sw_interface_vhost_user_dump"
148         err_msg = f"Failed to get vhost-user dump on host {node['host']}"
149
150         with PapiSocketExecutor(node) as papi_exec:
151             details = papi_exec.add(cmd).get_details(err_msg)
152
153         logger.debug(f"Vhost-user details:\n{details}")
154         return details
155
156     @staticmethod
157     def vhost_user_affinity(node, pf_key, skip_cnt=0):
158         """Set vhost-user affinity for the given node.
159
160         :param node: Topology node.
161         :param pf_key: Interface key to compute numa location.
162         :param skip_cnt: Skip first "skip_cnt" CPUs.
163         :type node: dict
164         :type pf_key: str
165         :type skip_cnt: int
166         """
167         pids, _ = exec_cmd_no_error(
168             node, f"grep -h vhost /proc/*/comm | uniq | xargs pidof")
169
170         affinity = CpuUtils.get_affinity_vhost(
171             node, pf_key, skip_cnt=skip_cnt, cpu_cnt=len(pids.split(" ")))
172
173         for cpu, pid in zip(affinity, pids.split(" ")):
174             exec_cmd_no_error(node, f"taskset -pc {cpu} {pid}", sudo=True)
175
176
177 class VirtioFeatureMask:
178     """Virtio features utilities"""
179
180     @staticmethod
181     def create_virtio_feature_mask(**kwargs):
182         """Create virtio feature mask with feature bits set according to kwargs.
183         :param kwargs: Key-value pairs of feature names and it's state
184         :type kwargs: dict
185         """
186         virtio_feature_mask = 0
187
188         if u"all" in kwargs and kwargs[u"all"] is True:
189             for virtio_feature_flag in VirtioFeaturesFlags:
190                 virtio_feature_mask |= 1 << virtio_feature_flag.value
191         else:
192             for feature_name, enabled in kwargs.items():
193                 virtio_feature_name = \
194                     u"VIRTIO_NET_F_API_" + feature_name.upper()
195                 if virtio_feature_name not in VirtioFeaturesFlags.__members__:
196                     raise ValueError(u"Unsupported virtio feature flag name")
197                 if enabled:
198                     virtio_feature_mask |= \
199                         1 << VirtioFeaturesFlags[virtio_feature_name].value
200
201         return virtio_feature_mask
202
203     @staticmethod
204     def is_feature_enabled(virtio_feature_mask, virtio_feature_flag):
205         """Checks if concrete virtio feature is enabled within
206         virtio_feature_mask
207         :param virtio_feature_mask: Mask of enabled virtio features
208         :param virtio_feature_flag: Checked virtio feature
209         :type virtio_feature_mask: int
210         :type virtio_feature_flag: VirtioFeaturesFlags
211         """
212         feature_flag_bit = 1 << virtio_feature_flag.value
213         return (virtio_feature_mask & feature_flag_bit) > 0