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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """Vhost-user interfaces library."""
16 from enum import IntEnum
18 from robot.api import logger
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
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
47 """Vhost-user interfaces L1 library."""
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.
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.
61 :type virtio_feature_mask: int
62 :returns: SW interface index.
65 cmd = u"create_vhost_user_if"
66 err_msg = f"Failed to create Vhost-user interface " \
67 f"on host {node[u'host']}"
68 if virtio_feature_mask is None:
71 enable_gso = VirtioFeatureMask.is_feature_enabled(
72 virtio_feature_mask, VirtioFeaturesFlags.VIRTIO_NET_F_API_GSO
75 is_server=bool(is_server),
76 sock_filename=str(socket),
77 enable_gso=bool(enable_gso)
80 with PapiSocketExecutor(node) as papi_exec:
81 sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
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)
87 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_index)
88 Topology.update_interface_name(node, if_key, ifc_name)
90 ifc_mac = InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
91 Topology.update_interface_mac_address(node, if_key, ifc_mac)
93 Topology.update_interface_vhost_socket(node, if_key, socket)
98 def get_vhost_user_if_name_by_sock(node, socket):
99 """Get Vhost-user interface name by socket.
101 :param node: Node to get Vhost-user interface name on.
102 :param socket: Vhost-user interface socket path.
105 :returns: Interface name or None if not found.
108 for interface in node[u"interfaces"].values():
109 if interface.get(u"socket") == socket:
110 return interface.get(u"name")
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
118 :param node: VPP node to get interface data from.
119 :param sw_if_index: SW index of the specific interface.
121 :type sw_if_index: str
122 :returns: l2_address of the given interface.
125 return InterfaceUtil.vpp_get_interface_mac(node, sw_if_index)
128 def show_vpp_vhost_on_all_duts(nodes):
129 """Show Vhost-user on all DUTs.
131 :param nodes: VPP nodes.
134 for node in nodes.values():
135 if node[u"type"] == NodeType.DUT:
136 VhostUser.vhost_user_dump(node)
139 def vhost_user_dump(node):
140 """Get vhost-user data for the given node.
142 :param node: VPP node to get interface data from.
144 :returns: List of dictionaries with all vhost-user interfaces.
147 cmd = u"sw_interface_vhost_user_dump"
148 err_msg = f"Failed to get vhost-user dump on host {node['host']}"
150 with PapiSocketExecutor(node) as papi_exec:
151 details = papi_exec.add(cmd).get_details(err_msg)
153 logger.debug(f"Vhost-user details:\n{details}")
157 def vhost_user_affinity(node, pf_key, skip_cnt=0):
158 """Set vhost-user affinity for the given node.
160 :param node: Topology node.
161 :param pf_key: Interface key to compute numa location.
162 :param skip_cnt: Skip first "skip_cnt" CPUs.
167 pids, _ = exec_cmd_no_error(
168 node, f"grep -h vhost /proc/*/comm | uniq | xargs pidof")
170 affinity = CpuUtils.get_affinity_vhost(
171 node, pf_key, skip_cnt=skip_cnt, cpu_cnt=len(pids.split(" ")))
173 for cpu, pid in zip(affinity, pids.split(" ")):
174 exec_cmd_no_error(node, f"taskset -pc {cpu} {pid}", sudo=True)
177 class VirtioFeatureMask:
178 """Virtio features utilities"""
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
186 virtio_feature_mask = 0
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
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")
198 virtio_feature_mask |= \
199 1 << VirtioFeaturesFlags[virtio_feature_name].value
201 return virtio_feature_mask
204 def is_feature_enabled(virtio_feature_mask, virtio_feature_flag):
205 """Checks if concrete virtio feature is enabled within
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
212 feature_flag_bit = 1 << virtio_feature_flag.value
213 return (virtio_feature_mask & feature_flag_bit) > 0