Adding QAT support
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / rapid / rapid_machine.py
1 #!/usr/bin/python
2
3 ##
4 ## Copyright (c) 2020 Intel Corporation
5 ##
6 ## Licensed under the Apache License, Version 2.0 (the "License");
7 ## you may not use this file except in compliance with the License.
8 ## You may obtain a copy of the License at
9 ##
10 ##     http://www.apache.org/licenses/LICENSE-2.0
11 ##
12 ## Unless required by applicable law or agreed to in writing, software
13 ## distributed under the License is distributed on an "AS IS" BASIS,
14 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ## See the License for the specific language governing permissions and
16 ## limitations under the License.
17 ##
18
19 from rapid_log import RapidLog 
20 from prox_ctrl import prox_ctrl
21 import os
22 import re
23 import uuid
24
25 class RapidMachine(object):
26     """
27     Class to deal with a PROX instance (VM, bare metal, container)
28     """
29     def __init__(self, key, user, password, vim, rundir, resultsdir,
30             machine_params, configonly):
31         self.name = machine_params['name']
32         self.ip = machine_params['admin_ip']
33         self.key = key
34         self.user = user
35         self.password = password
36         self.rundir = rundir
37         self.resultsdir = resultsdir
38         self.dp_ports = []
39         self.dpdk_port_index = []
40         self.configonly = configonly
41         index = 1
42         while True:
43             ip_key = 'dp_ip{}'.format(index)
44             mac_key = 'dp_mac{}'.format(index)
45             if ip_key in machine_params.keys():
46                 if mac_key in machine_params.keys():
47                     dp_port = {'ip': machine_params[ip_key], 'mac' : machine_params[mac_key]}
48                 else:
49                     dp_port = {'ip': machine_params[ip_key], 'mac' : None}
50                 self.dp_ports.append(dict(dp_port))
51                 self.dpdk_port_index.append(index - 1)
52                 index += 1
53             else:
54                 break
55         self.machine_params = machine_params
56         self.vim = vim
57         self.cpu_mapping = None
58         if 'config_file' in self.machine_params.keys():
59             PROXConfigfile =  open (self.machine_params['config_file'], 'r')
60             PROXConfig = PROXConfigfile.read()
61             PROXConfigfile.close()
62             self.all_tasks_for_this_cfg = set(re.findall("task\s*=\s*(\d+)",PROXConfig))
63
64     def get_cores(self):
65         return (self.machine_params['cores'])
66
67     def expand_list_format(self, list):
68         """Expand cpuset list format provided as comma-separated list of
69         numbers and ranges of numbers. For more information please see
70         https://man7.org/linux/man-pages/man7/cpuset.7.html
71         """
72         list_expanded = []
73         for num in list.split(','):
74             if '-' in num:
75                 num_range = num.split('-')
76                 list_expanded += range(int(num_range[0]), int(num_range[1]) + 1)
77             else:
78                 list_expanded.append(int(num))
79         return list_expanded
80
81     def read_cpuset(self):
82         """Read list of cpus on which we allowed to execute
83         """
84         cpu_set_file = '/sys/fs/cgroup/cpuset.cpus'
85         cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
86         if (self._client.run_cmd(cmd).decode().rstrip()):
87             cmd = 'cat {}'.format(cpu_set_file)
88         else:
89             cpu_set_file = '/sys/fs/cgroup/cpuset/cpuset.cpus'
90             cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
91             if (self._client.run_cmd(cmd).decode().rstrip()):
92                 cmd = 'cat {}'.format(cpu_set_file)
93             else:
94                 RapidLog.critical('{Cannot determine cpuset')
95         cpuset_cpus = self._client.run_cmd(cmd).decode().rstrip()
96         RapidLog.debug('{} ({}): Allocated cpuset: {}'.format(self.name, self.ip, cpuset_cpus))
97         self.cpu_mapping = self.expand_list_format(cpuset_cpus)
98         RapidLog.debug('{} ({}): Expanded cpuset: {}'.format(self.name, self.ip, self.cpu_mapping))
99
100         # Log CPU core mapping for user information
101         cpu_mapping_str = ''
102         for i in range(len(self.cpu_mapping)):
103             cpu_mapping_str = cpu_mapping_str + '[' + str(i) + '->' + str(self.cpu_mapping[i]) + '], '
104         cpu_mapping_str = cpu_mapping_str[:-2]
105         RapidLog.debug('{} ({}): CPU mapping: {}'.format(self.name, self.ip, cpu_mapping_str))
106
107     def remap_cpus(self, cpus):
108         """Convert relative cpu ids provided as function parameter to match
109         cpu ids from allocated list
110         """
111         cpus_remapped = []
112         for cpu in cpus:
113             cpus_remapped.append(self.cpu_mapping[cpu])
114         return cpus_remapped
115
116     def remap_all_cpus(self):
117         """Convert relative cpu ids for different parameters (mcore, cores)
118         """
119         if self.cpu_mapping is None:
120             RapidLog.debug('{} ({}): cpu mapping is not defined! Please check the configuration!'.format(self.name, self.ip))
121             return
122
123         if 'mcore' in self.machine_params.keys():
124             cpus_remapped = self.remap_cpus(self.machine_params['mcore'])
125             RapidLog.debug('{} ({}): mcore {} remapped to {}'.format(self.name, self.ip, self.machine_params['mcore'], cpus_remapped))
126             self.machine_params['mcore'] = cpus_remapped
127
128         if 'cores' in self.machine_params.keys():
129             cpus_remapped = self.remap_cpus(self.machine_params['cores'])
130             RapidLog.debug('{} ({}): cores {} remapped to {}'.format(self.name, self.ip, self.machine_params['cores'], cpus_remapped))
131             self.machine_params['cores'] = cpus_remapped
132
133     def devbind(self):
134         # Script to bind the right network interface to the poll mode driver
135         for index, dp_port in enumerate(self.dp_ports, start = 1):
136             DevBindFileName = self.rundir + '/devbind-{}-port{}.sh'.format(self.ip, index)
137             self._client.scp_put('./devbind.sh', DevBindFileName)
138             cmd =  'sed -i \'s/MACADDRESS/' + dp_port['mac'] + '/\' ' + DevBindFileName 
139             result = self._client.run_cmd(cmd)
140             RapidLog.debug('devbind.sh MAC updated for port {} on {} {}'.format(index, self.name, result))
141             if ((not self.configonly) and self.machine_params['prox_launch_exit']):
142                 result = self._client.run_cmd(DevBindFileName)
143                 RapidLog.debug('devbind.sh running for port {} on {} {}'.format(index, self.name, result))
144
145     def generate_lua(self, appendix = ''):
146         self.LuaFileName = 'parameters-{}.lua'.format(self.ip)
147         with open(self.LuaFileName, "w") as LuaFile:
148             LuaFile.write('require "helper"\n')
149             LuaFile.write('name="%s"\n'% self.name)
150             for index, dp_port in enumerate(self.dp_ports, start = 1):
151                 LuaFile.write('local_ip{}="{}"\n'.format(index, dp_port['ip']))
152                 LuaFile.write('local_hex_ip{}=convertIPToHex(local_ip{})\n'.format(index, index))
153             if self.vim in ['kubernetes']:
154                 cmd = 'cat /opt/rapid/dpdk_version'
155                 dpdk_version = self._client.run_cmd(cmd).decode().rstrip()
156                 if (dpdk_version >= '20.11.0'):
157                     allow_parameter = 'allow'
158                 else:
159                     allow_parameter = 'pci-whitelist'
160                 eal_line = 'eal=\"--file-prefix {}{} --{} {} --force-max-simd-bitwidth=512'.format(
161                         self.name, str(uuid.uuid4()), allow_parameter,
162                         self.machine_params['dp_pci_dev'])
163                 looking_for_qat = True
164                 index = 0
165                 while (looking_for_qat):
166                     if  'qat_pci_dev{}'.format(index) in self.machine_params:
167                         eal_line += ' --{} {}'.format(allow_parameter,
168                             self.machine_params['qat_pci_dev{}'.format(index)])
169                         index += 1
170                     else:
171                         looking_for_qat = False
172                         eal_line += '"\n'
173                 LuaFile.write(eal_line)
174             else:
175                 LuaFile.write("eal=\"\"\n")
176             if 'mcore' in self.machine_params.keys():
177                 LuaFile.write('mcore="%s"\n'% ','.join(map(str,
178                     self.machine_params['mcore'])))
179             if 'cores' in self.machine_params.keys():
180                 LuaFile.write('cores="%s"\n'% ','.join(map(str,
181                     self.machine_params['cores'])))
182             if 'ports' in self.machine_params.keys():
183                 LuaFile.write('ports="%s"\n'% ','.join(map(str,
184                     self.machine_params['ports'])))
185             if 'dest_ports' in self.machine_params.keys():
186                 for index, dest_port in enumerate(self.machine_params['dest_ports'], start = 1):
187                     LuaFile.write('dest_ip{}="{}"\n'.format(index, dest_port['ip']))
188                     LuaFile.write('dest_hex_ip{}=convertIPToHex(dest_ip{})\n'.format(index, index))
189                     if dest_port['mac']:
190                         LuaFile.write('dest_hex_mac{}="{}"\n'.format(index ,
191                             dest_port['mac'].replace(':',' ')))
192             if 'gw_vm' in self.machine_params.keys():
193                 for index, gw_ip in enumerate(self.machine_params['gw_ips'],
194                         start = 1):
195                     LuaFile.write('gw_ip{}="{}"\n'.format(index, gw_ip))
196                     LuaFile.write('gw_hex_ip{}=convertIPToHex(gw_ip{})\n'.
197                             format(index, index))
198             LuaFile.write(appendix)
199         self._client.scp_put(self.LuaFileName, self.rundir + '/parameters.lua')
200         self._client.scp_put('helper.lua', self.rundir + '/helper.lua')
201
202     def start_prox(self, autostart=''):
203         if self.machine_params['prox_socket']:
204             self._client = prox_ctrl(self.ip, self.key, self.user,
205                     self.password)
206             self._client.test_connection()
207             if self.vim in ['OpenStack']:
208                 self.devbind()
209             if self.vim in ['kubernetes']:
210                 self.read_cpuset()
211                 self.remap_all_cpus()
212             _, prox_config_file_name = os.path.split(self.
213                     machine_params['config_file'])
214             if self.machine_params['prox_launch_exit']:
215                 self.generate_lua()
216                 self._client.scp_put(self.machine_params['config_file'], '{}/{}'.
217                         format(self.rundir, prox_config_file_name))
218                 if not self.configonly:
219                     cmd = 'sudo {}/prox {} -t -o cli -f {}/{}'.format(self.rundir,
220                             autostart, self.rundir, prox_config_file_name)
221                     RapidLog.debug("Starting PROX on {}: {}".format(self.name,
222                         cmd))
223                     result = self._client.run_cmd(cmd)
224                     RapidLog.debug("Finished PROX on {}: {}".format(self.name,
225                         cmd))
226
227     def close_prox(self):
228         if (not self.configonly) and self.machine_params[
229                 'prox_socket'] and self.machine_params['prox_launch_exit']:
230             self.socket.quit_prox()
231             self._client.scp_get('/prox.log', '{}/{}.prox.log'.format(
232                 self.resultsdir, self.name))
233
234     def connect_prox(self):
235         if self.machine_params['prox_socket']:
236            self.socket = self._client.connect_socket()
237
238     def start(self):
239         self.socket.start(self.get_cores())
240
241     def stop(self):
242         self.socket.stop(self.get_cores())
243
244     def reset_stats(self):
245         self.socket.reset_stats()
246
247     def core_stats(self):
248         return (self.socket.core_stats(self.get_cores(), self.all_tasks_for_this_cfg))
249
250     def multi_port_stats(self):
251         return (self.socket.multi_port_stats(self.dpdk_port_index))