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() and mac_key in machine_params.keys():
45 dp_port = {'ip': machine_params[ip_key], 'mac' : machine_params[mac_key]}
46 self.dp_ports.append(dict(dp_port))
47 self.dpdk_port_index.append(index - 1)
51 self.machine_params = machine_params
53 self.cpu_mapping = None
54 self.numa_nodes = [ 0 ]
55 self.socket_mem_mb = '512'
56 if 'config_file' in self.machine_params.keys():
57 PROXConfigfile = open (self.machine_params['config_file'], 'r')
58 PROXConfig = PROXConfigfile.read()
59 PROXConfigfile.close()
60 self.all_tasks_for_this_cfg = set(re.findall("task\s*=\s*(\d+)",PROXConfig))
63 return (self.machine_params['cores'])
65 def expand_list_format(self, list):
66 """Expand cpuset list format provided as comma-separated list of
67 numbers and ranges of numbers. For more information please see
68 https://man7.org/linux/man-pages/man7/cpuset.7.html
71 for num in list.split(','):
73 num_range = num.split('-')
74 list_expanded += range(int(num_range[0]), int(num_range[1]) + 1)
76 list_expanded.append(int(num))
79 def read_cpuset(self):
80 """Read list of cpus on which we allowed to execute
82 cmd = 'cat /sys/fs/cgroup/cpuset/cpuset.cpus'
83 cpuset_cpus = self._client.run_cmd(cmd).decode().rstrip()
84 RapidLog.debug('{} ({}): Allocated cpuset: {}'.format(self.name, self.ip, cpuset_cpus))
85 self.cpu_mapping = self.expand_list_format(cpuset_cpus)
86 RapidLog.debug('{} ({}): Expanded cpuset: {}'.format(self.name, self.ip, self.cpu_mapping))
88 # Log CPU core mapping for user information
90 for i in range(len(self.cpu_mapping)):
91 cpu_mapping_str = cpu_mapping_str + '[' + str(i) + '->' + str(self.cpu_mapping[i]) + '], '
92 cpu_mapping_str = cpu_mapping_str[:-2]
93 RapidLog.debug('{} ({}): CPU mapping: {}'.format(self.name, self.ip, cpu_mapping_str))
95 def remap_cpus(self, cpus):
96 """Convert relative cpu ids provided as function parameter to match
97 cpu ids from allocated list
101 cpus_remapped.append(self.cpu_mapping[cpu])
104 def remap_all_cpus(self):
105 """Convert relative cpu ids for different parameters (mcore, cores)
107 if self.cpu_mapping is None:
108 RapidLog.debug('{} ({}): cpu mapping is not defined! Please check the configuration!'.format(self.name, self.ip))
111 if 'mcore' in self.machine_params.keys():
112 cpus_remapped = self.remap_cpus(self.machine_params['mcore'])
113 RapidLog.debug('{} ({}): mcore {} remapped to {}'.format(self.name, self.ip, self.machine_params['mcore'], cpus_remapped))
114 self.machine_params['mcore'] = cpus_remapped
116 if 'cores' in self.machine_params.keys():
117 cpus_remapped = self.remap_cpus(self.machine_params['cores'])
118 RapidLog.debug('{} ({}): cores {} remapped to {}'.format(self.name, self.ip, self.machine_params['cores'], cpus_remapped))
119 self.machine_params['cores'] = cpus_remapped
121 def read_cpuset_mems(self):
122 """Read list of NUMA nodes on which we allowed to allocate memory
124 cmd = 'cat /sys/fs/cgroup/cpuset/cpuset.mems'
125 cpuset_mems = self._client.run_cmd(cmd).decode().rstrip()
126 RapidLog.debug('{} ({}): Allowed NUMA nodes: {}'.format(self.name, self.ip, cpuset_mems))
127 self.numa_nodes = self.expand_list_format(cpuset_mems)
128 RapidLog.debug('{} ({}): Expanded allowed NUMA nodes: {}'.format(self.name, self.ip, self.numa_nodes))
130 def get_prox_socket_mem_str(self):
132 for node in range(self.numa_nodes[-1] + 1):
133 if node in self.numa_nodes:
134 socket_mem_str += self.socket_mem_mb + ','
136 socket_mem_str += '0,'
137 socket_mem_str = socket_mem_str[:-1]
138 return socket_mem_str
141 # Script to bind the right network interface to the poll mode driver
142 for index, dp_port in enumerate(self.dp_ports, start = 1):
143 DevBindFileName = self.rundir + '/devbind-{}-port{}.sh'.format(self.ip, index)
144 self._client.scp_put('./devbind.sh', DevBindFileName)
145 cmd = 'sed -i \'s/MACADDRESS/' + dp_port['mac'] + '/\' ' + DevBindFileName
146 result = self._client.run_cmd(cmd)
147 RapidLog.debug('devbind.sh MAC updated for port {} on {} {}'.format(index, self.name, result))
148 if ((not self.configonly) and self.machine_params['prox_launch_exit']):
149 result = self._client.run_cmd(DevBindFileName)
150 RapidLog.debug('devbind.sh running for port {} on {} {}'.format(index, self.name, result))
152 def generate_lua(self, appendix = ''):
153 self.LuaFileName = 'parameters-{}.lua'.format(self.ip)
154 with open(self.LuaFileName, "w") as LuaFile:
155 LuaFile.write('require "helper"\n')
156 LuaFile.write('name="%s"\n'% self.name)
157 for index, dp_port in enumerate(self.dp_ports, start = 1):
158 LuaFile.write('local_ip{}="{}"\n'.format(index, dp_port['ip']))
159 LuaFile.write('local_hex_ip{}=convertIPToHex(local_ip{})\n'.format(index, index))
160 if self.vim in ['kubernetes']:
161 socket_mem_str = self.get_prox_socket_mem_str()
162 RapidLog.debug('{} ({}): PROX socket mem str: {}'.format(self.name, self.ip, socket_mem_str))
163 LuaFile.write("eal=\"--socket-mem=%s --file-prefix %s --pci-whitelist %s\"\n" % (socket_mem_str, self.name, self.machine_params['dp_pci_dev']))
165 LuaFile.write("eal=\"\"\n")
166 if 'mcore' in self.machine_params.keys():
167 LuaFile.write('mcore="%s"\n'% ','.join(map(str, self.machine_params['mcore'])))
168 if 'cores' in self.machine_params.keys():
169 LuaFile.write('cores="%s"\n'% ','.join(map(str, self.machine_params['cores'])))
170 if 'ports' in self.machine_params.keys():
171 LuaFile.write('ports="%s"\n'% ','.join(map(str, self.machine_params['ports'])))
172 if 'dest_ports' in self.machine_params.keys():
173 for index, dest_port in enumerate(self.machine_params['dest_ports'], start = 1):
174 LuaFile.write('dest_ip{}="{}"\n'.format(index, dest_port['ip']))
175 LuaFile.write('dest_hex_ip{}=convertIPToHex(dest_ip{})\n'.format(index, index))
176 LuaFile.write('dest_hex_mac{}="{}"\n'.format(index , dest_port['mac'].replace(':',' ')))
177 if 'gw_vm' in self.machine_params.keys():
178 for index, gw_ip in enumerate(self.machine_params['gw_ips'],
180 LuaFile.write('gw_ip{}="{}"\n'.format(index, gw_ip))
181 LuaFile.write('gw_hex_ip{}=convertIPToHex(gw_ip{})\n'.
182 format(index, index))
183 LuaFile.write(appendix)
184 self._client.scp_put(self.LuaFileName, self.rundir + '/parameters.lua')
185 self._client.scp_put('helper.lua', self.rundir + '/helper.lua')
187 def start_prox(self, autostart=''):
188 if self.machine_params['prox_socket']:
189 self._client = prox_ctrl(self.ip, self.key, self.user,
191 self._client.test_connection()
192 if self.vim in ['OpenStack']:
194 if self.vim in ['kubernetes']:
196 self.read_cpuset_mems()
197 self.remap_all_cpus()
198 _, prox_config_file_name = os.path.split(self.
199 machine_params['config_file'])
201 self._client.scp_put(self.machine_params['config_file'], '{}/{}'.
202 format(self.rundir, prox_config_file_name))
203 if ((not self.configonly) and
204 self.machine_params['prox_launch_exit']):
205 cmd = 'sudo {}/prox {} -t -o cli -f {}/{}'.format(self.rundir,
206 autostart, self.rundir, prox_config_file_name)
207 RapidLog.debug("Starting PROX on {}: {}".format(self.name,
209 result = self._client.run_cmd(cmd)
210 RapidLog.debug("Finished PROX on {}: {}".format(self.name,
213 def close_prox(self):
214 if (not self.configonly) and self.machine_params[
215 'prox_socket'] and self.machine_params['prox_launch_exit']:
216 self.socket.quit_prox()
217 self._client.scp_get('/prox.log', '{}/{}.prox.log'.format(
218 self.resultsdir, self.name))
220 def connect_prox(self):
221 if self.machine_params['prox_socket']:
222 self.socket = self._client.connect_socket()
225 self.socket.start(self.get_cores())
228 self.socket.stop(self.get_cores())
230 def reset_stats(self):
231 self.socket.reset_stats()
233 def core_stats(self):
234 return (self.socket.core_stats(self.get_cores(), self.all_tasks_for_this_cfg))
236 def multi_port_stats(self):
237 return (self.socket.multi_port_stats(self.dpdk_port_index))