Python3: resources and libraries
[csit.git] / resources / libraries / python / QemuManager.py
1 # Copyright (c) 2019 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         img = Constants.QEMU_VM_KERNEL
60
61         for nf_chain in range(1, nf_chains + 1):
62             for nf_node in range(1, nf_nodes + 1):
63                 qemu_id = (nf_chain - 1) * nf_nodes + nf_node
64                 name = f"{node}_{qemu_id}"
65                 sock1 = f"/var/run/vpp/sock-{qemu_id}-1"
66                 sock2 = f"/var/run/vpp/sock-{qemu_id}-2"
67                 idx1 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2 - 1
68                 vif1_mac = Topology.get_interface_mac(
69                     self.nodes[node], f"vhost{idx1}"
70                 ) if kwargs[u"vnf"] == u"testpmd_mac" \
71                     else kwargs[u"tg_if1_mac"] if nf_node == 1 \
72                     else f"52:54:00:00:{(qemu_id - 1):02x}:02"
73                 idx2 = (nf_chain - 1) * nf_nodes * 2 + nf_node * 2
74                 vif2_mac = Topology.get_interface_mac(
75                     self.nodes[node], f"vhost{idx2}"
76                 ) if kwargs[u"vnf"] == u"testpmd_mac" \
77                     else kwargs[u"tg_if2_mac"] if nf_node == nf_nodes \
78                     else f"52:54:00:00:{(qemu_id + 1):02x}:01"
79
80                 self.machines_affinity[name] = CpuUtils.get_affinity_nf(
81                     nodes=self.nodes, node=node, nf_chains=nf_chains,
82                     nf_nodes=nf_nodes, nf_chain=nf_chain, nf_node=nf_node,
83                     vs_dtc=vs_dtc, nf_dtc=nf_dtc, nf_dtcr=nf_dtcr
84                 )
85
86                 self.machines[name] = QemuUtils(
87                     node=self.nodes[node], qemu_id=qemu_id,
88                     smp=len(self.machines_affinity[name]), mem=4096,
89                     vnf=kwargs[u"vnf"], img=img
90                 )
91                 self.machines[name].configure_kernelvm_vnf(
92                     mac1=f"52:54:00:00:{qemu_id:02x}:01",
93                     mac2=f"52:54:00:00:{qemu_id:02x}:02",
94                     vif1_mac=vif1_mac, vif2_mac=vif2_mac, queues=queues,
95                     jumbo_frames=kwargs[u"jumbo"]
96                 )
97                 self.machines[name].qemu_add_vhost_user_if(
98                     sock1, jumbo_frames=kwargs[u"jumbo"], queues=queues,
99                     queue_size=kwargs[u"perf_qemu_qsz"]
100                 )
101                 self.machines[name].qemu_add_vhost_user_if(
102                     sock2, jumbo_frames=kwargs[u"jumbo"], queues=queues,
103                     queue_size=kwargs[u"perf_qemu_qsz"]
104                 )
105
106     def construct_vms_on_all_nodes(self, **kwargs):
107         """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
108
109         :param kwargs: Named parameters.
110         :type kwargs: dict
111         """
112         self.initialize()
113         for node in self.nodes:
114             if self.nodes[node][u"type"] == NodeType.DUT:
115                 self.construct_vms_on_node(node=node, **kwargs)
116
117     def start_all_vms(self, pinning=False):
118         """Start all added VMs in manager.
119
120         :param pinning: If True, then do also QEMU process pinning.
121         :type pinning: bool
122         """
123         for machine, machine_affinity in \
124                 zip(self.machines.values(), self.machines_affinity.values()):
125             machine.qemu_start()
126             if pinning:
127                 machine.qemu_set_affinity(*machine_affinity)
128
129     def kill_all_vms(self, force=False):
130         """Kill all added VMs in manager.
131
132         :param force: Force kill all Qemu instances by pkill qemu if True.
133         :type force: bool
134         """
135         for machine in self.machines.values():
136             if force:
137                 machine.qemu_kill_all()
138             else:
139                 machine.qemu_kill()