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