feat(jobspec): Unify soak jobspecs
[csit.git] / resources / libraries / python / QemuManager.py
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:
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 """QEMU Manager library."""
15
16 from collections import OrderedDict
17
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
22
23 __all__ = [u"QemuManager"]
24
25
26 class QemuManager:
27     """QEMU lifecycle management class"""
28
29     # Use one instance of class per tests.
30     ROBOT_LIBRARY_SCOPE = u"TEST CASE"
31
32     def __init__(self, nodes):
33         """Init QemuManager object."""
34         self.machines = None
35         self.machines_affinity = None
36         self.nodes = nodes
37
38     def initialize(self):
39         """Initialize QemuManager object."""
40         self.machines = OrderedDict()
41         self.machines_affinity = OrderedDict()
42
43     def construct_vms_on_node(self, **kwargs):
44         """Construct 1..Mx1..N VMs(s) on node with specified name.
45
46         :param kwargs: Named parameters.
47         :type kwargs: dict
48         """
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
58
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
64
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"
76
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
81                 )
82
83                 try:
84                     getattr(self, f'_c_{kwargs["vnf"]}')(
85                         qemu_id=qemu_id, name=name, queues=queues, **kwargs
86                     )
87                 except AttributeError:
88                     self._c_default(
89                         qemu_id=qemu_id, name=name, queues=queues,
90                         vif1_mac=vif1_mac, vif2_mac=vif2_mac, **kwargs
91                     )
92
93     def construct_vms_on_all_nodes(self, **kwargs):
94         """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
95
96         :param kwargs: Named parameters.
97         :type kwargs: dict
98         """
99         self.initialize()
100         for node in self.nodes:
101             if self.nodes[node][u"type"] == NodeType.DUT:
102                 self.construct_vms_on_node(node=node, **kwargs)
103
104     def start_all_vms(self, pinning=False):
105         """Start all added VMs in manager.
106
107         :param pinning: If True, then do also QEMU process pinning.
108         :type pinning: bool
109         """
110         cpus = []
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()
116             if pinning:
117                 machine.qemu_set_affinity(*machine_affinity)
118                 cpus.extend(machine_affinity)
119         return ",".join(str(cpu) for cpu in cpus)
120
121     def kill_all_vms(self, force=False):
122         """Kill all added VMs in manager.
123
124         :param force: Force kill all Qemu instances by pkill qemu if True.
125         :type force: bool
126         """
127         for node in list(self.nodes.values()):
128             if node["type"] == NodeType.VM:
129                 try:
130                     self.nodes.popitem(node)
131                 except TypeError:
132                     pass
133         for machine in self.machines.values():
134             if force:
135                 machine.qemu_kill_all()
136             else:
137                 machine.qemu_kill()
138
139     def _c_default(self, **kwargs):
140         """Instantiate one VM with default configuration.
141
142         :param kwargs: Named parameters.
143         :type kwargs: dict
144         """
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
149
150         self.machines[name] = QemuUtils(
151             node=self.nodes[kwargs[u"node"]],
152             qemu_id=qemu_id,
153             smp=len(self.machines_affinity[name]),
154             mem=4096,
155             vnf=kwargs[u"vnf"],
156             img=Constants.QEMU_VM_KERNEL
157         )
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"]
167         )
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
174         )
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
181         )
182
183     def _c_vpp_2vfpt_ip4base_plen24(self, **kwargs):
184         """Instantiate one VM with vpp_2vfpt_ip4base_plen24 configuration.
185
186         :param kwargs: Named parameters.
187         :type kwargs: dict
188         """
189         qemu_id = kwargs[u"qemu_id"]
190         name = kwargs[u"name"]
191
192         self.machines[name] = QemuUtils(
193             node=self.nodes[kwargs[u"node"]],
194             qemu_id=qemu_id,
195             smp=len(self.machines_affinity[name]),
196             mem=4096,
197             vnf=kwargs[u"vnf"],
198             img=Constants.QEMU_VM_KERNEL
199         )
200         self.machines[name].add_default_params()
201         self.machines[name].add_kernelvm_params()
202         if u"DUT1" in name:
203             self.machines[name].configure_kernelvm_vnf(
204                 ip1=u"2.2.2.1/30",
205                 ip2=u"1.1.1.2/30",
206                 route1=u"20.0.0.0/24",
207                 routeif1=u"avf-0/0/6/0",
208                 nexthop1=u"2.2.2.2",
209                 route2=u"10.0.0.0/24",
210                 routeif2=u"avf-0/0/7/0",
211                 nexthop2=u"1.1.1.1",
212                 arpmac1=u"3c:fd:fe:d1:5c:d8",
213                 arpip1=u"1.1.1.1",
214                 arpif1=u"avf-0/0/7/0",
215                 queues=kwargs[u"queues"],
216                 jumbo_frames=kwargs[u"jumbo"]
217             )
218         else:
219             self.machines[name].configure_kernelvm_vnf(
220                 ip1=u"3.3.3.2/30",
221                 ip2=u"2.2.2.2/30",
222                 route1=u"10.0.0.0/24",
223                 routeif1=u"avf-0/0/7/0",
224                 nexthop1=u"2.2.2.1",
225                 route2=u"20.0.0.0/24",
226                 routeif2=u"avf-0/0/6/0",
227                 nexthop2=u"3.3.3.1",
228                 arpmac1=u"3c:fd:fe:d1:5c:d9",
229                 arpip1=u"3.3.3.1",
230                 arpif1=u"avf-0/0/6/0",
231                 queues=kwargs[u"queues"],
232                 jumbo_frames=kwargs[u"jumbo"]
233             )
234         self.machines[name].add_vfio_pci_if(
235             pci=Topology.get_interface_pci_addr(
236                 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
237         )
238         self.machines[name].add_vfio_pci_if(
239             pci=Topology.get_interface_pci_addr(
240                 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
241         )
242
243     def _c_vpp_2vfpt_ip4scale2k_plen30(self, **kwargs):
244         """Instantiate one VM with vpp_2vfpt_ip4scale2k_plen30 configuration.
245
246         :param kwargs: Named parameters.
247         :type kwargs: dict
248         """
249         qemu_id = kwargs[u"qemu_id"]
250         name = kwargs[u"name"]
251
252         self.machines[name] = QemuUtils(
253             node=self.nodes[kwargs[u"node"]],
254             qemu_id=qemu_id,
255             smp=len(self.machines_affinity[name]),
256             mem=4096,
257             vnf=kwargs[u"vnf"],
258             img=Constants.QEMU_VM_KERNEL
259         )
260         self.machines[name].add_default_params()
261         self.machines[name].add_kernelvm_params()
262         if u"DUT1" in name:
263             self.machines[name].configure_kernelvm_vnf(
264                 ip1=u"2.2.2.1/30",
265                 ip2=u"1.1.1.2/30",
266                 route1=u"20.0.0.0/30",
267                 routeif1=u"avf-0/0/6/0",
268                 nexthop1=u"2.2.2.2",
269                 route2=u"10.0.0.0/30",
270                 routeif2=u"avf-0/0/7/0",
271                 nexthop2=u"1.1.1.1",
272                 arpmac1=u"3c:fd:fe:d1:5c:d8",
273                 arpip1=u"1.1.1.1",
274                 arpif1=u"avf-0/0/7/0",
275                 queues=kwargs[u"queues"],
276                 jumbo_frames=kwargs[u"jumbo"]
277             )
278         else:
279             self.machines[name].configure_kernelvm_vnf(
280                 ip1=u"3.3.3.2/30",
281                 ip2=u"2.2.2.2/30",
282                 route1=u"10.0.0.0/30",
283                 routeif1=u"avf-0/0/7/0",
284                 nexthop1=u"2.2.2.1",
285                 route2=u"20.0.0.0/30",
286                 routeif2=u"avf-0/0/6/0",
287                 nexthop2=u"3.3.3.1",
288                 arpmac1=u"3c:fd:fe:d1:5c:d9",
289                 arpip1=u"3.3.3.1",
290                 arpif1=u"avf-0/0/6/0",
291                 queues=kwargs[u"queues"],
292                 jumbo_frames=kwargs[u"jumbo"]
293             )
294         self.machines[name].add_vfio_pci_if(
295             pci=Topology.get_interface_pci_addr(
296                 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
297         )
298         self.machines[name].add_vfio_pci_if(
299             pci=Topology.get_interface_pci_addr(
300                 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
301         )
302
303     def _c_vpp_2vfpt_ip4scale20k_plen30(self, **kwargs):
304         """Instantiate one VM with vpp_2vfpt_ip4scale20k_plen30 configuration.
305
306         :param kwargs: Named parameters.
307         :type kwargs: dict
308         """
309         qemu_id = kwargs[u"qemu_id"]
310         name = kwargs[u"name"]
311
312         self.machines[name] = QemuUtils(
313             node=self.nodes[kwargs[u"node"]],
314             qemu_id=qemu_id,
315             smp=len(self.machines_affinity[name]),
316             mem=4096,
317             vnf=kwargs[u"vnf"],
318             img=Constants.QEMU_VM_KERNEL
319         )
320         self.machines[name].add_default_params()
321         self.machines[name].add_kernelvm_params()
322         if u"DUT1" in name:
323             self.machines[name].configure_kernelvm_vnf(
324                 ip1=u"2.2.2.1/30",
325                 ip2=u"1.1.1.2/30",
326                 route1=u"20.0.0.0/30",
327                 routeif1=u"avf-0/0/6/0",
328                 nexthop1=u"2.2.2.2",
329                 route2=u"10.0.0.0/30",
330                 routeif2=u"avf-0/0/7/0",
331                 nexthop2=u"1.1.1.1",
332                 arpmac1=u"3c:fd:fe:d1:5c:d8",
333                 arpip1=u"1.1.1.1",
334                 arpif1=u"avf-0/0/7/0",
335                 queues=kwargs[u"queues"],
336                 jumbo_frames=kwargs[u"jumbo"]
337             )
338         else:
339             self.machines[name].configure_kernelvm_vnf(
340                 ip1=u"3.3.3.2/30",
341                 ip2=u"2.2.2.2/30",
342                 route1=u"10.0.0.0/30",
343                 routeif1=u"avf-0/0/7/0",
344                 nexthop1=u"2.2.2.1",
345                 route2=u"20.0.0.0/30",
346                 routeif2=u"avf-0/0/6/0",
347                 nexthop2=u"3.3.3.1",
348                 arpmac1=u"3c:fd:fe:d1:5c:d9",
349                 arpip1=u"3.3.3.1",
350                 arpif1=u"avf-0/0/6/0",
351                 queues=kwargs[u"queues"],
352                 jumbo_frames=kwargs[u"jumbo"]
353             )
354         self.machines[name].add_vfio_pci_if(
355             pci=Topology.get_interface_pci_addr(
356                 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
357         )
358         self.machines[name].add_vfio_pci_if(
359             pci=Topology.get_interface_pci_addr(
360                 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
361         )
362
363     def _c_vpp_2vfpt_ip4scale200k_plen30(self, **kwargs):
364         """Instantiate one VM with vpp_2vfpt_ip4scale200k_plen30 configuration.
365
366         :param kwargs: Named parameters.
367         :type kwargs: dict
368         """
369         qemu_id = kwargs[u"qemu_id"]
370         name = kwargs[u"name"]
371
372         self.machines[name] = QemuUtils(
373             node=self.nodes[kwargs[u"node"]],
374             qemu_id=qemu_id,
375             smp=len(self.machines_affinity[name]),
376             mem=4096,
377             vnf=kwargs[u"vnf"],
378             img=Constants.QEMU_VM_KERNEL
379         )
380         self.machines[name].add_default_params()
381         self.machines[name].add_kernelvm_params()
382         if u"DUT1" in name:
383             self.machines[name].configure_kernelvm_vnf(
384                 ip1=u"2.2.2.1/30",
385                 ip2=u"1.1.1.2/30",
386                 route1=u"20.0.0.0/30",
387                 routeif1=u"avf-0/0/6/0",
388                 nexthop1=u"2.2.2.2",
389                 route2=u"10.0.0.0/30",
390                 routeif2=u"avf-0/0/7/0",
391                 nexthop2=u"1.1.1.1",
392                 arpmac1=u"3c:fd:fe:d1:5c:d8",
393                 arpip1=u"1.1.1.1",
394                 arpif1=u"avf-0/0/7/0",
395                 queues=kwargs[u"queues"],
396                 jumbo_frames=kwargs[u"jumbo"]
397             )
398         else:
399             self.machines[name].configure_kernelvm_vnf(
400                 ip1=u"3.3.3.2/30",
401                 ip2=u"2.2.2.2/30",
402                 route1=u"10.0.0.0/30",
403                 routeif1=u"avf-0/0/7/0",
404                 nexthop1=u"2.2.2.1",
405                 route2=u"20.0.0.0/30",
406                 routeif2=u"avf-0/0/6/0",
407                 nexthop2=u"3.3.3.1",
408                 arpmac1=u"3c:fd:fe:d1:5c:d9",
409                 arpip1=u"3.3.3.1",
410                 arpif1=u"avf-0/0/6/0",
411                 queues=kwargs[u"queues"],
412                 jumbo_frames=kwargs[u"jumbo"]
413             )
414         self.machines[name].add_vfio_pci_if(
415             pci=Topology.get_interface_pci_addr(
416                 self.nodes[kwargs[u"node"]], kwargs[u"if2"])
417         )
418         self.machines[name].add_vfio_pci_if(
419             pci=Topology.get_interface_pci_addr(
420                 self.nodes[kwargs[u"node"]], kwargs[u"if1"])
421         )