Optional MAC address and other changes
[samplevnf.git] / VNFs / DPPD-PROX / helper-scripts / rapid / rapid_machine.py
index 4a0bcb8..352561d 100644 (file)
 
 from rapid_log import RapidLog 
 from prox_ctrl import prox_ctrl
+import os
 import re
 
 class RapidMachine(object):
     """
     Class to deal with a PROX instance (VM, bare metal, container)
     """
-    def __init__(self, key, user, vim, rundir, machine_params):
+    def __init__(self, key, user, password, vim, rundir, resultsdir,
+            machine_params, configonly):
         self.name = machine_params['name']
         self.ip = machine_params['admin_ip']
         self.key = key
         self.user = user
+        self.password = password
         self.rundir = rundir
+        self.resultsdir = resultsdir
         self.dp_ports = []
         self.dpdk_port_index = []
+        self.configonly = configonly
         index = 1
         while True:
             ip_key = 'dp_ip{}'.format(index)
             mac_key = 'dp_mac{}'.format(index)
-            if ip_key in machine_params.keys() and mac_key in machine_params.keys():
-                dp_port = {'ip': machine_params[ip_key], 'mac' : machine_params[mac_key]}
+            if ip_key in machine_params.keys():
+                if mac_key in machine_params.keys():
+                    dp_port = {'ip': machine_params[ip_key],
+                            'mac' : machine_params[mac_key]}
+                else:
+                    dp_port = {'ip': machine_params[ip_key], 'mac' : None}
                 self.dp_ports.append(dict(dp_port))
                 self.dpdk_port_index.append(index - 1)
                 index += 1
             else:
                 break
-        self.rundir = rundir
         self.machine_params = machine_params
         self.vim = vim
-
-    def __del__(self):
-        if self.machine_params['prox_socket']:
-            self._client.scp_get('/prox.log', './{}.prox.log'.format(self.name))
+        self.cpu_mapping = None
+        if 'config_file' in self.machine_params.keys():
+            PROXConfigfile =  open (self.machine_params['config_file'], 'r')
+            PROXConfig = PROXConfigfile.read()
+            PROXConfigfile.close()
+            self.all_tasks_for_this_cfg = set(re.findall("task\s*=\s*(\d+)",
+                PROXConfig))
 
     def get_cores(self):
         return (self.machine_params['cores'])
 
-    def devbind(self, configonly):
+    def expand_list_format(self, list):
+        """Expand cpuset list format provided as comma-separated list of
+        numbers and ranges of numbers. For more information please see
+        https://man7.org/linux/man-pages/man7/cpuset.7.html
+        """
+        list_expanded = []
+        for num in list.split(','):
+            if '-' in num:
+                num_range = num.split('-')
+                list_expanded += range(int(num_range[0]), int(num_range[1]) + 1)
+            else:
+                list_expanded.append(int(num))
+        return list_expanded
+
+    def read_cpuset(self):
+        """Read list of cpus on which we allowed to execute
+        """
+        cpu_set_file = '/sys/fs/cgroup/cpuset.cpus'
+        cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
+        if (self._client.run_cmd(cmd).decode().rstrip()):
+            cmd = 'cat {}'.format(cpu_set_file)
+        else:
+            cpu_set_file = '/sys/fs/cgroup/cpuset/cpuset.cpus'
+            cmd = 'test -e {0} && echo exists'.format(cpu_set_file)
+            if (self._client.run_cmd(cmd).decode().rstrip()):
+                cmd = 'cat {}'.format(cpu_set_file)
+            else:
+                RapidLog.critical('{Cannot determine cpuset')
+        cpuset_cpus = self._client.run_cmd(cmd).decode().rstrip()
+        RapidLog.debug('{} ({}): Allocated cpuset: {}'.format(self.name,
+            self.ip, cpuset_cpus))
+        self.cpu_mapping = self.expand_list_format(cpuset_cpus)
+        RapidLog.debug('{} ({}): Expanded cpuset: {}'.format(self.name,
+            self.ip, self.cpu_mapping))
+
+        # Log CPU core mapping for user information
+        cpu_mapping_str = ''
+        for i in range(len(self.cpu_mapping)):
+            cpu_mapping_str = cpu_mapping_str + '[' + str(i) + '->' + str(self.cpu_mapping[i]) + '], '
+        cpu_mapping_str = cpu_mapping_str[:-2]
+        RapidLog.debug('{} ({}): CPU mapping: {}'.format(self.name, self.ip,
+            cpu_mapping_str))
+
+    def remap_cpus(self, cpus):
+        """Convert relative cpu ids provided as function parameter to match
+        cpu ids from allocated list
+        """
+        cpus_remapped = []
+        for cpu in cpus:
+            cpus_remapped.append(self.cpu_mapping[cpu])
+        return cpus_remapped
+
+    def remap_all_cpus(self):
+        """Convert relative cpu ids for different parameters (mcore, cores)
+        """
+        if self.cpu_mapping is None:
+            RapidLog.debug('{} ({}): cpu mapping is not defined! Please check the configuration!'.format(self.name, self.ip))
+            return
+
+        if 'mcore' in self.machine_params.keys():
+            cpus_remapped = self.remap_cpus(self.machine_params['mcore'])
+            RapidLog.debug('{} ({}): mcore {} remapped to {}'.format(self.name,
+                self.ip, self.machine_params['mcore'], cpus_remapped))
+            self.machine_params['mcore'] = cpus_remapped
+
+        if 'cores' in self.machine_params.keys():
+            cpus_remapped = self.remap_cpus(self.machine_params['cores'])
+            RapidLog.debug('{} ({}): cores {} remapped to {}'.format(self.name,
+                self.ip, self.machine_params['cores'], cpus_remapped))
+            self.machine_params['cores'] = cpus_remapped
+
+    def devbind(self):
         # Script to bind the right network interface to the poll mode driver
         for index, dp_port in enumerate(self.dp_ports, start = 1):
             DevBindFileName = self.rundir + '/devbind-{}-port{}.sh'.format(self.ip, index)
@@ -62,15 +144,11 @@ class RapidMachine(object):
             cmd =  'sed -i \'s/MACADDRESS/' + dp_port['mac'] + '/\' ' + DevBindFileName 
             result = self._client.run_cmd(cmd)
             RapidLog.debug('devbind.sh MAC updated for port {} on {} {}'.format(index, self.name, result))
-            if ((not configonly) and self.machine_params['prox_launch_exit']):
+            if ((not self.configonly) and self.machine_params['prox_launch_exit']):
                 result = self._client.run_cmd(DevBindFileName)
                 RapidLog.debug('devbind.sh running for port {} on {} {}'.format(index, self.name, result))
 
-    def generate_lua(self, vim, appendix = ''):
-        PROXConfigfile =  open (self.machine_params['config_file'], 'r')
-        PROXConfig = PROXConfigfile.read()
-        PROXConfigfile.close()
-        self.all_tasks_for_this_cfg = set(re.findall("task\s*=\s*(\d+)",PROXConfig))
+    def generate_lua(self, appendix = ''):
         self.LuaFileName = 'parameters-{}.lua'.format(self.ip)
         with open(self.LuaFileName, "w") as LuaFile:
             LuaFile.write('require "helper"\n')
@@ -78,10 +156,21 @@ class RapidMachine(object):
             for index, dp_port in enumerate(self.dp_ports, start = 1):
                 LuaFile.write('local_ip{}="{}"\n'.format(index, dp_port['ip']))
                 LuaFile.write('local_hex_ip{}=convertIPToHex(local_ip{})\n'.format(index, index))
-            if vim in ['kubernetes']:
-                LuaFile.write("eal=\"--socket-mem=512,0 --file-prefix %s --pci-whitelist %s\"\n" % (self.name, self.machine_params['dp_pci_dev']))
+            if self.vim in ['kubernetes']:
+                cmd = 'pkg-config --modversion libdpdk'
+                dpdk_version = self._client.run_cmd(cmd).decode().rstrip()
+                if (dpdk_version >= '20.11.0'):
+                    allow_parameter = 'allow'
+                else:
+                    allow_parameter = 'pci-whitelist'
+                eal_line = 'eal=\"--file-prefix {} --{} {}\"\n'.format(
+                        self.name, allow_parameter,
+                        self.machine_params['dp_pci_dev'])
+                LuaFile.write(eal_line)
             else:
                 LuaFile.write("eal=\"\"\n")
+            if 'mcore' in self.machine_params.keys():
+                LuaFile.write('mcore="%s"\n'% ','.join(map(str, self.machine_params['mcore'])))
             if 'cores' in self.machine_params.keys():
                 LuaFile.write('cores="%s"\n'% ','.join(map(str, self.machine_params['cores'])))
             if 'ports' in self.machine_params.keys():
@@ -90,29 +179,50 @@ class RapidMachine(object):
                 for index, dest_port in enumerate(self.machine_params['dest_ports'], start = 1):
                     LuaFile.write('dest_ip{}="{}"\n'.format(index, dest_port['ip']))
                     LuaFile.write('dest_hex_ip{}=convertIPToHex(dest_ip{})\n'.format(index, index))
-                    LuaFile.write('dest_hex_mac{}="{}"\n'.format(index , dest_port['mac'].replace(':',' ')))
+                    if dest_port['mac']:
+                        LuaFile.write('dest_hex_mac{}="{}"\n'.format(index,
+                            dest_port['mac'].replace(':',' ')))
+            if 'gw_vm' in self.machine_params.keys():
+                for index, gw_ip in enumerate(self.machine_params['gw_ips'],
+                        start = 1):
+                    LuaFile.write('gw_ip{}="{}"\n'.format(index, gw_ip))
+                    LuaFile.write('gw_hex_ip{}=convertIPToHex(gw_ip{})\n'.
+                            format(index, index))
             LuaFile.write(appendix)
         self._client.scp_put(self.LuaFileName, self.rundir + '/parameters.lua')
         self._client.scp_put('helper.lua', self.rundir + '/helper.lua')
 
-    def start_prox(self, configonly=False, autostart=''):
+    def start_prox(self, autostart=''):
         if self.machine_params['prox_socket']:
-            self._client = prox_ctrl(self.ip, self.key, self.user)
-            self._client.connect()
+            self._client = prox_ctrl(self.ip, self.key, self.user,
+                    self.password)
+            self._client.test_connection()
             if self.vim in ['OpenStack']:
-                self.devbind(configonly)
-            self.generate_lua(self.vim)
-            self._client.scp_put(self.machine_params['config_file'], '{}/{}'.format(self.rundir, self.machine_params['config_file']))
-            if ((not configonly) and self.machine_params['prox_launch_exit']):
-                cmd = 'sudo {}/prox {} -t -o cli -f {}/{}'.format(self.rundir, autostart, self.rundir, self.machine_params['config_file'])
-                RapidLog.debug("Starting PROX on {}: {}".format(self.name, cmd))
-                result = self._client.run_cmd(cmd, 'PROX Testing on {}'.format(self.name))
-                #RapidLog.debug("Finished PROX on {}: {}, {}".format(self.name, cmd, result))
-                RapidLog.debug("Finished PROX on {}: {}".format(self.name, cmd))
+                self.devbind()
+            if self.vim in ['kubernetes']:
+                self.read_cpuset()
+                self.remap_all_cpus()
+            _, prox_config_file_name = os.path.split(self.
+                    machine_params['config_file'])
+            if self.machine_params['prox_launch_exit']:
+                self.generate_lua()
+                self._client.scp_put(self.machine_params['config_file'], '{}/{}'.
+                        format(self.rundir, prox_config_file_name))
+                if not self.configonly:
+                    cmd = 'sudo {}/prox {} -t -o cli -f {}/{}'.format(self.rundir,
+                            autostart, self.rundir, prox_config_file_name)
+                    RapidLog.debug("Starting PROX on {}: {}".format(self.name,
+                        cmd))
+                    result = self._client.run_cmd(cmd)
+                    RapidLog.debug("Finished PROX on {}: {}".format(self.name,
+                        cmd))
 
     def close_prox(self):
-        if self.machine_params['prox_socket'] and self.machine_params['prox_launch_exit']:
-            self.socket.quit()
+        if (not self.configonly) and self.machine_params[
+                'prox_socket'] and self.machine_params['prox_launch_exit']:
+            self.socket.quit_prox()
+            self._client.scp_get('/prox.log', '{}/{}.prox.log'.format(
+                self.resultsdir, self.name))
 
     def connect_prox(self):
         if self.machine_params['prox_socket']: