A bit of cleanup, updated the README, started vhost test.
Change-Id: I49b998644b8b79c778c1186fc09831b1cd8fc015
Signed-off-by: John DeNisco <jdenisco@cisco.com>
diff --git a/extras/vpp_config/README.rst b/extras/vpp_config/README.rst
index 748f66f..ec9c8e4 100644
--- a/extras/vpp_config/README.rst
+++ b/extras/vpp_config/README.rst
@@ -5,7 +5,7 @@
then modifies the key configuration files. The user can then examine these files
to be sure they are correct and then actually apply the configuration. The user
can also install a released and stable version of VPP. This is currently
-released with release 17.07.
+released with release 17.10.
Use:
@@ -23,9 +23,7 @@
Caveats:
-- Only supports Ubuntu, centos7 is coming shortly.
-- When Inspecting the system, you may see a Huge page error, inspect the system a
-few more times, if the error persists it is real.
+- Supports Ubuntu, centos7, RedHat is coming shortly.
For Developers:
diff --git a/extras/vpp_config/setup.py b/extras/vpp_config/setup.py
index 8d2a396..32c376d 100644
--- a/extras/vpp_config/setup.py
+++ b/extras/vpp_config/setup.py
@@ -1,7 +1,7 @@
from setuptools import setup
setup(name="vpp_config",
- version="17.10.3",
+ version="17.10.5",
author="John DeNisco",
author_email="jdenisco@cisco.com",
description="VPP Configuration Utility",
@@ -9,7 +9,7 @@
keywords="vppconfig",
url = 'https://wiki.fd.io/view/VPP',
py_modules=['vpp_config'],
- install_requires=['pyyaml'],
+ install_requires=['pyyaml','netaddr'],
packages=['vpplib'],
scripts=['scripts/vpp-config'],
data_files=[('vpp/vpp-config/scripts', ['scripts/dpdk-devbind.py']),
diff --git a/extras/vpp_config/vpp_config.py b/extras/vpp_config/vpp_config.py
index b8b49a0..da455c1 100755
--- a/extras/vpp_config/vpp_config.py
+++ b/extras/vpp_config/vpp_config.py
@@ -450,6 +450,16 @@
acfg.ipv4_interface_setup()
+def autoconfig_create_vm():
+ """
+ Setup IPv4 interfaces
+
+ """
+
+ acfg = AutoConfig(rootdir, VPP_AUTO_CONFIGURATION_FILE)
+ acfg.create_and_bridge_virtual_interfaces()
+
+
def autoconfig_not_implemented():
"""
This feature is not implemented
@@ -465,10 +475,14 @@
"""
+# basic_menu_text = '\nWhat would you like to do?\n\n\
+# 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.'
+
basic_menu_text = '\nWhat would you like to do?\n\n\
1) List/Create Simple IPv4 Setup\n\
9 or q) Back to main menu.'
-
print "{}".format(basic_menu_text)
input_valid = False
@@ -506,6 +520,8 @@
answer = autoconfig_basic_test_menu()
if answer == '1':
autoconfig_ipv4_setup()
+ # elif answer == '2':
+ # autoconfig_create_vm()
elif answer == '9' or answer == 'q':
return
else:
diff --git a/extras/vpp_config/vpplib/AutoConfig.py b/extras/vpp_config/vpplib/AutoConfig.py
index ab943e0..7b7d7a7 100644
--- a/extras/vpp_config/vpplib/AutoConfig.py
+++ b/extras/vpp_config/vpplib/AutoConfig.py
@@ -17,7 +17,7 @@
import os
import re
import yaml
-import ipaddress
+from netaddr import IPAddress
from vpplib.VPPUtil import VPPUtil
from vpplib.VppPCIUtil import VppPCIUtil
@@ -90,30 +90,25 @@
Asks the user for a number within a range.
default is returned if return is entered.
- :returns: IP address and prefix len
- :rtype: tuple
+ :returns: IP address with cidr
+ :rtype: str
"""
while True:
- answer = raw_input("Please enter the IPv4 Address [n.n.n.n]: ")
+ answer = raw_input("Please enter the IPv4 Address [n.n.n.n/n]: ")
try:
- ipaddr = ipaddress.ip_address(u'{}'.format(answer))
+ ipinput = answer.split('/')
+ ipaddr = IPAddress(ipinput[0])
+ if len(ipinput) > 1:
+ plen = answer.split('/')[1]
+ else:
+ answer = raw_input("Please enter the netmask [n.n.n.n]: ")
+ plen = IPAddress(answer).netmask_bits()
+ return '{}/{}'.format(ipaddr, plen)
except:
print "Please enter a valid IPv4 address."
continue
- answer = raw_input("Please enter the netmask [n.n.n.n]: ")
- try:
- netmask = ipaddress.ip_address(u'{}'.format(answer))
- pl = ipaddress.ip_network(u'0.0.0.0/{}'.format(netmask))
- plen = pl.exploded.split('/')[1]
- break
- except:
- print "Please enter a valid IPv4 address and netmask."
- continue
-
- return ipaddr, plen
-
@staticmethod
def _ask_user_range(question, first, last, default):
"""
@@ -1479,14 +1474,13 @@
if name == 'local0':
continue
- question = "Would you like an address to interface {} [Y/n]? ".format(name)
+ question = "Would you like add address to interface {} [Y/n]? ".format(name)
answer = self._ask_user_yn(question, 'y')
if answer == 'y':
address = {}
- addr, plen = self._ask_user_ipv4()
+ addr = self._ask_user_ipv4()
address['name'] = name
address['addr'] = addr
- address['plen'] = plen
interfaces_with_ip.append(address)
return interfaces_with_ip
@@ -1527,8 +1521,7 @@
for ints in ints_with_addrs:
name = ints['name']
addr = ints['addr']
- plen = ints['plen']
- setipstr = 'set int ip address {} {}/{}\n'.format(name, addr, plen)
+ setipstr = 'set int ip address {} {}\n'.format(name, addr)
setintupstr = 'set int state {} up\n'.format(name)
content += setipstr + setintupstr
@@ -1546,4 +1539,118 @@
print("\nA script as been created at {}".format(filename))
print("This script can be run using the following:")
- print("vppctl exec {}\n".format(filename))
\ No newline at end of file
+ print("vppctl exec {}\n".format(filename))
+
+ def _create_vints_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
+ 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, 'y')
+ if answer == 'y':
+ sockfilename = '/tmp/sock{}.sock'.format(inum)
+ 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))
+ vintname = stdout.rstrip('\r\n')
+
+ 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_virtual_interfaces(self):
+ """
+ After asking the user some questions, create a VM and connect the interfaces
+ to VPP interfaces
+
+ """
+
+ for i in self._nodes.items():
+ node = i[1]
+
+ # Show the current bridge and interface configuration
+ print "\nThis the current bridge configuration:"
+ VPPUtil.show_bridge(node)
+ question = "\nWould you like to keep this configuration [Y/n]? "
+ answer = self._ask_user_yn(question, 'y')
+ if answer == 'y':
+ continue
+
+ # Create a script that builds a bridge configuration with physical interfaces
+ # and virtual interfaces
+ ints_with_vints = self._create_vints_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 /tmp/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_vms_and_connect_to_vpp'
+ 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))
diff --git a/extras/vpp_config/vpplib/VPPUtil.py b/extras/vpp_config/vpplib/VPPUtil.py
index f042e80..4551cf4 100644
--- a/extras/vpp_config/vpplib/VPPUtil.py
+++ b/extras/vpp_config/vpplib/VPPUtil.py
@@ -140,8 +140,11 @@
stderr))
reps = 'deb [trusted=yes] https://nexus.fd.io/content/'
- reps += 'repositories/fd.io.stable.{}.ubuntu.{}.main/ ./\n' \
- .format(fdio_release, ubuntu_version)
+ # When using a stable branch
+ # reps += 'repositories/fd.io.stable.{}.ubuntu.{}.main/ ./\n' \
+ # .format(fdio_release, ubuntu_version)
+ reps += 'repositories/fd.io.ubuntu.{}.main/ ./\n' \
+ .format(ubuntu_version)
cmd = 'echo "{0}" | sudo tee {1}'.format(reps, sfile)
(ret, stdout, stderr) = self.exec_command(cmd)
@@ -201,8 +204,11 @@
reps = '[fdio-stable-{}]\n'.format(fdio_release)
reps += 'name=fd.io stable/{} branch latest merge\n'.format(fdio_release)
- reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.stable.{}.{}/\n'.\
- format(fdio_release, centos_version)
+ # When using stable
+ # reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.stable.{}.{}/\n'.\
+ # format(fdio_release, centos_version)
+ reps += 'baseurl=https://nexus.fd.io/content/repositories/fd.io.{}/\n'.\
+ format(centos_version)
reps += 'enabled=1\n'
reps += 'gpgcheck=0'
@@ -336,6 +342,10 @@
:param node: Node dictionary with cpuinfo.
:type node: dict
"""
+
+ # First stop VPP
+ self.stop(node)
+
distro = self.get_linux_distro()
if distro[0] == 'Ubuntu':
self._uninstall_vpp_ubuntu(node)
@@ -373,6 +383,23 @@
self.exec_command('vppctl sh {}'.format(value))
@staticmethod
+ def get_vms(node):
+ """
+ Get a list of VMs that are connected to VPP interfaces
+
+ :param node: VPP node.
+ :type node: dict
+ :returns: Dictionary containing a list of VMs and the interfaces that are connected to VPP
+ :rtype: dictionary
+ """
+
+ vmdict = {}
+
+ print "Need to implement get vms"
+
+ return vmdict
+
+ @staticmethod
def get_int_ip(node):
"""
Get the VPP interfaces and IP addresses
@@ -393,6 +420,7 @@
if lines[0].split(' ')[0] == 'FileNotFoundError':
return interfaces
+ name = ''
for line in lines:
if len(line) is 0:
continue
@@ -583,6 +611,23 @@
return 0
@staticmethod
+ def restart(node):
+ """
+
+ Starts vpp for a given node
+
+ :param node: VPP node.
+ :type node: dict
+ """
+
+ cmd = 'service vpp restart'
+ (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+ if ret != 0:
+ raise RuntimeError('{} failed on node {} {} {}'.
+ format(cmd, node['host'],
+ stdout, stderr))
+
+ @staticmethod
def start(node):
"""
@@ -699,3 +744,40 @@
version[dct[0]] = dct[1].lstrip(' ')
return version
+
+ @staticmethod
+ def show_bridge(node):
+ """
+ Shows the current bridge configuration
+
+ :param node: VPP node.
+ :type node: dict
+ """
+
+ cmd = 'vppctl show bridge'
+ (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+ if ret != 0:
+ raise RuntimeError('{} failed on node {} {} {}'.
+ format(cmd, node['host'],
+ stdout, stderr))
+ lines = stdout.split('\r\n')
+ bridges = []
+ for line in lines:
+ if line == 'no bridge-domains in use':
+ print line
+ return
+ if len(line) == 0:
+ continue
+
+ lspl = line.lstrip(' ').split()
+ if lspl[0] != 'BD-ID':
+ bridges.append(lspl[0])
+
+ for bridge in bridges:
+ cmd = 'vppctl show bridge {} detail'.format(bridge)
+ (ret, stdout, stderr) = VPPUtil.exec_command(cmd)
+ if ret != 0:
+ raise RuntimeError('{} failed on node {} {} {}'.
+ format(cmd, node['host'],
+ stdout, stderr))
+ print stdout
diff --git a/extras/vpp_config/vpplib/VppGrubUtil.py b/extras/vpp_config/vpplib/VppGrubUtil.py
index 4aac427..1723170 100644
--- a/extras/vpp_config/vpplib/VppGrubUtil.py
+++ b/extras/vpp_config/vpplib/VppGrubUtil.py
@@ -101,12 +101,13 @@
value = cmdline.split('{}='.format(grubcmdline))[1]
value = value.rstrip('"').lstrip('"')
- iommu = re.findall(r'iommu=\w+', value)
- pstate = re.findall(r'intel_pstate=\w+', value)
+ # jadfix intel_pstate=disable sometimes cause networks to hang on reboot
+ # iommu = re.findall(r'iommu=\w+', value)
+ # pstate = re.findall(r'intel_pstate=\w+', value)
# If there is already some iommu commands set, leave them,
# if not use ours
- if iommu == [] and pstate == []:
- value = '{} intel_pstate=disable'.format(value)
+ # if iommu == [] and pstate == []:
+ # value = '{} intel_pstate=disable'.format(value)
# Replace isolcpus with ours
isolcpus = re.findall(r'isolcpus=[\w+\-,]+', value)
diff --git a/extras/vpp_config/vpplib/VppPCIUtil.py b/extras/vpp_config/vpplib/VppPCIUtil.py
index 829d66a..591dfab 100644
--- a/extras/vpp_config/vpplib/VppPCIUtil.py
+++ b/extras/vpp_config/vpplib/VppPCIUtil.py
@@ -251,11 +251,12 @@
:param devices: A list of devices
:param show_interfaces: show the kernel information
+ :param show_header: Display the header if true
:type devices: dict
:type show_interfaces: bool
+ :type show_header: bool
"""
-
if show_interfaces:
header = "{:15} {:25} {:50}".format("PCI ID",
"Kernel Interface(s)",
@@ -265,8 +266,7 @@
"Description")
dashseparator = ("-" * (len(header) - 2))
-
- if show_header == True:
+ if show_header is True:
print header
print dashseparator
for dit in devices.items():
@@ -298,7 +298,6 @@
:type device_id: string
"""
-
rootdir = node['rootdir']
dpdk_script = rootdir + DPDK_SCRIPT
cmd = dpdk_script + ' -u ' + ' ' + device_id