X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=extras%2Fvpp_config%2Fvpplib%2FAutoConfig.py;h=2664a6aa7c4e9e9f4c88dab85c8a865cd2fc4fe9;hb=7c37a67fda3c467272f2c5cebff08329ba94994a;hp=36b6833e7a9aa847d78cee05e7c89da28a371d9b;hpb=a7da67fcc6df3ab319a6873a20a18ee1092d2a9e;p=vpp.git diff --git a/extras/vpp_config/vpplib/AutoConfig.py b/extras/vpp_config/vpplib/AutoConfig.py index 36b6833e7a9..2664a6aa7c4 100644 --- a/extras/vpp_config/vpplib/AutoConfig.py +++ b/extras/vpp_config/vpplib/AutoConfig.py @@ -33,6 +33,10 @@ MIN_SYSTEM_CPUS = 2 MIN_TOTAL_HUGE_PAGES = 1024 MAX_PERCENT_FOR_HUGE_PAGES = 70 +IPERFVM_XML = 'configs/iperf-vm.xml' +IPERFVM_IMAGE = 'images/xenial-mod.img' +IPERFVM_ISO = 'configs/cloud-config.iso' + class AutoConfig(object): """Auto Configuration Tools""" @@ -56,6 +60,7 @@ class AutoConfig(object): self._hugepage_config = "" self._clean = clean self._loadconfig() + self._sockfilename = "" def get_nodes(self): """ @@ -551,7 +556,9 @@ class AutoConfig(object): # If total_vpp_cpus is 0 or is less than the numa nodes with ports # then we shouldn't get workers - total_workers_node = total_vpp_cpus / len(ports_per_numa) + total_workers_node = 0 + if len(ports_per_numa): + total_workers_node = total_vpp_cpus / len(ports_per_numa) total_main = 0 if reserve_vpp_main_core: total_main = 1 @@ -622,14 +629,14 @@ class AutoConfig(object): tcp = tcp + " v4-halfopen-table-buckets " + \ "{:d}".format((aos + pos) / 4) + "\n" tcp = tcp + " v4-halfopen-table-memory 3g\n" + tcp = tcp + " local-endpoints-table-buckets " + "{:d}".format((aos + pos) / 4) + "\n" + tcp = tcp + " local-endpoints-table-memory 3g\n" tcp = tcp + "}\n\n" tcp = tcp + "tcp {\n" tcp = tcp + " preallocated-connections " + "{:d}".format(aos + pos) + "\n" if aos > 0: tcp = tcp + " preallocated-half-open-connections " + "{:d}".format(aos) + "\n" - tcp = tcp + " local-endpoints-table-buckets " + "{:d}".format((aos + pos) / 4) + "\n" - tcp = tcp + " local-endpoints-table-memory 3g\n" tcp = tcp + "}\n\n" return tcp.rstrip('\n') @@ -1041,10 +1048,11 @@ class AutoConfig(object): if answer == 'y': if 'unused' in device and len(device['unused']) != 0 and device['unused'][0] != '': driver = device['unused'][0] - VppPCIUtil.bind_vpp_device(node, driver, dvid) - else: - logging.debug('Could not bind device {}'.format(dvid)) - vppd[dvid] = device + ret = VppPCIUtil.bind_vpp_device(node, driver, dvid) + if ret: + logging.debug('Could not bind device {}'.format(dvid)) + else: + vppd[dvid] = device for dit in vppd.items(): dvid = dit[0] device = dit[1] @@ -1074,11 +1082,12 @@ class AutoConfig(object): if 'unused' in device and len(device['unused']) != 0 and device['unused'][0] != '': driver = device['unused'][0] logging.debug('Binding device {} to driver {}'.format(dvid, driver)) - VppPCIUtil.bind_vpp_device(node, driver, dvid) - else: - logging.debug('Could not bind device {}'.format(dvid)) - dpdk_devices[dvid] = device - del other_devices[dvid] + ret = VppPCIUtil.bind_vpp_device(node, driver, dvid) + if ret: + logging.debug('Could not bind device {}'.format(dvid)) + else: + dpdk_devices[dvid] = device + del other_devices[dvid] def update_interfaces_config(self): """ @@ -1155,11 +1164,12 @@ class AutoConfig(object): if 'unused' in device and len(device['unused']) != 0 and device['unused'][0] != '': driver = device['unused'][0] logging.debug('Binding device {} to driver {}'.format(dvid, driver)) - VppPCIUtil.bind_vpp_device(node, driver, dvid) - else: - logging.debug('Could not bind device {}'.format(dvid)) - dpdk_devices[dvid] = device - del kernel_devices[dvid] + ret = VppPCIUtil.bind_vpp_device(node, driver, dvid) + if ret: + logging.debug('Could not bind device {}'.format(dvid)) + else: + dpdk_devices[dvid] = device + del kernel_devices[dvid] dlen = len(dpdk_devices) if dlen > 0: @@ -1184,11 +1194,12 @@ class AutoConfig(object): if 'unused' in device and len(device['unused']) != 0 and device['unused'][0] != '': driver = device['unused'][0] logging.debug('Binding device {} to driver {}'.format(dvid, driver)) - VppPCIUtil.bind_vpp_device(node, driver, dvid) - else: - logging.debug('Could not bind device {}'.format(dvid)) - kernel_devices[dvid] = device - del dpdk_devices[dvid] + ret = VppPCIUtil.bind_vpp_device(node, driver, dvid) + if ret: + logging.debug('Could not bind device {}'.format(dvid)) + else: + kernel_devices[dvid] = device + del dpdk_devices[dvid] interfaces = {} for dit in dpdk_devices.items(): @@ -1379,6 +1390,14 @@ class AutoConfig(object): else: print ("\nNo devices bound to DPDK drivers") + other_devs = vpp.get_other_devices() + if len(other_devs): + print ("\nDevices not bound to Kernel or DPDK drivers:") + vpp.show_vpp_devices(other_devs, show_interfaces=True, + show_header=False) + else: + print ("\nNo devices not bound to Kernel or DPDK drivers") + vpputl = VPPUtil() interfaces = vpputl.get_hardware(node) if interfaces == {}: @@ -1390,17 +1409,17 @@ class AutoConfig(object): print ("None") return - print "{:30} {:6} {:4} {:7} {:4} {:7}". \ - format('Name', 'Socket', 'RXQs', + print "{:30} {:4} {:4} {:7} {:4} {:7}". \ + format('Name', 'Numa', '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']) + numa = rx_qs = rx_ds = tx_qs = tx_ds = '' + if 'numa' in value: + numa = int(value['numa']) if 'rx queues' in value: rx_qs = int(value['rx queues']) if 'rx descs' in value: @@ -1410,8 +1429,8 @@ class AutoConfig(object): 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)) + print ("{:30} {:>4} {:>4} {:>7} {:>4} {:>7}". + format(name, numa, rx_qs, rx_ds, tx_qs, tx_ds)) @staticmethod def hugepage_info(node): @@ -1637,16 +1656,20 @@ class AutoConfig(object): question = "Would you like connect this interface {} to the VM [Y/n]? ".format(name) answer = self._ask_user_yn(question, 'y') if answer == 'y': - sockfilename = '/tmp/sock{}.sock'.format(inum) + sockfilename = '/var/run/vpp/{}.sock'.format(name.replace('/', '_')) if os.path.exists(sockfilename): os.remove(sockfilename) cmd = 'vppctl create vhost-user socket {} server'.format(sockfilename) (ret, stdout, stderr) = vpputl.exec_command(cmd) if ret != 0: - raise RuntimeError("Create vhost failed on node {} {}." - .format(node['host'], stderr)) + raise RuntimeError("Couldn't execute the command {}, {}.".format(cmd, stderr)) vintname = stdout.rstrip('\r\n') + cmd = 'chmod 777 {}'.format(sockfilename) + (ret, stdout, stderr) = vpputl.exec_command(cmd) + if ret != 0: + raise RuntimeError("Couldn't execute the command {}, {}.".format(cmd, stderr)) + interface = {'name': name, 'virtualinterface': '{}'.format(vintname), 'bridge': '{}'.format(inum)} inum += 1 @@ -1679,7 +1702,7 @@ class AutoConfig(object): for intf in ints_with_vints: vhoststr = 'comment { The following command creates the socket }\n' vhoststr += 'comment { and returns a virtual interface }\n' - vhoststr += 'comment {{ create vhost-user socket /tmp/sock{}.sock server }}\n'. \ + vhoststr += 'comment {{ create vhost-user socket /var/run/vpp/sock{}.sock server }}\n'. \ format(intf['bridge']) setintdnstr = 'set interface state {} down\n'.format(intf['name']) @@ -1710,3 +1733,184 @@ class AutoConfig(object): print("\nA script as been created at {}".format(filename)) print("This script can be run using the following:") print("vppctl exec {}\n".format(filename)) + + def _iperf_vm_questions(self, node): + """ + Ask the user some questions and get a list of interfaces + and IPv4 addresses associated with those interfaces + + :param node: Node dictionary. + :type node: dict + :returns: A list or interfaces with ip addresses + :rtype: list + """ + + vpputl = VPPUtil() + interfaces = vpputl.get_hardware(node) + if interfaces == {}: + return [] + + # First delete all the Virtual interfaces + for intf in sorted(interfaces.items()): + name = intf[0] + if name[:7] == 'Virtual': + cmd = 'vppctl delete vhost-user {}'.format(name) + (ret, stdout, stderr) = vpputl.exec_command(cmd) + if ret != 0: + logging.debug('{} failed on node {} {}'.format( + cmd, node['host'], stderr)) + + # Create a virtual interface, for each interface the user wants to use + interfaces = vpputl.get_hardware(node) + if interfaces == {}: + return [] + interfaces_with_virtual_interfaces = [] + inum = 1 + + while True: + print '\nPlease pick one interface to connect to the iperf VM.' + for intf in sorted(interfaces.items()): + name = intf[0] + if name == 'local0': + continue + + question = "Would you like connect this interface {} to the VM [y/N]? ".format(name) + answer = self._ask_user_yn(question, 'n') + if answer == 'y': + self._sockfilename = '/var/run/vpp/{}.sock'.format(name.replace('/', '_')) + if os.path.exists(self._sockfilename): + os.remove(self._sockfilename) + cmd = 'vppctl create vhost-user socket {} server'.format(self._sockfilename) + (ret, stdout, stderr) = vpputl.exec_command(cmd) + if ret != 0: + raise RuntimeError("Couldn't execute the command {}, {}.".format(cmd, stderr)) + vintname = stdout.rstrip('\r\n') + + cmd = 'chmod 777 {}'.format(self._sockfilename) + (ret, stdout, stderr) = vpputl.exec_command(cmd) + if ret != 0: + raise RuntimeError("Couldn't execute the command {}, {}.".format(cmd, stderr)) + + interface = {'name': name, 'virtualinterface': '{}'.format(vintname), + 'bridge': '{}'.format(inum)} + inum += 1 + interfaces_with_virtual_interfaces.append(interface) + return interfaces_with_virtual_interfaces + + def create_and_bridge_iperf_virtual_interface(self): + """ + After asking the user some questions, and create and bridge a virtual interface + to be used with iperf VM + + """ + + for i in self._nodes.items(): + node = i[1] + + # Show the current bridge and interface configuration + print "\nThis the current bridge configuration:" + ifaces = VPPUtil.show_bridge(node) + question = "\nWould you like to keep this configuration [Y/n]? " + answer = self._ask_user_yn(question, 'y') + if answer == 'y': + self._sockfilename = '/var/run/vpp/{}.sock'.format(ifaces[0]['name'].replace('/', '_')) + if os.path.exists(self._sockfilename): + continue + + # Create a script that builds a bridge configuration with physical interfaces + # and virtual interfaces + ints_with_vints = self._iperf_vm_questions(node) + content = '' + for intf in ints_with_vints: + vhoststr = 'comment { The following command creates the socket }\n' + vhoststr += 'comment { and returns a virtual interface }\n' + vhoststr += 'comment {{ create vhost-user socket /var/run/vpp/sock{}.sock server }}\n'. \ + format(intf['bridge']) + + setintdnstr = 'set interface state {} down\n'.format(intf['name']) + + setintbrstr = 'set interface l2 bridge {} {}\n'.format(intf['name'], intf['bridge']) + setvintbrstr = 'set interface l2 bridge {} {}\n'.format(intf['virtualinterface'], intf['bridge']) + + # set interface state VirtualEthernet/0/0/0 up + setintvststr = 'set interface state {} up\n'.format(intf['virtualinterface']) + + # set interface state VirtualEthernet/0/0/0 down + setintupstr = 'set interface state {} up\n'.format(intf['name']) + + content += vhoststr + setintdnstr + setintbrstr + setvintbrstr + setintvststr + setintupstr + + # Write the content to the script + rootdir = node['rootdir'] + filename = rootdir + '/vpp/vpp-config/scripts/create_iperf_vm' + with open(filename, 'w+') as sfile: + sfile.write(content) + + # Execute the script + cmd = 'vppctl exec {}'.format(filename) + (ret, stdout, stderr) = VPPUtil.exec_command(cmd) + if ret != 0: + logging.debug(stderr) + + print("\nA script as been created at {}".format(filename)) + print("This script can be run using the following:") + print("vppctl exec {}\n".format(filename)) + + @staticmethod + def destroy_iperf_vm(name): + """ + After asking the user some questions, create a VM and connect the interfaces + to VPP interfaces + + :param name: The name of the VM to be be destroyed + :type name: str + """ + + cmd = 'virsh list' + (ret, stdout, stderr) = VPPUtil.exec_command(cmd) + if ret != 0: + logging.debug(stderr) + raise RuntimeError("Couldn't execute the command {} : {}".format(cmd, stderr)) + + if re.findall(name, stdout): + cmd = 'virsh destroy {}'.format(name) + (ret, stdout, stderr) = VPPUtil.exec_command(cmd) + if ret != 0: + logging.debug(stderr) + raise RuntimeError("Couldn't execute the command {} : {}".format(cmd, stderr)) + + def create_iperf_vm(self, vmname): + """ + After asking the user some questions, create a VM and connect the interfaces + to VPP interfaces + + """ + + # Read the iperf VM template file + distro = VPPUtil.get_linux_distro() + if distro[0] == 'Ubuntu': + tfilename = '{}/vpp/vpp-config/configs/iperf-ubuntu.xml.template'.format(self._rootdir) + else: + tfilename = '{}/vpp/vpp-config/configs/iperf-centos.xml.template'.format(self._rootdir) + + with open(tfilename, 'r') as tfile: + tcontents = tfile.read() + tfile.close() + + # Add the variables + imagename = '{}/vpp/vpp-config/{}'.format(self._rootdir, IPERFVM_IMAGE) + isoname = '{}/vpp/vpp-config/{}'.format(self._rootdir, IPERFVM_ISO) + tcontents = tcontents.format(vmname=vmname, imagename=imagename, isoname=isoname, + vhostsocketname=self._sockfilename) + + # Write the xml + ifilename = '{}/vpp/vpp-config/{}'.format(self._rootdir, IPERFVM_XML) + with open(ifilename, 'w+') as ifile: + ifile.write(tcontents) + ifile.close() + + cmd = 'virsh create {}'.format(ifilename) + (ret, stdout, stderr) = VPPUtil.exec_command(cmd) + if ret != 0: + logging.debug(stderr) + raise RuntimeError("Couldn't execute the command {} : {}".format(cmd, stderr))