def autoconfig_dryrun(ask_questions=True): """ Execute the dryrun function. :param ask_questions: When true ask the user for paraameters :type ask_questions: bool """ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE, clean=True) # Stop VPP on each node nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] VPPUtil.stop(node) # Discover acfg.discover() # Check the system resources nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] if not acfg.min_system_resources(node): return # Modify the devices if ask_questions: acfg.modify_devices() else: acfg.update_interfaces_config() # If there are no interfaces, just return for i in nodes.items(): node = i[1] if not acfg.has_interfaces(node): print("\nThere are no VPP interfaces configured, please configure at least 1.") return # Modify CPU acfg.modify_cpu(ask_questions) # Calculate the cpu parameters acfg.calculate_cpu_parameters() # Acquire TCP stack parameters if ask_questions: acfg.acquire_tcp_params() # Apply the startup acfg.apply_vpp_startup() # Apply the grub configuration acfg.apply_grub_cmdline() # Huge Pages if ask_questions: acfg.modify_huge_pages() acfg.apply_huge_pages()
def autoconfig_cp(node, src, dst): """ Copies a file, saving the original if needed. :param node: Node dictionary with cpuinfo. :param src: Source File :param dst: Destination file :type node: dict :type src: string :type dst: string :raises RuntimeError: If command fails """ # If the destination file exist, create a copy if one does not already # exist ofile = dst + '.orig' (ret, stdout, stderr) = VPPUtil.exec_command('ls {}'.format(dst)) if ret == 0: cmd = 'cp {} {}'.format(dst, ofile) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'. format(cmd, node['host'], stdout, stderr)) # Copy the source file cmd = 'cp {} {}'.format(src, os.path.dirname(dst)) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'. format(cmd, node['host'], stderr))
def autoconfig_setup(ask_questions=True): """ The auto configuration setup function. We will copy the configuration files to the dryrun directory. """ global rootdir distro = VPPUtil.get_linux_distro() if distro[0] == 'Ubuntu': rootdir = '/usr/local' else: rootdir = '/usr' # If there is a system configuration file use that, if not use the initial auto-config file filename = rootdir + VPP_AUTO_CONFIGURATION_FILE if os.path.isfile(filename) is True: acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE) else: raise RuntimeError('The Auto configuration file does not exist {}'. format(filename)) if ask_questions: print ("\nWelcome to the VPP system configuration utility") print ("\nThese are the files we will modify:") print (" /etc/vpp/startup.conf") print (" /etc/sysctl.d/80-vpp.conf") print (" /etc/default/grub") print ( "\nBefore we change them, we'll create working copies in " "{}".format(rootdir + VPP_DRYRUNDIR)) print ( "Please inspect them carefully before applying the actual " "configuration (option 3)!") nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] if (os.path.isfile(rootdir + VPP_STARTUP_FILE) is not True) and \ (os.path.isfile(VPP_REAL_STARTUP_FILE) is True): autoconfig_cp(node, VPP_REAL_STARTUP_FILE, '{}'.format(rootdir + VPP_STARTUP_FILE)) if (os.path.isfile(rootdir + VPP_HUGE_PAGE_FILE) is not True) and \ (os.path.isfile(VPP_REAL_HUGE_PAGE_FILE) is True): autoconfig_cp(node, VPP_REAL_HUGE_PAGE_FILE, '{}'.format(rootdir + VPP_HUGE_PAGE_FILE)) if (os.path.isfile(rootdir + VPP_GRUB_FILE) is not True) and \ (os.path.isfile(VPP_REAL_GRUB_FILE) is True): autoconfig_cp(node, VPP_REAL_GRUB_FILE, '{}'.format(rootdir + VPP_GRUB_FILE)) # Be sure the uio_pci_generic driver is installed cmd = 'modprobe uio_pci_generic' (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: logging.warning('{} failed on node {} {}'. format(cmd, node['host'], stderr))
def autoconfig_grub_apply(node, ask_questions=True): """ Apply the grub configuration. :param node: The node structure :type node: dict :param ask_questions: When True ask the user questions :type ask_questions: bool :returns: -1 if the caller should return, 0 if not :rtype: int """ print ("\nThe configured grub cmdline looks like this:") configured_cmdline = node['grub']['default_cmdline'] current_cmdline = node['grub']['current_cmdline'] print (configured_cmdline) print ("\nThe current boot cmdline looks like this:") print (current_cmdline) if ask_questions: question = "\nDo you want to keep the current boot cmdline [Y/n]? " answer = autoconfig_yn(question, 'y') if answer == 'y': return node['grub']['keep_cmdline'] = False # Diff the file diffs = autoconfig_diff(node, VPP_REAL_GRUB_FILE, rootdir + VPP_GRUB_FILE) if diffs != '': print ("These are the changes we will apply to") print ("the GRUB file ({}).\n".format(VPP_REAL_GRUB_FILE)) print (diffs) if ask_questions: answer = autoconfig_yn("\nAre you sure you want to apply these changes [y/N]? ", 'n') if answer == 'n': return -1 # Copy and update grub autoconfig_cp(node, rootdir + VPP_GRUB_FILE, VPP_REAL_GRUB_FILE) distro = VPPUtil.get_linux_distro() if distro[0] == 'Ubuntu': cmd = "update-grub" else: cmd = "grub2-mkconfig -o /boot/grub2/grub.cfg" (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'. format(cmd, node['host'], stdout, stderr)) print ("There have been changes to the GRUB config a", end=' ') print ("reboot will be required.") return -1 else: print ('\nThere are no changes to the GRUB config.') return 0
def _get_default_cmdline(self): """ Using /etc/default/grub return the default grub cmdline :returns: The default grub cmdline :rtype: string """ # Get the default grub cmdline rootdir = self._node['rootdir'] gfile = self._node['cpu']['grub_config_file'] grubcmdline = self._node['cpu']['grubcmdline'] cmd = 'cat {}'.format(rootdir + gfile) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} Executing failed on node {} {}'. format(cmd, self._node['host'], stderr)) # Get the Default Linux command line, ignoring commented lines lines = stdout.split('\n') for line in lines: if line == '' or line[0] == '#': continue ldefault = re.findall(r'{}=.+'.format(grubcmdline), line) if ldefault: self._default_cmdline = ldefault[0] break
def get_actual_huge_pages(self): """ Get the current huge page configuration :returns the hugepage total, hugepage free, hugepage size, total memory, and total memory free :rtype: tuple """ # Get the memory information using /proc/meminfo cmd = 'sudo cat /proc/meminfo' (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError( '{} failed on node {} {} {}'.format( cmd, self._node['host'], stdout, stderr)) total = re.findall(r'HugePages_Total:\s+\w+', stdout) free = re.findall(r'HugePages_Free:\s+\w+', stdout) size = re.findall(r'Hugepagesize:\s+\w+\s+\w+', stdout) memtotal = re.findall(r'MemTotal:\s+\w+\s+\w+', stdout) memfree = re.findall(r'MemFree:\s+\w+\s+\w+', stdout) total = total[0].split(':')[1].lstrip() free = free[0].split(':')[1].lstrip() size = size[0].split(':')[1].lstrip() memtotal = memtotal[0].split(':')[1].lstrip() memfree = memfree[0].split(':')[1].lstrip() return total, free, size, memtotal, memfree
def autoconfig_hugepage_apply(node, ask_questions=True): """ Apply the huge page configuration. :param node: The node structure :type node: dict :param ask_questions: When True ask the user questions :type ask_questions: bool :returns: -1 if the caller should return, 0 if not :rtype: int """ diffs = autoconfig_diff(node, VPP_REAL_HUGE_PAGE_FILE, rootdir + VPP_HUGE_PAGE_FILE) if diffs != '': print ("These are the changes we will apply to") print ("the huge page file ({}).\n".format(VPP_REAL_HUGE_PAGE_FILE)) print (diffs) if ask_questions: answer = autoconfig_yn("\nAre you sure you want to apply these changes [Y/n]? ", 'y') if answer == 'n': return -1 # Copy and sysctl autoconfig_cp(node, rootdir + VPP_HUGE_PAGE_FILE, VPP_REAL_HUGE_PAGE_FILE) cmd = "sysctl -p {}".format(VPP_REAL_HUGE_PAGE_FILE) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'. format(cmd, node['host'], stdout, stderr)) else: print ('\nThere are no changes to the huge page configuration.') return 0
def autoconfig_diff(node, src, dst): """ Returns the diffs of 2 files. :param node: Node dictionary with cpuinfo. :param src: Source File :param dst: Destination file :type node: dict :type src: string :type dst: string :returns: The Answer :rtype: string :raises RuntimeError: If command fails """ # Diff the files and return the output cmd = "diff {} {}".format(src, dst) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if stderr != '': raise RuntimeError('{} failed on node {} {} {}'. format(cmd, node['host'], ret, stderr)) return stdout
def autoconfig_apply(ask_questions=True): """ Apply the configuration. Show the diff of the dryrun file and the actual configuration file Copy the files from the dryrun directory to the actual file. Peform the system function :param ask_questions: When true ask the user questions :type ask_questions: bool """ vutil = VPPUtil() pkgs = vutil.get_installed_vpp_pkgs() if len(pkgs) == 0: print ("\nVPP is not installed, Install VPP with option 4.") return acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE) if ask_questions: print ("\nWe are now going to configure your system(s).\n") answer = autoconfig_yn("Are you sure you want to do this [Y/n]? ", 'y') if answer == 'n': return nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] # Check the system resources if not acfg.min_system_resources(node): return # Stop VPP VPPUtil.stop(node) # Huge Pages ret = autoconfig_hugepage_apply(node, ask_questions) if ret != 0: return # VPP ret = autoconfig_vpp_apply(node, ask_questions) if ret != 0: return # Grub ret = autoconfig_grub_apply(node, ask_questions) if ret != 0: # We can still start VPP, even if we haven't configured grub VPPUtil.start(node) return # Everything is configured start vpp VPPUtil.start(node)
def __init__(self, node): distro = VPPUtil.get_linux_distro() if distro[0] == 'Ubuntu': node['cpu']['grubcmdline'] = 'GRUB_CMDLINE_LINUX_DEFAULT' else: node['cpu']['grubcmdline'] = 'GRUB_CMDLINE_LINUX' self._node = node self._current_cmdline = "" self._default_cmdline = "" self._get_current_cmdline() self._get_default_cmdline()
def autoconfig_basic_test(): """ The auto configuration basic test menu """ vutil = VPPUtil() pkgs = vutil.get_installed_vpp_pkgs() if len(pkgs) == 0: print ("\nVPP is not installed, install VPP with option 4.") return answer = '' while answer != 'q': answer = autoconfig_basic_test_menu() if answer == '1': autoconfig_ipv4_setup() elif answer == '2': autoconfig_create_iperf_vm() elif answer == '9' or answer == 'q': return else: autoconfig_not_implemented()
def get_cpu_info_per_node(node): """Return node related list of CPU numbers. :param node: Node dictionary with cpuinfo. :type node: dict :returns: Important CPU information. :rtype: dict """ cmd = "lscpu" ret, stdout, stderr = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("lscpu command failed on node {} {}." .format(node['host'], stderr)) cpuinfo = {} lines = stdout.split('\n') for line in lines: if line != '': linesplit = re.split(r':\s+', line) cpuinfo[linesplit[0]] = linesplit[1] cmd = "cat /proc/*/task/*/stat | awk '{print $1" "$2" "$39}'" ret, stdout, stderr = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("cat command failed on node {} {}." .format(node['host'], stderr)) vpp_processes = {} vpp_lines = re.findall(r'\w+\(vpp_\w+\)\w+', stdout) for line in vpp_lines: linesplit = re.split(r'\w+\(', line)[1].split(')') vpp_processes[linesplit[0]] = linesplit[1] cpuinfo['vpp_processes'] = vpp_processes return cpuinfo
def get_cpu_info_per_node(node): """Return node related list of CPU numbers. :param node: Node dictionary with cpuinfo. :type node: dict :returns: Important CPU information. :rtype: dict """ cmd = "lscpu" ret, stdout, stderr = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("lscpu command failed on node {} {}.".format( node['host'], stderr)) cpuinfo = {} lines = stdout.split('\n') for line in lines: if line != '': linesplit = re.split(r':\s+', line) cpuinfo[linesplit[0]] = linesplit[1] cmd = "cat /proc/*/task/*/stat | awk '{print $1" "$2" "$39}'" ret, stdout, stderr = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("cat command failed on node {} {}.".format( node['host'], stderr)) vpp_processes = {} vpp_lines = re.findall(r'\w+\(vpp_\w+\)\w+', stdout) for line in vpp_lines: linesplit = re.split(r'\w+\(', line)[1].split(')') vpp_processes[linesplit[0]] = linesplit[1] cpuinfo['vpp_processes'] = vpp_processes return cpuinfo
def autoconfig_install(): """ Install or Uninstall VPP. """ # Since these commands will take a while, we # want to see the progress logger = logging.getLogger() acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE) vutil = VPPUtil() nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] pkgs = vutil.get_installed_vpp_pkgs() if len(pkgs) > 0: print("\nThese packages are installed on node {}".format( node['host'])) print("{:25} {}".format("Name", "Version")) for pkg in pkgs: try: print("{:25} {}".format(pkg['name'], pkg['version'])) except KeyError: print("{}".format(pkg['name'])) question = "\nDo you want to uninstall these " question += "packages [y/N]? " answer = autoconfig_yn(question, 'n') if answer == 'y': logger.setLevel(logging.INFO) vutil.uninstall_vpp(node) else: print("\nThere are no VPP packages on node {}.".format( node['host'])) question = "Do you want to install VPP [Y/n]? " answer = autoconfig_yn(question, 'y') if answer == 'y': question = "Do you want to install the release version [Y/n]? " answer = autoconfig_yn(question, 'y') if answer == 'y': branch = 'release' else: branch = 'master' logger.setLevel(logging.INFO) vutil.install_vpp(node, branch) # Set the logging level back logger.setLevel(logging.ERROR)
def _get_current_cmdline(self): """ Using /proc/cmdline return the current grub cmdline :returns: The current grub cmdline :rtype: string """ # Get the memory information using /proc/meminfo cmd = "sudo cat /proc/cmdline" (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("{} on node {} {} {}".format( cmd, self._node["host"], stdout, stderr)) self._current_cmdline = stdout.strip("\n")
def unbind_vpp_device(node, device_id): """ unbind the device specified :param node: Node dictionary with cpuinfo. :param device_id: The device id :type node: dict :type device_id: string """ rootdir = node['rootdir'] dpdk_script = rootdir + DPDK_SCRIPT cmd = dpdk_script + ' -u ' + ' ' + device_id (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'.format( cmd, node['host'], stdout, stderr))
def _get_current_cmdline(self): """ Using /proc/cmdline return the current grub cmdline :returns: The current grub cmdline :rtype: string """ # Get the memory information using /proc/meminfo cmd = 'sudo cat /proc/cmdline' (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} on node {} {} {}'. format(cmd, self._node['host'], stdout, stderr)) self._current_cmdline = stdout.strip('\n')
def sys_info(self): """ Print the system information """ for i in self._nodes.items(): print "\n==============================" name = i[0] node = i[1] print "NODE: {}\n".format(name) # CPU print "CPU:" self.cpu_info(node) # Grub print "\nGrub Command Line:" if 'grub' in node: print \ " Current: {}".format( node['grub']['current_cmdline']) print \ " Configured: {}".format( node['grub']['default_cmdline']) # Huge Pages print "\nHuge Pages:" self.hugepage_info(node) # Devices print "\nDevices:" self.device_info(node) # Status print "\nVPP Service Status:" state, errors = VPPUtil.status(node) print " {}".format(state) for e in errors: print " {}".format(e) # Minimum system resources self.min_system_resources(node) print "\n=============================="
def autoconfig_install(): """ Install or Uninstall VPP. """ # Since these commands will take a while, we # want to see the progress logger = logging.getLogger() acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE) vutil = VPPUtil() nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] pkgs = vutil.get_installed_vpp_pkgs() if len(pkgs) > 0: print ("\nThese packages are installed on node {}" .format(node['host'])) print ("{:25} {}".format("Name", "Version")) for pkg in pkgs: try: print ("{:25} {}".format( pkg['name'], pkg['version'])) except KeyError: print ("{}".format(pkg['name'])) question = "\nDo you want to uninstall these " question += "packages [y/N]? " answer = autoconfig_yn(question, 'n') if answer == 'y': logger.setLevel(logging.INFO) vutil.uninstall_vpp(node) else: print ("\nThere are no VPP packages on node {}." .format(node['host'])) question = "Do you want to install VPP [Y/n]? " answer = autoconfig_yn(question, 'y') if answer == 'y': question = "Do you want to install the release version [Y/n]? " answer = autoconfig_yn(question, 'y') if answer == 'y': branch = 'release' else: branch = 'master' logger.setLevel(logging.INFO) vutil.install_vpp(node, branch) # Set the logging level back logger.setLevel(logging.ERROR)
def hugepages_dryrun_apply(self): """ Apply the huge page configuration """ node = self._node hugepages = node['hugepages'] vpp_hugepage_config = VPP_HUGEPAGE_CONFIG.format( nr_hugepages=hugepages['total'], max_map_count=hugepages['max_map_count'], shmmax=hugepages['shmax']) rootdir = node['rootdir'] filename = rootdir + node['hugepages']['hugepage_config_file'] cmd = 'echo "{0}" | sudo tee {1}'.\ format(vpp_hugepage_config, filename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'.format( cmd, node['host'], stdout, stderr))
def autoconfig_diff(node, src, dst): """ Returns the diffs of 2 files. :param node: Node dictionary with cpuinfo. :param src: Source File :param dst: Destination file :type node: dict :type src: string :type dst: string :returns: The Answer :rtype: string :raises RuntimeError: If command fails """ # Diff the files and return the output cmd = "diff {} {}".format(src, dst) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if stderr != '': raise RuntimeError('{} failed on node {} {} {}'.format( cmd, node['host'], ret, stderr)) return stdout
def bind_vpp_device(node, driver, device_id): """ bind the device specified :param node: Node dictionary with cpuinfo. :param driver: The driver :param device_id: The device id :type node: dict :type driver: string :type device_id: string :returns ret: Command return code """ rootdir = node['rootdir'] dpdk_script = rootdir + DPDK_SCRIPT cmd = dpdk_script + ' -b ' + driver + ' ' + device_id (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: logging.error('{} failed on node {}'.format( cmd, node['host'], stdout, stderr)) logging.error('{} {}'.format(stdout, stderr)) return ret
def autoconfig_hugepage_apply(node, ask_questions=True): """ Apply the huge page configuration. :param node: The node structure :type node: dict :param ask_questions: When True ask the user questions :type ask_questions: bool :returns: -1 if the caller should return, 0 if not :rtype: int """ diffs = autoconfig_diff(node, VPP_REAL_HUGE_PAGE_FILE, rootdir + VPP_HUGE_PAGE_FILE) if diffs != "": print("These are the changes we will apply to") print("the huge page file ({}).\n".format(VPP_REAL_HUGE_PAGE_FILE)) print(diffs) if ask_questions: answer = autoconfig_yn( "\nAre you sure you want to apply these changes [Y/n]? ", "y" ) if answer == "n": return -1 # Copy and sysctl autoconfig_cp(node, rootdir + VPP_HUGE_PAGE_FILE, VPP_REAL_HUGE_PAGE_FILE) cmd = "sysctl -p {}".format(VPP_REAL_HUGE_PAGE_FILE) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError( "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr) ) else: print("\nThere are no changes to the huge page configuration.") return 0
def hugepages_dryrun_apply(self): """ Apply the huge page configuration """ node = self._node hugepages = node["hugepages"] vpp_hugepage_config = VPP_HUGEPAGE_CONFIG.format( nr_hugepages=hugepages["total"], max_map_count=hugepages["max_map_count"], shmmax=hugepages["shmax"], ) rootdir = node["rootdir"] filename = rootdir + node["hugepages"]["hugepage_config_file"] cmd = 'echo "{0}" | sudo tee {1}'.format(vpp_hugepage_config, filename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError( "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr) )
def bind_vpp_device(node, driver, device_id): """ bind the device specified :param node: Node dictionary with cpuinfo. :param driver: The driver :param device_id: The device id :type node: dict :type driver: string :type device_id: string :returns ret: Command return code """ rootdir = node['rootdir'] dpdk_script = rootdir + DPDK_SCRIPT cmd = dpdk_script + ' -b ' + driver + ' ' + device_id (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: logging.error('{} failed on node {}'.format( cmd, node['host'], stdout, stderr)) logging.error('{} {}'.format( stdout, stderr)) return ret
def get_cpu_layout_from_all_nodes(nodes): """Retrieve cpu layout from all nodes, assuming all nodes are Linux nodes. :param nodes: DICT__nodes from Topology.DICT__nodes. :type nodes: dict :raises RuntimeError: If the ssh command "lscpu -p" fails. """ for node in nodes.values(): cmd = "lscpu -p" ret, stdout, stderr = VPPUtil.exec_command(cmd) # parsing of "lscpu -p" output: # # CPU,Core,Socket,Node,,L1d,L1i,L2,L3 # 0,0,0,0,,0,0,0,0 # 1,1,0,0,,1,1,1,0 if ret != 0: raise RuntimeError( "Failed to execute ssh command, ret: {} err: {}".format( ret, stderr)) node['cpuinfo'] = list() for line in stdout.split("\n"): if line != '' and line[0] != "#": node['cpuinfo'].append([CpuUtils.__str2int(x) for x in line.split(",")])
def hugepages_dryrun_apply(self): """ Apply the huge page configuration """ node = self._node hugepages = node['hugepages'] vpp_hugepage_config = VPP_HUGEPAGE_CONFIG.format( nr_hugepages=hugepages['total'], max_map_count=hugepages['max_map_count'], shmmax=hugepages['shmax']) rootdir = node['rootdir'] filename = rootdir + node['hugepages']['hugepage_config_file'] cmd = 'echo "{0}" | sudo tee {1}'.\ format(vpp_hugepage_config, filename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {} {}'. format(cmd, node['host'], stdout, stderr))
def get_cpu_layout_from_all_nodes(nodes): """Retrieve cpu layout from all nodes, assuming all nodes are Linux nodes. :param nodes: DICT__nodes from Topology.DICT__nodes. :type nodes: dict :raises RuntimeError: If the ssh command "lscpu -p" fails. """ for node in nodes.values(): cmd = "lscpu -p" ret, stdout, stderr = VPPUtil.exec_command(cmd) # parsing of "lscpu -p" output: # # CPU,Core,Socket,Node,,L1d,L1i,L2,L3 # 0,0,0,0,,0,0,0,0 # 1,1,0,0,,1,1,1,0 if ret != 0: raise RuntimeError( "Failed to execute ssh command, ret: {} err: {}".format( ret, stderr)) node["cpuinfo"] = list() for line in stdout.split("\n"): if line != "" and line[0] != "#": node["cpuinfo"].append( [CpuUtils.__str2int(x) for x in line.split(",")])
def get_cpu_layout(node): """ Get the cpu layout using lscpu -p get the cpu layout. Returns a list with each item representing a single cpu. :param node: Node dictionary. :type node: dict :returns: The cpu layout :rtype: list """ cmd = 'lscpu -p' (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'.format( cmd, node['host'], stderr)) pcpus = [] lines = stdout.split('\n') for line in lines: if line == '' or line[0] == '#': continue linesplit = line.split(',') layout = { 'cpu': linesplit[0], 'core': linesplit[1], 'socket': linesplit[2], 'node': linesplit[3] } # cpu, core, socket, node pcpus.append(layout) return pcpus
def autoconfig_grub_apply(node, ask_questions=True): """ Apply the grub configuration. :param node: The node structure :type node: dict :param ask_questions: When True ask the user questions :type ask_questions: bool :returns: -1 if the caller should return, 0 if not :rtype: int """ print("\nThe configured grub cmdline looks like this:") configured_cmdline = node["grub"]["default_cmdline"] current_cmdline = node["grub"]["current_cmdline"] print(configured_cmdline) print("\nThe current boot cmdline looks like this:") print(current_cmdline) if ask_questions: question = "\nDo you want to keep the current boot cmdline [Y/n]? " answer = autoconfig_yn(question, "y") if answer == "y": return node["grub"]["keep_cmdline"] = False # Diff the file diffs = autoconfig_diff(node, VPP_REAL_GRUB_FILE, rootdir + VPP_GRUB_FILE) if diffs != "": print("These are the changes we will apply to") print("the GRUB file ({}).\n".format(VPP_REAL_GRUB_FILE)) print(diffs) if ask_questions: answer = autoconfig_yn( "\nAre you sure you want to apply these changes [y/N]? ", "n" ) if answer == "n": return -1 # Copy and update grub autoconfig_cp(node, rootdir + VPP_GRUB_FILE, VPP_REAL_GRUB_FILE) distro = VPPUtil.get_linux_distro() if distro[0] == "Ubuntu": cmd = "update-grub" else: cmd = "grub2-mkconfig -o /boot/grub2/grub.cfg" (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError( "{} failed on node {} {} {}".format(cmd, node["host"], stdout, stderr) ) print("There have been changes to the GRUB config a", end=" ") print("reboot will be required.") return -1 else: print("\nThere are no changes to the GRUB config.") return 0
def autoconfig_dryrun(ask_questions=True): """ Execute the dryrun function. :param ask_questions: When true ask the user for paraameters :type ask_questions: bool """ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE, clean=True) # Stop VPP on each node nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] VPPUtil.stop(node) # Discover acfg.discover() # Check the system resources nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] if not acfg.min_system_resources(node): return # Modify the devices if ask_questions: acfg.modify_devices() else: acfg.update_interfaces_config() # If there are no interfaces, just return for i in nodes.items(): node = i[1] if not acfg.has_interfaces(node): print( "\nThere are no VPP interfaces configured, please configure at least 1." ) return # Modify CPU acfg.modify_cpu(ask_questions) # Calculate the cpu parameters acfg.calculate_cpu_parameters() # Acquire TCP stack parameters if ask_questions: acfg.acquire_tcp_params() # Apply the startup acfg.apply_vpp_startup() # Apply the grub configuration acfg.apply_grub_cmdline() # Huge Pages if ask_questions: acfg.modify_huge_pages() acfg.apply_huge_pages()
def autoconfig_setup(ask_questions=True): """ The auto configuration setup function. We will copy the configuration files to the dryrun directory. """ global rootdir distro = VPPUtil.get_linux_distro() if distro[0] == "Ubuntu": rootdir = "/usr/local" else: rootdir = "/usr" # If there is a system configuration file use that, if not use the initial auto-config file filename = rootdir + VPP_AUTO_CONFIGURATION_FILE if os.path.isfile(filename) is True: acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE) else: raise RuntimeError( "The Auto configuration file does not exist {}".format(filename) ) if ask_questions: print("\nWelcome to the VPP system configuration utility") print("\nThese are the files we will modify:") print(" /etc/vpp/startup.conf") print(" /etc/sysctl.d/80-vpp.conf") print(" /etc/default/grub") print( "\nBefore we change them, we'll create working copies in " "{}".format(rootdir + VPP_DRYRUNDIR) ) print( "Please inspect them carefully before applying the actual " "configuration (option 3)!" ) nodes = acfg.get_nodes() for i in nodes.items(): node = i[1] if (os.path.isfile(rootdir + VPP_STARTUP_FILE) is not True) and ( os.path.isfile(VPP_REAL_STARTUP_FILE) is True ): autoconfig_cp( node, VPP_REAL_STARTUP_FILE, "{}".format(rootdir + VPP_STARTUP_FILE) ) if (os.path.isfile(rootdir + VPP_HUGE_PAGE_FILE) is not True) and ( os.path.isfile(VPP_REAL_HUGE_PAGE_FILE) is True ): autoconfig_cp( node, VPP_REAL_HUGE_PAGE_FILE, "{}".format(rootdir + VPP_HUGE_PAGE_FILE) ) if (os.path.isfile(rootdir + VPP_GRUB_FILE) is not True) and ( os.path.isfile(VPP_REAL_GRUB_FILE) is True ): autoconfig_cp( node, VPP_REAL_GRUB_FILE, "{}".format(rootdir + VPP_GRUB_FILE) ) # Be sure the uio_pci_generic driver is installed cmd = "modprobe uio_pci_generic" (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: logging.warning("{} failed on node {} {}".format(cmd, node["host"], stderr))
def apply_cmdline(self, node, isolated_cpus): """ Apply cmdline to the default grub file :param node: Node dictionary with cpuinfo. :param isolated_cpus: The isolated cpu string :type node: dict :type isolated_cpus: string :return The vpp cmdline :rtype string """ vpp_cmdline = self.create_cmdline(isolated_cpus) if vpp_cmdline == '': return vpp_cmdline # Update grub # Save the original file rootdir = node['rootdir'] grubcmdline = node['cpu']['grubcmdline'] ofilename = rootdir + node['cpu']['grub_config_file'] + '.orig' filename = rootdir + node['cpu']['grub_config_file'] # Write the output file # Does a copy of the original file exist, if not create one (ret, stdout, stderr) = VPPUtil.exec_command('ls {}'.format(ofilename)) if ret != 0: if stdout.strip('\n') != ofilename: cmd = 'sudo cp {} {}'.format(filename, ofilename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'. format(cmd, self._node['host'], stderr)) # Get the contents of the current grub config file cmd = 'cat {}'.format(filename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'.format( cmd, self._node['host'], stderr)) # Write the new contents # Get the Default Linux command line, ignoring commented lines content = "" lines = stdout.split('\n') for line in lines: if line == '': content += line + '\n' continue if line[0] == '#': content += line + '\n' continue ldefault = re.findall(r'{}=.+'.format(grubcmdline), line) if ldefault: content += vpp_cmdline + '\n' else: content += line + '\n' content = content.replace(r"`", r"\`") content = content.rstrip('\n') cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'.format( cmd, self._node['host'], stderr)) return vpp_cmdline
def apply_cmdline(self, node, isolated_cpus): """ Apply cmdline to the default grub file :param node: Node dictionary with cpuinfo. :param isolated_cpus: The isolated cpu string :type node: dict :type isolated_cpus: string :return The vpp cmdline :rtype string """ vpp_cmdline = self.create_cmdline(isolated_cpus) if len(vpp_cmdline): # Update grub # Save the original file rootdir = node["rootdir"] grubcmdline = node["cpu"]["grubcmdline"] ofilename = rootdir + node["cpu"]["grub_config_file"] + ".orig" filename = rootdir + node["cpu"]["grub_config_file"] # Write the output file # Does a copy of the original file exist, if not create one (ret, stdout, stderr) = VPPUtil.exec_command("ls {}".format(ofilename)) if ret != 0: if stdout.strip("\n") != ofilename: cmd = "sudo cp {} {}".format(filename, ofilename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("{} failed on node {} {}".format( cmd, self._node["host"], stderr)) # Get the contents of the current grub config file cmd = "cat {}".format(filename) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("{} failed on node {} {}".format( cmd, self._node["host"], stderr)) # Write the new contents # Get the Default Linux command line, ignoring commented lines content = "" lines = stdout.split("\n") for line in lines: if line == "": content += line + "\n" continue if line[0] == "#": content += line + "\n" continue ldefault = re.findall(r"{}=.+".format(grubcmdline), line) if ldefault: content += vpp_cmdline + "\n" else: content += line + "\n" content = content.replace(r"`", r"\`") content = content.rstrip("\n") cmd = "sudo cat > {0} << EOF\n{1}\n".format(filename, content) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError("{} failed on node {} {}".format( cmd, self._node["host"], stderr)) return vpp_cmdline
def get_all_devices(self): """ Returns a list of all the devices """ node = self._node rootdir = node['rootdir'] dpdk_script = rootdir + DPDK_SCRIPT cmd = dpdk_script + ' --status' (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'.format( cmd, node['host'], stderr)) # Get the network devices using the DPDK # First get everything after using DPDK stda = stdout.split('Network devices using DPDK-compatible driver')[1] # Then get everything before using kernel driver using_dpdk = stda.split('Network devices using kernel driver')[0] self._dpdk_devices = self._create_device_list(using_dpdk) # Get the network devices using the kernel stda = stdout.split('Network devices using kernel driver')[1] using_kernel = stda.split('Other network devices')[0] self._kernel_devices = self._create_device_list(using_kernel) # Get the other network devices stda = stdout.split('Other network devices')[1] other = stda.split('Crypto devices using DPDK-compatible driver')[0] self._other_devices = self._create_device_list(other) # Get the crypto devices using the DPDK stda = stdout.split('Crypto devices using DPDK-compatible driver')[1] crypto_using_dpdk = stda.split('Crypto devices using kernel driver')[0] self._crypto_dpdk_devices = self._create_device_list( crypto_using_dpdk) # Get the network devices using the kernel stda = stdout.split('Crypto devices using kernel driver')[1] crypto_using_kernel = stda.split('Other crypto devices')[0] self._crypto_kernel_devices = self._create_device_list( crypto_using_kernel) # Get the other network devices crypto_other = stdout.split('Other crypto devices')[1] self._crypto_other_devices = self._create_device_list(crypto_other) # Get the devices used by the kernel for devk in self._kernel_devices.items(): dvid = devk[0] device = devk[1] for i in device['interfaces']: cmd = "ip addr show " + i (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed on node {} {}'.format( cmd, node['host'], stderr)) lstate = re.findall(r'state \w+', stdout)[0].split(' ')[1] # Take care of the links that are UP if lstate == 'UP': device['linkup'] = True self._link_up_devices[dvid] = device for devl in self._link_up_devices.items(): dvid = devl[0] del self._kernel_devices[dvid]
def _create_device_list(device_string): """ Returns a list of PCI devices :param device_string: The devices string from dpdk_devbind :returns: The device list :rtype: dictionary """ devices = {} ids = re.findall(PCI_DEV_ID_REGEX, device_string) descriptions = re.findall(r'\'([\s\S]*?)\'', device_string) unused = re.findall(r'unused=\w+|unused=', device_string) for i, j in enumerate(ids): device = {'description': descriptions[i]} if unused: device['unused'] = unused[i].split('=')[1].split(',') cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \ format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret == 0: device['driver'] = stdout.split(':')[1].rstrip('\n') cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed {} {}'. format(cmd, stderr, stdout)) numa_node = stdout.rstrip('\n') if numa_node == '-1': device['numa_node'] = '0' else: device['numa_node'] = numa_node interfaces = [] device['interfaces'] = [] cmd = 'ls /sys/bus/pci/devices/{}/net'.format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret == 0: interfaces = stdout.rstrip('\n').split() device['interfaces'] = interfaces l2_addrs = [] for intf in interfaces: cmd = 'cat /sys/bus/pci/devices/{}/net/{}/address'.format( ids[i], intf) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed {} {}'. format(cmd, stderr, stdout)) l2_addrs.append(stdout.rstrip('\n')) device['l2addr'] = l2_addrs devices[ids[i]] = device return devices
def _create_device_list(device_string): """ Returns a list of PCI devices :param device_string: The devices string from dpdk_devbind :returns: The device list :rtype: dictionary """ devices = {} ids = re.findall(PCI_DEV_ID_REGEX, device_string) descriptions = re.findall(r'\'([\s\S]*?)\'', device_string) unused = re.findall(r'unused=[\w,]+', device_string) for i, j in enumerate(ids): device = {'description': descriptions[i]} if unused: device['unused'] = unused[i].split('=')[1].split(',') cmd = 'ls /sys/bus/pci/devices/{}/driver/module/drivers'. \ format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret == 0: device['driver'] = stdout.split(':')[1].rstrip('\n') cmd = 'cat /sys/bus/pci/devices/{}/numa_node'.format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed {} {}'. format(cmd, stderr, stdout)) numa_node = stdout.rstrip('\n') if numa_node == '-1': device['numa_node'] = '0' else: device['numa_node'] = numa_node interfaces = [] device['interfaces'] = [] cmd = 'ls /sys/bus/pci/devices/{}/net'.format(ids[i]) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret == 0: interfaces = stdout.rstrip('\n').split() device['interfaces'] = interfaces l2_addrs = [] for intf in interfaces: cmd = 'cat /sys/bus/pci/devices/{}/net/{}/address'.format( ids[i], intf) (ret, stdout, stderr) = VPPUtil.exec_command(cmd) if ret != 0: raise RuntimeError('{} failed {} {}'. format(cmd, stderr, stdout)) l2_addrs.append(stdout.rstrip('\n')) device['l2addr'] = l2_addrs devices[ids[i]] = device return devices
def device_info(node): """ Show the device information. """ if 'cpu' in node and 'total_mbufs' in node['cpu']: total_mbufs = node['cpu']['total_mbufs'] if total_mbufs is not 0: print "Total Number of Buffers: {}".format(total_mbufs) vpp = VppPCIUtil(node) vpp.get_all_devices() linkup_devs = vpp.get_link_up_devices() if len(linkup_devs): print("\nDevices with link up (can not be used with VPP):") vpp.show_vpp_devices(linkup_devs, show_header=False) # for dev in linkup_devs: # print (" " + dev) kernel_devs = vpp.get_kernel_devices() if len(kernel_devs): print("\nDevices bound to kernel drivers:") vpp.show_vpp_devices(kernel_devs, show_header=False) else: print("\nNo devices bound to kernel drivers") dpdk_devs = vpp.get_dpdk_devices() if len(dpdk_devs): print("\nDevices bound to DPDK drivers:") vpp.show_vpp_devices(dpdk_devs, show_interfaces=True, show_header=False) else: print("\nNo devices bound to DPDK drivers") vpputl = VPPUtil() interfaces = vpputl.get_hardware(node) if interfaces == {}: return print("\nDevices in use by VPP:") if len(interfaces.items()) < 2: print("None") return print "{:30} {:6} {:4} {:7} {:4} {:7}". \ format('Name', 'Socket', 'RXQs', 'RXDescs', 'TXQs', 'TXDescs') for intf in sorted(interfaces.items()): name = intf[0] value = intf[1] if name == 'local0': continue socket = rx_qs = rx_ds = tx_qs = tx_ds = '' if 'cpu socket' in value: socket = int(value['cpu socket']) if 'rx queues' in value: rx_qs = int(value['rx queues']) if 'rx descs' in value: rx_ds = int(value['rx descs']) if 'tx queues' in value: tx_qs = int(value['tx queues']) if 'tx descs' in value: tx_ds = int(value['tx descs']) print("{:30} {:>6} {:>4} {:>7} {:>4} {:>7}".format( name, socket, rx_qs, rx_ds, tx_qs, tx_ds))