Separate files needing GPL license
[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         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"/run/vpp/sock-{qemu_id}-1"
66                 sock2 = f"/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_pf1_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_pf2_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                     csum=kwargs[u"enable_csum"], gso=kwargs[u"enable_gso"]
101                 )
102                 self.machines[name].qemu_add_vhost_user_if(
103                     sock2, jumbo_frames=kwargs[u"jumbo"], queues=queues,
104                     queue_size=kwargs[u"perf_qemu_qsz"],
105                     csum=kwargs[u"enable_csum"], gso=kwargs[u"enable_gso"]
106                 )
107
108     def construct_vms_on_all_nodes(self, **kwargs):
109         """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
110
111         :param kwargs: Named parameters.
112         :type kwargs: dict
113         """
114         self.initialize()
115         for node in self.nodes:
116             if self.nodes[node][u"type"] == NodeType.DUT:
117                 self.construct_vms_on_node(node=node, **kwargs)
118
119     def start_all_vms(self, pinning=False):
120         """Start all added VMs in manager.
121
122         :param pinning: If True, then do also QEMU process pinning.
123         :type pinning: bool
124         """
125         for machine, machine_affinity in \
126                 zip(self.machines.values(), self.machines_affinity.values()):
127             machine.qemu_start()
128             if pinning:
129                 machine.qemu_set_affinity(*machine_affinity)
130
131     def kill_all_vms(self, force=False):
132         """Kill all added VMs in manager.
133
134         :param force: Force kill all Qemu instances by pkill qemu if True.
135         :type force: bool
136         """
137         for machine in self.machines.values():
138             if force:
139                 machine.qemu_kill_all()
140             else:
141                 machine.qemu_kill()