1 # Copyright (c) 2020 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"vs_dtc"] if kwargs[u"auto_scale"] \
55 else kwargs[u"nf_dtc"]
56 nf_dtcr = kwargs[u"nf_dtcr"] \
57 if isinstance(kwargs[u"nf_dtcr"], int) else 2
59 for nf_chain in range(1, nf_chains + 1):
60 for nf_node in range(1, nf_nodes + 1):
61 qemu_id = (nf_chain - 1) * nf_nodes + nf_node
62 name = f"{node}_{qemu_id}"
63 idx1 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2 - 1
65 vif1_mac = Topology.get_interface_mac(
66 self.nodes[node], f"vhost{idx1}"
67 ) if kwargs[u"vnf"] == u"testpmd_mac" \
68 else kwargs[u"tg_pf1_mac"] if nf_node == 1 \
69 else f"52:54:00:00:{(qemu_id - 1):02x}:02"
70 idx2 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2
71 vif2_mac = Topology.get_interface_mac(
72 self.nodes[node], f"vhost{idx2}"
73 ) if kwargs[u"vnf"] == u"testpmd_mac" \
74 else kwargs[u"tg_pf2_mac"] if nf_node == nf_nodes \
75 else f"52:54:00:00:{(qemu_id + 1):02x}:01"
77 self.machines_affinity[name] = CpuUtils.get_affinity_nf(
78 nodes=self.nodes, node=node, nf_chains=nf_chains,
79 nf_nodes=nf_nodes, nf_chain=nf_chain, nf_node=nf_node,
80 vs_dtc=vs_dtc, nf_dtc=nf_dtc, nf_dtcr=nf_dtcr
84 getattr(self, f'_c_{kwargs["vnf"]}')(
85 qemu_id=qemu_id, name=name, queues=queues, **kwargs
87 except AttributeError:
89 qemu_id=qemu_id, name=name, queues=queues,
90 vif1_mac=vif1_mac, vif2_mac=vif2_mac, **kwargs
93 def construct_vms_on_all_nodes(self, **kwargs):
94 """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
96 :param kwargs: Named parameters.
100 for node in self.nodes:
101 if self.nodes[node][u"type"] == NodeType.DUT:
102 self.construct_vms_on_node(node=node, **kwargs)
104 def start_all_vms(self, pinning=False):
105 """Start all added VMs in manager.
107 :param pinning: If True, then do also QEMU process pinning.
111 for machine, machine_affinity in \
112 zip(self.machines.values(), self.machines_affinity.values()):
113 index = list(self.machines.values()).index(machine)
114 name = list(self.machines.keys())[index]
115 self.nodes[name] = machine.qemu_start()
117 machine.qemu_set_affinity(*machine_affinity)
118 cpus.extend(machine_affinity)
119 return ",".join(str(cpu) for cpu in cpus)
121 def kill_all_vms(self, force=False):
122 """Kill all added VMs in manager.
124 :param force: Force kill all Qemu instances by pkill qemu if True.
127 for node in list(self.nodes.values()):
128 if node["type"] == NodeType.VM:
130 self.nodes.popitem(node)
133 for machine in self.machines.values():
135 machine.qemu_kill_all()
139 def _c_default(self, **kwargs):
140 """Instantiate one VM with default configuration.
142 :param kwargs: Named parameters.
145 qemu_id = kwargs[u"qemu_id"]
146 name = kwargs[u"name"]
147 virtio_feature_mask = kwargs[u"virtio_feature_mask"] \
148 if u"virtio_feature_mask" in kwargs else None
150 self.machines[name] = QemuUtils(
151 node=self.nodes[kwargs[u"node"]],
153 smp=len(self.machines_affinity[name]),
156 img=Constants.QEMU_VM_KERNEL
158 self.machines[name].add_default_params()
159 self.machines[name].add_kernelvm_params()
160 self.machines[name].configure_kernelvm_vnf(
161 mac1=f"52:54:00:00:{qemu_id:02x}:01",
162 mac2=f"52:54:00:00:{qemu_id:02x}:02",
163 vif1_mac=kwargs[u"vif1_mac"],
164 vif2_mac=kwargs[u"vif2_mac"],
165 queues=kwargs[u"queues"],
166 jumbo_frames=kwargs[u"jumbo"]
168 self.machines[name].add_vhost_user_if(
169 f"/run/vpp/sock-{qemu_id}-1",
170 jumbo_frames=kwargs[u"jumbo"],
171 queues=kwargs[u"queues"],
172 queue_size=kwargs[u"perf_qemu_qsz"],
173 virtio_feature_mask=virtio_feature_mask
175 self.machines[name].add_vhost_user_if(
176 f"/run/vpp/sock-{qemu_id}-2",
177 jumbo_frames=kwargs[u"jumbo"],
178 queues=kwargs[u"queues"],
179 queue_size=kwargs[u"perf_qemu_qsz"],
180 virtio_feature_mask=virtio_feature_mask
183 def _c_vpp_2vfpt_ip4base_plen24(self, **kwargs):
184 """Instantiate one VM with vpp_2vfpt_ip4base_plen24 configuration.
186 :param kwargs: Named parameters.
189 qemu_id = kwargs[u"qemu_id"]
190 name = kwargs[u"name"]
192 self.machines[name] = QemuUtils(
193 node=self.nodes[kwargs[u"node"]],
195 smp=len(self.machines_affinity[name]),
198 img=Constants.QEMU_VM_KERNEL
200 self.machines[name].add_default_params()
201 self.machines[name].add_kernelvm_params()
203 self.machines[name].configure_kernelvm_vnf(
206 route1=u"20.0.0.0/24",
207 routeif1=u"avf-0/0/6/0",
209 route2=u"10.0.0.0/24",
210 routeif2=u"avf-0/0/7/0",
212 arpmac1=u"3c:fd:fe:d1:5c:d8",
214 arpif1=u"avf-0/0/7/0",
215 queues=kwargs[u"queues"],
216 jumbo_frames=kwargs[u"jumbo"]
219 self.machines[name].configure_kernelvm_vnf(
222 route1=u"10.0.0.0/24",
223 routeif1=u"avf-0/0/7/0",
225 route2=u"20.0.0.0/24",
226 routeif2=u"avf-0/0/6/0",
228 arpmac1=u"3c:fd:fe:d1:5c:d9",
230 arpif1=u"avf-0/0/6/0",
231 queues=kwargs[u"queues"],
232 jumbo_frames=kwargs[u"jumbo"]
234 self.machines[name].add_vfio_pci_if(
235 pci=Topology.get_interface_pci_addr(
236 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
238 self.machines[name].add_vfio_pci_if(
239 pci=Topology.get_interface_pci_addr(
240 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
243 def _c_vpp_2vfpt_ip4scale2k_plen30(self, **kwargs):
244 """Instantiate one VM with vpp_2vfpt_ip4scale2k_plen30 configuration.
246 :param kwargs: Named parameters.
249 qemu_id = kwargs[u"qemu_id"]
250 name = kwargs[u"name"]
252 self.machines[name] = QemuUtils(
253 node=self.nodes[kwargs[u"node"]],
255 smp=len(self.machines_affinity[name]),
258 img=Constants.QEMU_VM_KERNEL
260 self.machines[name].add_default_params()
261 self.machines[name].add_kernelvm_params()
263 self.machines[name].configure_kernelvm_vnf(
266 route1=u"20.0.0.0/30",
267 routeif1=u"avf-0/0/6/0",
269 route2=u"10.0.0.0/30",
270 routeif2=u"avf-0/0/7/0",
272 arpmac1=u"3c:fd:fe:d1:5c:d8",
274 arpif1=u"avf-0/0/7/0",
275 queues=kwargs[u"queues"],
276 jumbo_frames=kwargs[u"jumbo"]
279 self.machines[name].configure_kernelvm_vnf(
282 route1=u"10.0.0.0/30",
283 routeif1=u"avf-0/0/7/0",
285 route2=u"20.0.0.0/30",
286 routeif2=u"avf-0/0/6/0",
288 arpmac1=u"3c:fd:fe:d1:5c:d9",
290 arpif1=u"avf-0/0/6/0",
291 queues=kwargs[u"queues"],
292 jumbo_frames=kwargs[u"jumbo"]
294 self.machines[name].add_vfio_pci_if(
295 pci=Topology.get_interface_pci_addr(
296 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
298 self.machines[name].add_vfio_pci_if(
299 pci=Topology.get_interface_pci_addr(
300 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
303 def _c_vpp_2vfpt_ip4scale20k_plen30(self, **kwargs):
304 """Instantiate one VM with vpp_2vfpt_ip4scale20k_plen30 configuration.
306 :param kwargs: Named parameters.
309 qemu_id = kwargs[u"qemu_id"]
310 name = kwargs[u"name"]
312 self.machines[name] = QemuUtils(
313 node=self.nodes[kwargs[u"node"]],
315 smp=len(self.machines_affinity[name]),
318 img=Constants.QEMU_VM_KERNEL
320 self.machines[name].add_default_params()
321 self.machines[name].add_kernelvm_params()
323 self.machines[name].configure_kernelvm_vnf(
326 route1=u"20.0.0.0/30",
327 routeif1=u"avf-0/0/6/0",
329 route2=u"10.0.0.0/30",
330 routeif2=u"avf-0/0/7/0",
332 arpmac1=u"3c:fd:fe:d1:5c:d8",
334 arpif1=u"avf-0/0/7/0",
335 queues=kwargs[u"queues"],
336 jumbo_frames=kwargs[u"jumbo"]
339 self.machines[name].configure_kernelvm_vnf(
342 route1=u"10.0.0.0/30",
343 routeif1=u"avf-0/0/7/0",
345 route2=u"20.0.0.0/30",
346 routeif2=u"avf-0/0/6/0",
348 arpmac1=u"3c:fd:fe:d1:5c:d9",
350 arpif1=u"avf-0/0/6/0",
351 queues=kwargs[u"queues"],
352 jumbo_frames=kwargs[u"jumbo"]
354 self.machines[name].add_vfio_pci_if(
355 pci=Topology.get_interface_pci_addr(
356 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
358 self.machines[name].add_vfio_pci_if(
359 pci=Topology.get_interface_pci_addr(
360 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
363 def _c_vpp_2vfpt_ip4scale200k_plen30(self, **kwargs):
364 """Instantiate one VM with vpp_2vfpt_ip4scale200k_plen30 configuration.
366 :param kwargs: Named parameters.
369 qemu_id = kwargs[u"qemu_id"]
370 name = kwargs[u"name"]
372 self.machines[name] = QemuUtils(
373 node=self.nodes[kwargs[u"node"]],
375 smp=len(self.machines_affinity[name]),
378 img=Constants.QEMU_VM_KERNEL
380 self.machines[name].add_default_params()
381 self.machines[name].add_kernelvm_params()
383 self.machines[name].configure_kernelvm_vnf(
386 route1=u"20.0.0.0/30",
387 routeif1=u"avf-0/0/6/0",
389 route2=u"10.0.0.0/30",
390 routeif2=u"avf-0/0/7/0",
392 arpmac1=u"3c:fd:fe:d1:5c:d8",
394 arpif1=u"avf-0/0/7/0",
395 queues=kwargs[u"queues"],
396 jumbo_frames=kwargs[u"jumbo"]
399 self.machines[name].configure_kernelvm_vnf(
402 route1=u"10.0.0.0/30",
403 routeif1=u"avf-0/0/7/0",
405 route2=u"20.0.0.0/30",
406 routeif2=u"avf-0/0/6/0",
408 arpmac1=u"3c:fd:fe:d1:5c:d9",
410 arpif1=u"avf-0/0/6/0",
411 queues=kwargs[u"queues"],
412 jumbo_frames=kwargs[u"jumbo"]
414 self.machines[name].add_vfio_pci_if(
415 pci=Topology.get_interface_pci_addr(
416 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
418 self.machines[name].add_vfio_pci_if(
419 pci=Topology.get_interface_pci_addr(
420 self.nodes[kwargs[u"node"]], kwargs[u"if1"])