Convert existing nf_density testpmd-mac into KernelVM
[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 robot.libraries.BuiltIn import BuiltIn
19
20 from resources.libraries.python.Constants import Constants
21 from resources.libraries.python.CpuUtils import CpuUtils
22 from resources.libraries.python.QemuUtils import QemuUtils
23 from resources.libraries.python.topology import NodeType, Topology
24
25 __all__ = ["QemuManager"]
26
27
28 def get_affinity_vm(nodes, node, nf_chains=1, nf_nodes=1, nf_chain=1, nf_node=1,
29                     cpu_count_int=1, vnf_count_int=1):
30     """Get affinity of VM. Result will be used to compute the amount of
31     CPUs and also affinity.
32
33     :param node: SUT nodes.
34     :param node: DUT node.
35     :param nf_chains: Number of NF chains.
36     :param nf_nodes: Number of NF nodes in chain.
37     :param nf_chain: Chain ID.
38     :param nf_node: Node ID.
39     :param cpu_count_int: Amount of Dataplane threads of vswitch.
40     :param vnf_count_int: Amount of Dataplane threads of vnf.
41     :type nodes: dict
42     :type node: dict
43     :type nf_chains: int
44     :type nf_nodes: int
45     :type nf_chain: int
46     :type nf_node: int
47     :type cpu_count_int: int
48     :type vnf_count_int: int
49     :returns: List of CPUs allocated to VM.
50     :rtype: list
51     """
52     sut_sc = 1
53     dut_mc = 1
54     dut_dc = cpu_count_int
55     skip_cnt = sut_sc + dut_mc + dut_dc
56     dtc = vnf_count_int
57
58     interface_list = []
59     interface_list.append(
60         BuiltIn().get_variable_value('${{{node}_if1}}'.format(node=node)))
61     interface_list.append(
62         BuiltIn().get_variable_value('${{{node}_if2}}'.format(node=node)))
63
64     cpu_node = Topology.get_interfaces_numa_node(nodes[node], *interface_list)
65
66     nf_cpus = CpuUtils.cpu_slice_of_list_for_nf(
67         node=nodes[node], cpu_node=cpu_node, chains=nf_chains,
68         nodeness=nf_nodes, chain_id=nf_chain, node_id=nf_node, mtcr=2, dtcr=1,
69         dtc=dtc, skip_cnt=skip_cnt)
70
71     return nf_cpus
72
73 class QemuManager(object):
74     """QEMU lifecycle management class"""
75
76     # Use one instance of class per tests.
77     ROBOT_LIBRARY_SCOPE = 'TEST CASE'
78
79     def __init__(self, nodes):
80         """Init QemuManager object."""
81         self.machines = None
82         self.machines_affinity = None
83         self.nodes = nodes
84
85     def initialize(self):
86         """Initialize QemuManager object."""
87         self.machines = OrderedDict()
88         self.machines_affinity = OrderedDict()
89
90     def construct_vms_on_node(self, **kwargs):
91         """Construct 1..Mx1..N VMs(s) on node with specified name.
92
93         :param kwargs: Named parameters.
94         :type kwargs: dict
95         """
96         node = kwargs['node']
97         nf_chains = int(kwargs['nf_chains'])
98         nf_nodes = int(kwargs['nf_nodes'])
99         queues = kwargs['rxq_count_int'] if kwargs['auto_scale'] else 1
100         cpu_count_int = kwargs['cpu_count_int']
101         vnf_count_int = kwargs['cpu_count_int'] if kwargs['auto_scale'] else 1
102
103         img = Constants.QEMU_PERF_VM_KERNEL
104
105         for nf_chain in range(1, nf_chains + 1):
106             for nf_node in range(1, nf_nodes + 1):
107                 qemu_id = (nf_chain - 1) * nf_nodes + nf_node
108                 name = '{node}_{qemu_id}'.format(node=node, qemu_id=qemu_id)
109                 sock1 = '/var/run/vpp/sock-{qemu_id}-1'.format(qemu_id=qemu_id)
110                 sock2 = '/var/run/vpp/sock-{qemu_id}-2'.format(qemu_id=qemu_id)
111                 vif1_mac = kwargs['tg_if1_mac'] if nf_node == 1 \
112                         else '52:54:00:00:{id:02x}:02'.format(id=qemu_id - 1)
113                 vif2_mac = kwargs['tg_if2_mac'] if nf_node == nf_nodes \
114                         else '52:54:00:00:{id:02x}:01'.format(id=qemu_id + 1)
115
116                 self.machines_affinity[name] = get_affinity_vm(
117                     nodes=self.nodes, node=node, nf_chains=nf_chains,
118                     nf_nodes=nf_nodes, nf_chain=nf_chain, nf_node=nf_node,
119                     cpu_count_int=cpu_count_int, vnf_count_int=vnf_count_int)
120
121                 self.machines[name] = QemuUtils(
122                     node=self.nodes[node], qemu_id=qemu_id,
123                     smp=len(self.machines_affinity[name]), mem=4096,
124                     vnf=kwargs['vnf'], img=img)
125                 self.machines[name].configure_kernelvm_vnf(
126                     mac1='52:54:00:00:{id:02x}:01'.format(id=qemu_id),
127                     mac2='52:54:00:00:{id:02x}:02'.format(id=qemu_id),
128                     vif1_mac=vif1_mac,
129                     vif2_mac=vif2_mac,
130                     queues=queues,
131                     jumbo_frames=kwargs['jumbo'])
132                 self.machines[name].qemu_add_vhost_user_if(
133                     sock1, jumbo_frames=kwargs['jumbo'], queues=queues,
134                     queue_size=1024)
135                 self.machines[name].qemu_add_vhost_user_if(
136                     sock2, jumbo_frames=kwargs['jumbo'], queues=queues,
137                     queue_size=1024)
138
139     def construct_vms_on_all_nodes(self, **kwargs):
140         """Construct 1..Mx1..N VMs(s) with specified name on all nodes.
141
142         :param kwargs: Named parameters.
143         :type kwargs: dict
144         """
145         self.initialize()
146         for node in self.nodes:
147             if self.nodes[node]['type'] == NodeType.DUT:
148                 self.construct_vms_on_node(node=node, **kwargs)
149
150     def start_all_vms(self, pinning=False):
151         """Start all added VMs in manager.
152
153         :param pinning: If True, then do also QEMU process pinning.
154         :type pinning: bool
155         """
156         for machine, machine_affinity in zip(self.machines.values(),
157                                              self.machines_affinity.values()):
158             machine.qemu_start()
159             if pinning:
160                 machine.qemu_set_affinity(*machine_affinity)
161
162     def set_scheduler_all_vms(self):
163         """Set CFS scheduler policy on all VMs in manager."""
164         for machine in self.machines.values():
165             machine.qemu_set_scheduler_policy()
166
167     def kill_all_vms(self, force=False):
168         """Kill all added VMs in manager.
169
170         :param force: Force kill all Qemu instances by pkill qemu if True.
171         :type force: bool
172         """
173         for machine in self.machines.values():
174             if force:
175                 machine.qemu_kill_all()
176             else:
177                 machine.qemu_kill()