Add iperf VM/vhost creation

Change-Id: I27a59203f406120558f73bfcc12dca8835ae6361
Signed-off-by: John DeNisco <jdenisco@cisco.com>
This commit is contained in:
John DeNisco
2018-02-06 15:23:05 -05:00
committed by Damjan Marion
parent 56a0d06cb4
commit 9fa5cf4669
12 changed files with 452 additions and 19 deletions
Binary file not shown.
@@ -0,0 +1,108 @@
<domain type='kvm' id='54'>
<name>{vmname}</name>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<memoryBacking>
<hugepages>
<page size='2048' unit='KiB'/>
</hugepages>
</memoryBacking>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-rhel7.0.0'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-model'>
<model fallback='allow'></model>
</cpu>
<clock offset='utc'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='{imagename}'/>
<backingStore/>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='{isoname}'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<readonly/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0' model='ich9-ehci1'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<alias name='virtio-serial0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>
<interface type='network'>
<mac address='52:54:00:4c:47:f3'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='virtio'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/2'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/2'>
<source path='/dev/pts/2'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>
</devices>
<seclabel type='dynamic' model='selinux' relabel='yes'>
<label>system_u:system_r:svirt_t:s0:c532,c551</label>
<imagelabel>system_u:object_r:svirt_image_t:s0:c532,c551</imagelabel>
</seclabel>
<seclabel type='dynamic' model='dac' relabel='yes'>
<label>+107:+107</label>
<imagelabel>+107:+107</imagelabel>
</seclabel>
</domain>
@@ -0,0 +1,114 @@
<domain type='kvm' id='54'>
<name>{vmname}</name>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<memoryBacking>
<hugepages>
<page size='2048' unit='KiB'/>
</hugepages>
</memoryBacking>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-xenial'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-model'>
<model fallback='allow'></model>
<numa>
<cell id='0' cpus='0' memory='262144' unit='KiB' memAccess='shared'/>
</numa>
</cpu>
<clock offset='utc'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/bin/kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='{imagename}'/>
<backingStore/>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='{isoname}'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<readonly/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0' model='ich9-ehci1'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='virtio-serial' index='0'>
<alias name='virtio-serial0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
</controller>
<interface type='network'>
<mac address='52:54:00:4c:47:f3'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='virtio'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<interface type='vhostuser'>
<mac address='52:54:00:4c:47:f4'/>
<source type='unix' path='{vhostsocketname}' mode='client'/>
<model type='virtio'/>
<alias name='net1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/2'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/2'>
<source path='/dev/pts/2'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>
</devices>
<seclabel type='dynamic' model='apparmor' relabel='yes'>
<label>libvirt-2c4c9317-c7a5-4b37-b789-386ccda7348a</label>
<imagelabel>libvirt-2c4c9317-c7a5-4b37-b789-386ccda7348a</imagelabel>
</seclabel>
</domain>
+2 -2
View File
@@ -12,8 +12,8 @@ api-trace {{
cpu {{
{cpu}
scheduler-policy fifo
scheduler-priority 50
# scheduler-policy fifo
# scheduler-priority 50
## In the VPP there is one main thread and optionally the user can create worker(s)
## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
View File
+7 -2
View File
@@ -64,11 +64,16 @@ sudo mkdir $ROOTDIR/vpp/vpp-config
sudo mkdir $ROOTDIR/vpp/vpp-config/dryrun
sudo mkdir $ROOTDIR/vpp/vpp-config/scripts
sudo mkdir $ROOTDIR/vpp/vpp-config/configs
sudo mkdir $ROOTDIR/vpp/vpp-config/images
sudo mkdir $ROOTDIR/vpp/vpp-config/dryrun/default
sudo mkdir $ROOTDIR/vpp/vpp-config/dryrun/sysctl.d
sudo mkdir $ROOTDIR/vpp/vpp-config/dryrun/vpp
sudo cp scripts/dpdk-devbind.py $ROOTDIR/vpp/vpp-config/scripts/.
sudo cp data/auto-config.yaml $ROOTDIR/vpp/vpp-config/configs/.
sudo cp data/cloud-config.iso $ROOTDIR/vpp/vpp-config/configs/.
sudo cp data/iperf-centos.xml.template $ROOTDIR/vpp/vpp-config/configs/.
sudo cp data/iperf-ubuntu.xml.template $ROOTDIR/vpp/vpp-config/configs/.
sudo cp data/xenial-mod.img $ROOTDIR/vpp/vpp-config/images/.
sudo cp data/80-vpp.conf.template $ROOTDIR/vpp/vpp-config/dryrun/sysctl.d/.
sudo cp data/grub.template $ROOTDIR/vpp/vpp-config/dryrun/default/.
sudo cp data/startup.conf.template $ROOTDIR/vpp/vpp-config/dryrun/vpp/.
sudo cp data/80-vpp.conf.template $ROOTDIR/vpp/vpp-config/dryrun/sysctl.d/.
sudo cp scripts/dpdk-devbind.py $ROOTDIR/vpp/vpp-config/scripts/.
View File
View File
+4 -1
View File
@@ -1,7 +1,7 @@
from setuptools import setup
setup(name="vpp_config",
version="18.01.1",
version="18.01.4",
author="John DeNisco",
author_email="jdenisco@cisco.com",
description="VPP Configuration Utility",
@@ -14,6 +14,9 @@ setup(name="vpp_config",
scripts=['scripts/vpp-config'],
data_files=[('vpp/vpp-config/scripts', ['scripts/dpdk-devbind.py']),
('vpp/vpp-config/configs', ['data/auto-config.yaml']),
('vpp/vpp-config/configs', ['data/cloud-config.iso']),
('vpp/vpp-config/configs', ['data/iperf-centos.xml.template']),
('vpp/vpp-config/configs', ['data/iperf-ubuntu.xml.template']),
('vpp/vpp-config/dryrun/sysctl.d', ['data/80-vpp.conf.template']),
('vpp/vpp-config/dryrun/default', ['data/grub.template']),
('vpp/vpp-config/dryrun/vpp', ['data/startup.conf.template']),
Executable → Regular
+8 -8
View File
@@ -464,14 +464,16 @@ def autoconfig_ipv4_setup():
acfg.ipv4_interface_setup()
def autoconfig_create_vm():
def autoconfig_create_iperf_vm():
"""
Setup IPv4 interfaces
"""
acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
acfg.create_and_bridge_virtual_interfaces()
acfg.destroy_iperf_vm('iperf-server')
acfg.create_and_bridge_iperf_virtual_interface()
acfg.create_iperf_vm('iperf-server')
def autoconfig_not_implemented():
@@ -491,12 +493,9 @@ def autoconfig_basic_test_menu():
basic_menu_text = '\nWhat would you like to do?\n\n\
1) List/Create Simple IPv4 Setup\n\
2) Create an iperf VM and Connect to VPP an interface\n\
9 or q) Back to main menu.'
# 1) List/Create Simple IPv4 Setup\n\
# 2) List/Create Create VM and Connect to VPP interfaces\n\
# 9 or q) Back to main menu.'
print "{}".format(basic_menu_text)
input_valid = False
@@ -534,8 +533,8 @@ def autoconfig_basic_test():
answer = autoconfig_basic_test_menu()
if answer == '1':
autoconfig_ipv4_setup()
# elif answer == '2':
# autoconfig_create_vm()
elif answer == '2':
autoconfig_create_iperf_vm()
elif answer == '9' or answer == 'q':
return
else:
@@ -664,6 +663,7 @@ def autoconfig_setup(ask_questions=True):
raise RuntimeError('{} failed on node {} {}'. format(cmd, node['host'], stderr))
# noinspection PyUnresolvedReferences
def execute_with_args(args):
"""
Execute the configuration utility with agruments.
+196 -4
View File
@@ -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
@@ -1637,16 +1644,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 = '/var/run/vpp/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
@@ -1710,3 +1721,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))
+13 -2
View File
@@ -753,8 +753,10 @@ class VPPUtil(object):
:param node: VPP node.
:type node: dict
:returns: A list of interfaces
"""
ifaces = []
cmd = 'vppctl show bridge'
(ret, stdout, stderr) = VPPUtil.exec_command(cmd)
if ret != 0:
@@ -766,7 +768,7 @@ class VPPUtil(object):
for line in lines:
if line == 'no bridge-domains in use':
print line
return
return ifaces
if len(line) == 0:
continue
@@ -781,4 +783,13 @@ class VPPUtil(object):
raise RuntimeError('{} failed on node {} {} {}'.
format(cmd, node['host'],
stdout, stderr))
print stdout
lines = stdout.split('\r\n')
for line in lines:
iface = re.findall(r'[a-zA-z]+\d+/\d+/\d+', line)
if len(iface):
ifcidx ={'name': iface[0], 'index': line.split()[1] }
ifaces.append(ifcidx)
print stdout
return ifaces