4 ## Copyright (c) 2020 Intel Corporation
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
10 ## http://www.apache.org/licenses/LICENSE-2.0
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.
19 from rapid_log import RapidLog
20 from prox_ctrl import prox_ctrl
24 class RapidMachine(object):
26 Class to deal with a PROX instance (VM, bare metal, container)
28 def __init__(self, key, user, password, vim, rundir, resultsdir,
29 machine_params, configonly):
30 self.name = machine_params['name']
31 self.ip = machine_params['admin_ip']
34 self.password = password
36 self.resultsdir = resultsdir
38 self.dpdk_port_index = []
39 self.configonly = configonly
42 ip_key = 'dp_ip{}'.format(index)
43 mac_key = 'dp_mac{}'.format(index)
44 if ip_key in machine_params.keys():
45 if mac_key in machine_params.keys():
46 dp_port = {'ip': machine_params[ip_key],
47 'mac' : machine_params[mac_key]}
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)
55 self.machine_params = machine_params
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+)",
66 return (self.machine_params['cores'])
68 def expand_list_format(self, list):
69 """Expand cpuset list format provided as comma-separated list of
70 numbers and ranges of numbers. For more information please see
71 https://man7.org/linux/man-pages/man7/cpuset.7.html
74 for num in list.split(','):
76 num_range = num.split('-')
77 list_expanded += range(int(num_range[0]), int(num_range[1]) + 1)
79 list_expanded.append(int(num))
82 def read_cpuset(self):
83 """Read list of cpus on which we allowed to execute
85 cpu_set_file = '/sys/fs/cgroup/cpuset.cpus'
86 cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
87 if (self._client.run_cmd(cmd).decode().rstrip()):
88 cmd = 'cat {}'.format(cpu_set_file)
90 cpu_set_file = '/sys/fs/cgroup/cpuset/cpuset.cpus'
91 cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
92 if (self._client.run_cmd(cmd).decode().rstrip()):
93 cmd = 'cat {}'.format(cpu_set_file)
95 RapidLog.critical('{Cannot determine cpuset')
96 cpuset_cpus = self._client.run_cmd(cmd).decode().rstrip()
97 RapidLog.debug('{} ({}): Allocated cpuset: {}'.format(self.name,
98 self.ip, cpuset_cpus))
99 self.cpu_mapping = self.expand_list_format(cpuset_cpus)
100 RapidLog.debug('{} ({}): Expanded cpuset: {}'.format(self.name,
101 self.ip, self.cpu_mapping))
103 # Log CPU core mapping for user information
105 for i in range(len(self.cpu_mapping)):
106 cpu_mapping_str = cpu_mapping_str + '[' + str(i) + '->' + str(self.cpu_mapping[i]) + '], '
107 cpu_mapping_str = cpu_mapping_str[:-2]
108 RapidLog.debug('{} ({}): CPU mapping: {}'.format(self.name, self.ip,
111 def remap_cpus(self, cpus):
112 """Convert relative cpu ids provided as function parameter to match
113 cpu ids from allocated list
117 cpus_remapped.append(self.cpu_mapping[cpu])
120 def remap_all_cpus(self):
121 """Convert relative cpu ids for different parameters (mcore, cores)
123 if self.cpu_mapping is None:
124 RapidLog.debug('{} ({}): cpu mapping is not defined! Please check the configuration!'.format(self.name, self.ip))
127 if 'mcore' in self.machine_params.keys():
128 cpus_remapped = self.remap_cpus(self.machine_params['mcore'])
129 RapidLog.debug('{} ({}): mcore {} remapped to {}'.format(self.name,
130 self.ip, self.machine_params['mcore'], cpus_remapped))
131 self.machine_params['mcore'] = cpus_remapped
133 if 'cores' in self.machine_params.keys():
134 cpus_remapped = self.remap_cpus(self.machine_params['cores'])
135 RapidLog.debug('{} ({}): cores {} remapped to {}'.format(self.name,
136 self.ip, self.machine_params['cores'], cpus_remapped))
137 self.machine_params['cores'] = cpus_remapped
140 # Script to bind the right network interface to the poll mode driver
141 for index, dp_port in enumerate(self.dp_ports, start = 1):
142 DevBindFileName = self.rundir + '/devbind-{}-port{}.sh'.format(self.ip, index)
143 self._client.scp_put('./devbind.sh', DevBindFileName)
144 cmd = 'sed -i \'s/MACADDRESS/' + dp_port['mac'] + '/\' ' + DevBindFileName
145 result = self._client.run_cmd(cmd)
146 RapidLog.debug('devbind.sh MAC updated for port {} on {} {}'.format(index, self.name, result))
147 if ((not self.configonly) and self.machine_params['prox_launch_exit']):
148 result = self._client.run_cmd(DevBindFileName)
149 RapidLog.debug('devbind.sh running for port {} on {} {}'.format(index, self.name, result))
151 def generate_lua(self, appendix = ''):
152 self.LuaFileName = 'parameters-{}.lua'.format(self.ip)
153 with open(self.LuaFileName, "w") as LuaFile:
154 LuaFile.write('require "helper"\n')
155 LuaFile.write('name="%s"\n'% self.name)
156 for index, dp_port in enumerate(self.dp_ports, start = 1):
157 LuaFile.write('local_ip{}="{}"\n'.format(index, dp_port['ip']))
158 LuaFile.write('local_hex_ip{}=convertIPToHex(local_ip{})\n'.format(index, index))
159 if self.vim in ['kubernetes']:
160 cmd = 'pkg-config --modversion libdpdk'
161 dpdk_version = self._client.run_cmd(cmd).decode().rstrip()
162 if (dpdk_version >= '20.11.0'):
163 allow_parameter = 'allow'
165 allow_parameter = 'pci-whitelist'
166 eal_line = 'eal=\"--file-prefix {} --{} {}\"\n'.format(
167 self.name, allow_parameter,
168 self.machine_params['dp_pci_dev'])
169 LuaFile.write(eal_line)
171 LuaFile.write("eal=\"\"\n")
172 if 'mcore' in self.machine_params.keys():
173 LuaFile.write('mcore="%s"\n'% ','.join(map(str, self.machine_params['mcore'])))
174 if 'cores' in self.machine_params.keys():
175 LuaFile.write('cores="%s"\n'% ','.join(map(str, self.machine_params['cores'])))
176 if 'ports' in self.machine_params.keys():
177 LuaFile.write('ports="%s"\n'% ','.join(map(str, self.machine_params['ports'])))
178 if 'dest_ports' in self.machine_params.keys():
179 for index, dest_port in enumerate(self.machine_params['dest_ports'], start = 1):
180 LuaFile.write('dest_ip{}="{}"\n'.format(index, dest_port['ip']))
181 LuaFile.write('dest_hex_ip{}=convertIPToHex(dest_ip{})\n'.format(index, index))
183 LuaFile.write('dest_hex_mac{}="{}"\n'.format(index,
184 dest_port['mac'].replace(':',' ')))
185 if 'gw_vm' in self.machine_params.keys():
186 for index, gw_ip in enumerate(self.machine_params['gw_ips'],
188 LuaFile.write('gw_ip{}="{}"\n'.format(index, gw_ip))
189 LuaFile.write('gw_hex_ip{}=convertIPToHex(gw_ip{})\n'.
190 format(index, index))
191 LuaFile.write(appendix)
192 self._client.scp_put(self.LuaFileName, self.rundir + '/parameters.lua')
193 self._client.scp_put('helper.lua', self.rundir + '/helper.lua')
195 def start_prox(self, autostart=''):
196 if self.machine_params['prox_socket']:
197 self._client = prox_ctrl(self.ip, self.key, self.user,
199 self._client.test_connection()
200 if self.vim in ['OpenStack']:
202 if self.vim in ['kubernetes']:
204 self.remap_all_cpus()
205 _, prox_config_file_name = os.path.split(self.
206 machine_params['config_file'])
207 if self.machine_params['prox_launch_exit']:
209 self._client.scp_put(self.machine_params['config_file'], '{}/{}'.
210 format(self.rundir, prox_config_file_name))
211 if not self.configonly:
212 cmd = 'sudo {}/prox {} -t -o cli -f {}/{}'.format(self.rundir,
213 autostart, self.rundir, prox_config_file_name)
214 RapidLog.debug("Starting PROX on {}: {}".format(self.name,
216 result = self._client.run_cmd(cmd)
217 RapidLog.debug("Finished PROX on {}: {}".format(self.name,
220 def close_prox(self):
221 if (not self.configonly) and self.machine_params[
222 'prox_socket'] and self.machine_params['prox_launch_exit']:
223 self.socket.quit_prox()
224 self._client.scp_get('/prox.log', '{}/{}.prox.log'.format(
225 self.resultsdir, self.name))
227 def connect_prox(self):
228 if self.machine_params['prox_socket']:
229 self.socket = self._client.connect_socket()
232 self.socket.start(self.get_cores())
235 self.socket.stop(self.get_cores())
237 def reset_stats(self):
238 self.socket.reset_stats()
240 def core_stats(self):
241 return (self.socket.core_stats(self.get_cores(), self.all_tasks_for_this_cfg))
243 def multi_port_stats(self):
244 return (self.socket.multi_port_stats(self.dpdk_port_index))