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 """QEMU Manager library."""
16 from collections import OrderedDict
18 from resources.libraries.python.Constants import Constants
19 from resources.libraries.python.CpuUtils import CpuUtils
20 from resources.libraries.python.QemuUtils import QemuUtils
21 from resources.libraries.python.topology import NodeType, Topology
23 __all__ = [u"QemuManager"]
27 """QEMU lifecycle management class"""
29 # Use one instance of class per tests.
30 ROBOT_LIBRARY_SCOPE = u"TEST CASE"
32 def __init__(self, nodes):
33 """Init QemuManager object."""
35 self.machines_affinity = None
39 """Initialize QemuManager object."""
40 self.machines = OrderedDict()
41 self.machines_affinity = OrderedDict()
43 def construct_vms_on_node(self, **kwargs):
44 """Construct 1..Mx1..N VMs(s) on node with specified name.
46 :param kwargs: Named parameters.
49 node = kwargs[u"node"]
50 nf_chains = int(kwargs[u"nf_chains"])
51 nf_nodes = int(kwargs[u"nf_nodes"])
52 queues = kwargs[u"rxq_count_int"] if kwargs[u"auto_scale"] else 1
53 vs_dtc = kwargs[u"vs_dtc"]
54 nf_dtc = kwargs[u"nf_dtc"]
55 if kwargs[u"auto_scale"] and not kwargs[u"fixed_auto_scale"]:
56 nf_dtc = kwargs[u"vs_dtc"]
57 nf_dtcr = kwargs[u"nf_dtcr"] \
58 if isinstance(kwargs[u"nf_dtcr"], int) else 2
60 for nf_chain in range(1, nf_chains + 1):
61 for nf_node in range(1, nf_nodes + 1):
62 qemu_id = (nf_chain - 1) * nf_nodes + nf_node
63 name = f"{node}_{qemu_id}"
64 idx1 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2 - 1
66 vif1_mac = Topology.get_interface_mac(
67 self.nodes[node], f"vhost{idx1}"
68 ) if kwargs[u"vnf"] == u"testpmd_mac" \
69 else kwargs[u"tg_pf1_mac"] if nf_node == 1 \
70 else f"52:54:00:00:{(qemu_id - 1):02x}:02"
71 idx2 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2
72 vif2_mac = Topology.get_interface_mac(
73 self.nodes[node], f"vhost{idx2}"
74 ) if kwargs[u"vnf"] == u"testpmd_mac" \
75 else kwargs[u"tg_pf2_mac"] if nf_node == nf_nodes \
76 else f"52:54:00:00:{(qemu_id + 1):02x}:01"
78 self.machines_affinity[name] = CpuUtils.get_affinity_nf(
79 nodes=self.nodes, node=node, nf_chains=nf_chains,
80 nf_nodes=nf_nodes, nf_chain=nf_chain, nf_node=nf_node,
81 vs_dtc=vs_dtc, nf_dtc=nf_dtc, nf_dtcr=nf_dtcr
85 getattr(self, f'_c_{kwargs["vnf"]}')(
86 qemu_id=qemu_id, name=name, queues=queues, **kwargs
88 except AttributeError:
90 qemu_id=qemu_id, name=name, queues=queues,
91 vif1_mac=vif1_mac, vif2_mac=vif2_mac, **kwargs
94 def construct_vms_on_all_nodes(self, **kwargs):
95 """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
97 :param kwargs: Named parameters.
101 for node in self.nodes:
102 if self.nodes[node][u"type"] == NodeType.DUT:
103 self.construct_vms_on_node(node=node, **kwargs)
105 def start_all_vms(self, pinning=False):
106 """Start all added VMs in manager.
108 :param pinning: If True, then do also QEMU process pinning.
112 for machine, machine_affinity in \
113 zip(self.machines.values(), self.machines_affinity.values()):
114 index = list(self.machines.values()).index(machine)
115 name = list(self.machines.keys())[index]
116 self.nodes[name] = machine.qemu_start()
118 machine.qemu_set_affinity(*machine_affinity)
119 cpus.extend(machine_affinity)
120 return ",".join(str(cpu) for cpu in cpus)
122 def kill_all_vms(self, force=False):
123 """Kill all added VMs in manager.
125 :param force: Force kill all Qemu instances by pkill qemu if True.
128 for node in list(self.nodes.values()):
129 if node["type"] == NodeType.VM:
131 self.nodes.popitem(node)
134 for machine in self.machines.values():
136 machine.qemu_kill_all()
140 def _c_default(self, **kwargs):
141 """Instantiate one VM with default configuration.
143 :param kwargs: Named parameters.
146 qemu_id = kwargs[u"qemu_id"]
147 name = kwargs[u"name"]
148 virtio_feature_mask = kwargs[u"virtio_feature_mask"] \
149 if u"virtio_feature_mask" in kwargs else None
151 self.machines[name] = QemuUtils(
152 node=self.nodes[kwargs[u"node"]],
154 smp=len(self.machines_affinity[name]),
157 img=Constants.QEMU_VM_KERNEL
159 self.machines[name].add_default_params()
160 self.machines[name].add_kernelvm_params()
161 self.machines[name].configure_kernelvm_vnf(
162 mac1=f"52:54:00:00:{qemu_id:02x}:01",
163 mac2=f"52:54:00:00:{qemu_id:02x}:02",
164 vif1_mac=kwargs[u"vif1_mac"],
165 vif2_mac=kwargs[u"vif2_mac"],
166 queues=kwargs[u"queues"],
167 jumbo_frames=kwargs[u"jumbo"]
169 self.machines[name].add_vhost_user_if(
170 f"/run/vpp/sock-{qemu_id}-1",
171 jumbo_frames=kwargs[u"jumbo"],
172 queues=kwargs[u"queues"],
173 queue_size=kwargs[u"perf_qemu_qsz"],
174 virtio_feature_mask=virtio_feature_mask
176 self.machines[name].add_vhost_user_if(
177 f"/run/vpp/sock-{qemu_id}-2",
178 jumbo_frames=kwargs[u"jumbo"],
179 queues=kwargs[u"queues"],
180 queue_size=kwargs[u"perf_qemu_qsz"],
181 virtio_feature_mask=virtio_feature_mask
184 def _c_vpp_2vfpt_ip4base_plen24(self, **kwargs):
185 """Instantiate one VM with vpp_2vfpt_ip4base_plen24 configuration.
187 :param kwargs: Named parameters.
190 qemu_id = kwargs[u"qemu_id"]
191 name = kwargs[u"name"]
193 self.machines[name] = QemuUtils(
194 node=self.nodes[kwargs[u"node"]],
196 smp=len(self.machines_affinity[name]),
199 img=Constants.QEMU_VM_KERNEL
201 self.machines[name].add_default_params()
202 self.machines[name].add_kernelvm_params()
204 self.machines[name].configure_kernelvm_vnf(
207 route1=u"20.0.0.0/24",
208 routeif1=u"avf-0/0/6/0",
210 route2=u"10.0.0.0/24",
211 routeif2=u"avf-0/0/7/0",
213 arpmac1=u"3c:fd:fe:d1:5c:d8",
215 arpif1=u"avf-0/0/7/0",
216 queues=kwargs[u"queues"],
217 jumbo_frames=kwargs[u"jumbo"]
220 self.machines[name].configure_kernelvm_vnf(
223 route1=u"10.0.0.0/24",
224 routeif1=u"avf-0/0/7/0",
226 route2=u"20.0.0.0/24",
227 routeif2=u"avf-0/0/6/0",
229 arpmac1=u"3c:fd:fe:d1:5c:d9",
231 arpif1=u"avf-0/0/6/0",
232 queues=kwargs[u"queues"],
233 jumbo_frames=kwargs[u"jumbo"]
235 self.machines[name].add_vfio_pci_if(
236 pci=Topology.get_interface_pci_addr(
237 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
239 self.machines[name].add_vfio_pci_if(
240 pci=Topology.get_interface_pci_addr(
241 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
244 def _c_vpp_2vfpt_ip4scale2k_plen30(self, **kwargs):
245 """Instantiate one VM with vpp_2vfpt_ip4scale2k_plen30 configuration.
247 :param kwargs: Named parameters.
250 qemu_id = kwargs[u"qemu_id"]
251 name = kwargs[u"name"]
253 self.machines[name] = QemuUtils(
254 node=self.nodes[kwargs[u"node"]],
256 smp=len(self.machines_affinity[name]),
259 img=Constants.QEMU_VM_KERNEL
261 self.machines[name].add_default_params()
262 self.machines[name].add_kernelvm_params()
264 self.machines[name].configure_kernelvm_vnf(
267 route1=u"20.0.0.0/30",
268 routeif1=u"avf-0/0/6/0",
270 route2=u"10.0.0.0/30",
271 routeif2=u"avf-0/0/7/0",
273 arpmac1=u"3c:fd:fe:d1:5c:d8",
275 arpif1=u"avf-0/0/7/0",
276 queues=kwargs[u"queues"],
277 jumbo_frames=kwargs[u"jumbo"]
280 self.machines[name].configure_kernelvm_vnf(
283 route1=u"10.0.0.0/30",
284 routeif1=u"avf-0/0/7/0",
286 route2=u"20.0.0.0/30",
287 routeif2=u"avf-0/0/6/0",
289 arpmac1=u"3c:fd:fe:d1:5c:d9",
291 arpif1=u"avf-0/0/6/0",
292 queues=kwargs[u"queues"],
293 jumbo_frames=kwargs[u"jumbo"]
295 self.machines[name].add_vfio_pci_if(
296 pci=Topology.get_interface_pci_addr(
297 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
299 self.machines[name].add_vfio_pci_if(
300 pci=Topology.get_interface_pci_addr(
301 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
304 def _c_vpp_2vfpt_ip4scale20k_plen30(self, **kwargs):
305 """Instantiate one VM with vpp_2vfpt_ip4scale20k_plen30 configuration.
307 :param kwargs: Named parameters.
310 qemu_id = kwargs[u"qemu_id"]
311 name = kwargs[u"name"]
313 self.machines[name] = QemuUtils(
314 node=self.nodes[kwargs[u"node"]],
316 smp=len(self.machines_affinity[name]),
319 img=Constants.QEMU_VM_KERNEL
321 self.machines[name].add_default_params()
322 self.machines[name].add_kernelvm_params()
324 self.machines[name].configure_kernelvm_vnf(
327 route1=u"20.0.0.0/30",
328 routeif1=u"avf-0/0/6/0",
330 route2=u"10.0.0.0/30",
331 routeif2=u"avf-0/0/7/0",
333 arpmac1=u"3c:fd:fe:d1:5c:d8",
335 arpif1=u"avf-0/0/7/0",
336 queues=kwargs[u"queues"],
337 jumbo_frames=kwargs[u"jumbo"]
340 self.machines[name].configure_kernelvm_vnf(
343 route1=u"10.0.0.0/30",
344 routeif1=u"avf-0/0/7/0",
346 route2=u"20.0.0.0/30",
347 routeif2=u"avf-0/0/6/0",
349 arpmac1=u"3c:fd:fe:d1:5c:d9",
351 arpif1=u"avf-0/0/6/0",
352 queues=kwargs[u"queues"],
353 jumbo_frames=kwargs[u"jumbo"]
355 self.machines[name].add_vfio_pci_if(
356 pci=Topology.get_interface_pci_addr(
357 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
359 self.machines[name].add_vfio_pci_if(
360 pci=Topology.get_interface_pci_addr(
361 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
364 def _c_vpp_2vfpt_ip4scale200k_plen30(self, **kwargs):
365 """Instantiate one VM with vpp_2vfpt_ip4scale200k_plen30 configuration.
367 :param kwargs: Named parameters.
370 qemu_id = kwargs[u"qemu_id"]
371 name = kwargs[u"name"]
373 self.machines[name] = QemuUtils(
374 node=self.nodes[kwargs[u"node"]],
376 smp=len(self.machines_affinity[name]),
379 img=Constants.QEMU_VM_KERNEL
381 self.machines[name].add_default_params()
382 self.machines[name].add_kernelvm_params()
384 self.machines[name].configure_kernelvm_vnf(
387 route1=u"20.0.0.0/30",
388 routeif1=u"avf-0/0/6/0",
390 route2=u"10.0.0.0/30",
391 routeif2=u"avf-0/0/7/0",
393 arpmac1=u"3c:fd:fe:d1:5c:d8",
395 arpif1=u"avf-0/0/7/0",
396 queues=kwargs[u"queues"],
397 jumbo_frames=kwargs[u"jumbo"]
400 self.machines[name].configure_kernelvm_vnf(
403 route1=u"10.0.0.0/30",
404 routeif1=u"avf-0/0/7/0",
406 route2=u"20.0.0.0/30",
407 routeif2=u"avf-0/0/6/0",
409 arpmac1=u"3c:fd:fe:d1:5c:d9",
411 arpif1=u"avf-0/0/6/0",
412 queues=kwargs[u"queues"],
413 jumbo_frames=kwargs[u"jumbo"]
415 self.machines[name].add_vfio_pci_if(
416 pci=Topology.get_interface_pci_addr(
417 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
419 self.machines[name].add_vfio_pci_if(
420 pci=Topology.get_interface_pci_addr(
421 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
424 def _c_iperf3(self, **kwargs):
425 """Instantiate one VM with iperf3 configuration.
427 :param kwargs: Named parameters.
430 qemu_id = kwargs[u"qemu_id"]
431 name = kwargs[u"name"]
432 virtio_feature_mask = kwargs[u"virtio_feature_mask"] \
433 if u"virtio_feature_mask" in kwargs else None
435 self.machines[name] = QemuUtils(
436 node=self.nodes[kwargs[u"node"]],
438 smp=len(self.machines_affinity[name]),
441 img=Constants.QEMU_VM_KERNEL
443 self.machines[name].add_default_params()
444 self.machines[name].add_kernelvm_params()
445 self.machines[name].configure_kernelvm_vnf(
446 queues=kwargs[u"queues"],
447 jumbo_frames=kwargs[u"jumbo"]
449 self.machines[name].add_net_user()
450 self.machines[name].add_vhost_user_if(
451 f"/run/vpp/sock-{qemu_id}-1",
453 jumbo_frames=kwargs[u"jumbo"],
454 queues=kwargs[u"queues"],
455 queue_size=kwargs[u"perf_qemu_qsz"],
456 virtio_feature_mask=virtio_feature_mask