Enable PVP and PVVP deployments for Vanilla OVS 35/2335/3
authorMartin Klozik <martinx.klozik@intel.com>
Fri, 2 Oct 2015 01:18:09 +0000 (02:18 +0100)
committerMaryam Tahhan <maryam.tahhan@intel.com>
Mon, 12 Oct 2015 14:58:14 +0000 (14:58 +0000)
Support for PVP and PVVP scenerios using Vanilla OVS was added.
VMs are configured to forward traffic between virtual interfaces
by standard linux capabilities. Traffic generator script was updated
to accept MAC and IP address configuration to allow VM forwarding
configuration.

VSPERF-66, VSPERF-70

Change-Id: Ia70ab6be547b39928a1eae319faba779d4e29284
Signed-off-by: Martin Klozik <martinx.klozik@intel.com>
Signed-off-by: Dino Simeon Madarang <dino.simeonx.madarang@intel.com>
Reviewed-by: Maryam Tahhan <maryam.tahhan@intel.com>
Reviewed-by: Brian Castelli <brian.castelli@spirent.com>
Reviewed-by: Gene Snider <eugene.snider@huawei.com>
Reviewed-by: Al Morton <acmorton@att.com>
Reviewed-by: Tv Rao <tv.rao@freescale.com>
18 files changed:
conf/04_vnf.conf
core/traffic_controller_rfc2544.py
core/vnf_controller.py
core/vswitch_controller.py
core/vswitch_controller_p2p.py
core/vswitch_controller_pvp.py
core/vswitch_controller_pvvp.py
docs/to-be-reorganized/NEWS.rst
docs/to-be-reorganized/quickstart.rst
testcases/testcase.py
tools/pkt_gen/ixnet/ixnetrfc2544.tcl
vnfs/qemu/qemu.py
vnfs/qemu/qemu_dpdk.py
vnfs/qemu/qemu_virtio_net.py [new file with mode: 0644]
vnfs/vnf/vnf.py
vswitches/ovs_dpdk_vhost.py
vswitches/ovs_vanilla.py
vswitches/vswitch.py

index 034e410..52cc6ec 100644 (file)
@@ -79,5 +79,33 @@ GUEST_SMP = ['2', '2']
 # For 2 VNFs you may use [(4,5), (6, 7)]
 GUEST_CORE_BINDING = [(6, 7), (9, 10)]
 
+GUEST_START_TIMEOUT = 120
 GUEST_OVS_DPDK_DIR = '/root/ovs_dpdk'
 OVS_DPDK_SHARE = '/mnt/ovs_dpdk_share'
+
+# IP addresses to use for Vanilla OVS PVP testing
+# Consider using RFC 2544/3330 recommended IP addresses for benchmark testing.
+# Network: 198.18.0.0/15
+# Netmask: 255.254.0.0
+# Broadcast: 198.19.255.255
+# First IP: 198.18.0.1
+# Last IP: 198.19.255.254
+# Hosts: 131070
+#
+
+# ARP entries for the IXIA ports and the bridge you are using:
+VANILLA_TGEN_PORT1_IP = '1.1.1.10'
+VANILLA_TGEN_PORT1_MAC = 'AA:BB:CC:DD:EE:FF'
+
+VANILLA_TGEN_PORT2_IP = '1.1.2.10'
+VANILLA_TGEN_PORT2_MAC = 'AA:BB:CC:DD:EE:F0'
+
+VANILLA_BRIDGE_IP = ['1.1.1.5/16', '1.1.1.6/16']
+
+VANILLA_NIC1_NAME = ['eth0', 'eth2']
+VANILLA_NIC2_NAME = ['eth1', 'eth3']
+
+VANILLA_NIC1_IP_CIDR = ['192.168.1.2/24', '192.168.1.4/24']
+VANILLA_NIC2_IP_CIDR = ['192.168.1.3/24', '192.168.1.5/24']
+
+VNF_AFFINITIZATION_ON = True
index fa4a9c3..5659569 100644 (file)
@@ -49,7 +49,7 @@ class TrafficControllerRFC2544(ITrafficController, IResults):
         packet_sizes_cli = get_test_param('pkt_sizes')
         if packet_sizes_cli:
             self._packet_sizes = [int(x.strip())
-                for x in packet_sizes_cli.split(',')]
+                                  for x in packet_sizes_cli.split(',')]
         else:
             self._packet_sizes = settings.getValue('TRAFFICGEN_PKT_SIZES')
 
@@ -91,7 +91,13 @@ class TrafficControllerRFC2544(ITrafficController, IResults):
                            str(self._traffic_gen_class))
 
         for packet_size in self._packet_sizes:
-            traffic['l2'] = {'framesize': packet_size}
+            # Merge framesize with the default traffic definition
+            if 'l2' in traffic:
+                traffic['l2'] = dict(traffic['l2'],
+                                     **{'framesize': packet_size})
+            else:
+                traffic['l2'] = {'framesize': packet_size}
+
             if traffic['traffic_type'] == 'back2back':
                 result = self._traffic_gen_class.send_rfc2544_back2back(
                     traffic, trials=self._trials,
index 3d3be04..3313e9e 100644 (file)
@@ -15,6 +15,7 @@
 """
 
 import logging
+from vnfs.vnf.vnf import IVnf
 
 class VnfController(object):
     """VNF controller class
@@ -33,6 +34,10 @@ class VnfController(object):
 
         :param vnf_class: The VNF class to be used.
         """
+        # reset VNF ID counter for each testcase
+        IVnf.reset_vnf_counter()
+
+        # setup controller with requested number of VNFs
         self._logger = logging.getLogger(__name__)
         self._vnf_class = vnf_class
         self._deployment_scenario = deployment_scenario.upper()
index 619e1d8..855de8b 100644 (file)
@@ -49,3 +49,10 @@ class IVswitchController(object):
         raise NotImplementedError(
             "The VswitchController does not implement the \"get_ports_info\" "
             "function.")
+
+    def dump_vswitch_flows(self):
+        """ Dumps flows from vswitch
+        """
+        raise NotImplementedError(
+            "The VswitchController does not implement the "
+            "\"dump_vswitch_flows\" function.")
index c15f7ef..35600e1 100644 (file)
@@ -114,3 +114,8 @@ class VswitchControllerP2P(IVswitchController):
         """
         self._logger.debug('get_ports_info  using ' + str(self._vswitch_class))
         return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME'))
+
+    def dump_vswitch_flows(self):
+        """See IVswitchController for description
+        """
+        self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
index 80c0fdb..b2337bd 100644 (file)
@@ -104,3 +104,8 @@ class VswitchControllerPVP(IVswitchController):
         """
         self._logger.debug('get_ports_info  using ' + str(self._vswitch_class))
         return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME'))
+
+    def dump_vswitch_flows(self):
+        """See IVswitchController for description
+        """
+        self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
index b445f9b..43cf8a3 100644 (file)
@@ -112,3 +112,8 @@ class VswitchControllerPVVP(IVswitchController):
         """
         self._logger.debug('get_ports_info  using ' + str(self._vswitch_class))
         return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME'))
+
+    def dump_vswitch_flows(self):
+        """See IVswitchController for description
+        """
+        self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
index 69df747..0fe9e22 100644 (file)
@@ -1,3 +1,9 @@
+October 2015
+==============
+New
+---
+- Support of PVP and PVVP deployment scenarios using Vanilla OVS
+
 September 2015
 ==============
 New
@@ -63,4 +69,3 @@ Missing
 -------
 
 -  xmlunit output is currently disabled
--  VNF support.
index 485bf1a..c575be5 100644 (file)
@@ -203,7 +203,45 @@ To run tests using vhost-cuse as guest access method:
 
      ./vsperf --conf-file <path_to_settings_py>
 
+Executing PVP tests using Vanilla OVS
+-------------------------------------
+To run tests using Vanilla OVS:
+
+1. Set the following variables:
+
+  .. code-block:: console
+
+   VSWITCH = 'OvsVanilla'
+   VNF = 'QemuVirtioNet'
+
+   VANILLA_TGEN_PORT1_IP = n.n.n.n
+   VANILLA_TGEN_PORT1_MAC = nn:nn:nn:nn:nn:nn
+
+   VANILLA_TGEN_PORT2_IP = n.n.n.n
+   VANILLA_TGEN_PORT2_MAC = nn:nn:nn:nn:nn:nn
+
+   VANILLA_BRIDGE_IP = n.n.n.n
+
+   or use --test-param
+
+   ./vsperf --conf-file user_settings.py
+            --test-param "vanilla_tgen_tx_ip=n.n.n.n;
+                          vanilla_tgen_tx_mac=nn:nn:nn:nn:nn:nn"
+
+
+2. Recompile src for Vanilla OVS testing
 
+  .. code-block:: console
+
+     cd src
+     make cleanse
+     make WITH_LINUX=/lib/modules/`uname -r`/build
+
+3. Run test:
+
+  .. code-block:: console
+
+     ./vsperf --conf-file <path_to_settings_py>
 
 GOTCHAs:
 --------
index e15572d..feb264d 100644 (file)
@@ -23,7 +23,7 @@ from core.results.results_constants import ResultsConstants
 import core.component_factory as component_factory
 from core.loader import Loader
 from tools.report import report
-from conf import settings
+from conf import settings as S
 
 class TestCase(object):
     """TestCase base class
@@ -92,12 +92,25 @@ class TestCase(object):
                            'bidir': self._bidir,
                            'multistream': self._multistream}
 
+                # OVS Vanilla requires guest VM MAC address and IPs
+                # to work
+                if (self.deployment in ["pvp", "pvvp"] and
+                        S.getValue('VSWITCH') == "OvsVanilla"):
+
+                    traffic['l2'] = {'srcmac': S.getValue('GUEST_NET2_MAC')[0],
+                                     'dstmac': S.getValue('GUEST_NET1_MAC')[0]}
+
+                    traffic['l3'] = {'srcip':
+                                     S.getValue('VANILLA_TGEN_PORT1_IP'),
+                                     'dstip':
+                                     S.getValue('VANILLA_TGEN_PORT2_IP')}
+
                 vswitch = vswitch_ctl.get_vswitch()
                 # TODO BOM 15-08-07 the frame mod code assumes that the
                 # physical ports are ports 1 & 2. The actual numbers
                 # need to be retrived from the vSwitch and the metadata value
                 # updated accordingly.
-                bridge = settings.getValue('VSWITCH_BRIDGE_NAME')
+                bridge = S.getValue('VSWITCH_BRIDGE_NAME')
                 if self._frame_mod == "vlan":
                     # 0x8100 => VLAN ethertype
                     self._logger.debug(" ****   VLAN   ***** ")
@@ -178,6 +191,9 @@ class TestCase(object):
                 with traffic_ctl:
                     traffic_ctl.send_traffic(traffic)
 
+                # dump vswitch flows before they are affected by VNF termination
+                vswitch_ctl.dump_vswitch_flows()
+
         self._logger.debug("Traffic Results:")
         traffic_ctl.print_results()
 
index d5479b2..eda369d 100644 (file)
@@ -702,7 +702,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
      -frEncapsulation ::ixNet::OBJ-null \
      -incrementPerVcVlanMode noIncrement \
      -incrementVlanMode noIncrement \
-     -mac "00:00:00:00:00:01" \
+     -mac $srcMac \
      -macRangeMode normal \
      -numberOfVcs 1 \
      -siteId 0 \
@@ -1082,7 +1082,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
      -frEncapsulation ::ixNet::OBJ-null \
      -incrementPerVcVlanMode noIncrement \
      -incrementVlanMode noIncrement \
-     -mac "00:01:00:05:08:00" \
+     -mac $dstMac \
      -macRangeMode normal \
      -numberOfVcs 1 \
      -siteId 0 \
@@ -2046,14 +2046,14 @@ proc startRfc2544Test { testSpec trafficSpec } {
     #
     set sg_field $ixNetSG_Stack(3)/field:"ipv4.header.srcIp-27"
     ixNet setMultiAttrs $sg_field \
-     -singleValue {1.1.1.1} \
+     -singleValue $srcIp \
      -seed {1} \
      -optionalEnabled True \
      -fullMesh False \
      -valueList {{0.0.0.0}} \
      -stepValue {0.0.0.0} \
      -fixedBits {0.0.0.0} \
-     -fieldValue {1.1.1.1} \
+     -fieldValue $srcIp \
      -auto False \
      -randomMask {0.0.0.0} \
      -trackingEnabled False \
@@ -2069,14 +2069,14 @@ proc startRfc2544Test { testSpec trafficSpec } {
     #
     set sg_field $ixNetSG_Stack(3)/field:"ipv4.header.dstIp-28"
     ixNet setMultiAttrs $sg_field \
-     -singleValue {90.90.90.90} \
+     -singleValue $dstIp \
      -seed {1} \
      -optionalEnabled True \
      -fullMesh False \
      -valueList {{0.0.0.0}} \
      -stepValue {0.0.0.0} \
      -fixedBits {0.0.0.0} \
-     -fieldValue {90.90.90.90} \
+     -fieldValue $dstIp \
      -auto False \
      -randomMask {0.0.0.0} \
      -trackingEnabled False \
@@ -3681,7 +3681,7 @@ proc startRfc2544Test { testSpec trafficSpec } {
     #
     set sg_field $ixNetSG_Stack(3)/field:"ipv4.header.srcIp-27"
     ixNet setMultiAttrs $sg_field \
-     -singleValue {1.1.1.1} \
+     -singleValue $srcIp \
      -seed {1} \
      -optionalEnabled True \
      -fullMesh False \
@@ -3704,14 +3704,14 @@ proc startRfc2544Test { testSpec trafficSpec } {
     #
     set sg_field $ixNetSG_Stack(3)/field:"ipv4.header.dstIp-28"
     ixNet setMultiAttrs $sg_field \
-     -singleValue {90.90.90.90} \
+     -singleValue $dstIp \
      -seed {1} \
      -optionalEnabled True \
      -fullMesh False \
      -valueList {{0.0.0.0}} \
      -stepValue {0.0.0.0} \
      -fixedBits {0.0.0.0} \
-     -fieldValue {90.90.90.90} \
+     -fieldValue $dstIp \
      -auto False \
      -randomMask {0.0.0.0} \
      -trackingEnabled False \
index 338ca77..2e2c63d 100644 (file)
@@ -41,13 +41,7 @@ class IVnfQemu(IVnf):
 
     def __init__(self):
         """
-        :param timeout: Time to wait for login prompt. If set to
-            0 do not wait.
-        :param number: Number of QEMU instance, used when multiple QEMU
-            instances are started at once.
-        :param args: Arguments to pass to QEMU.
-
-        :returns: None
+        Initialisation function.
         """
         super(IVnfQemu, self).__init__()
         self._logger = logging.getLogger(__name__)
@@ -67,9 +61,6 @@ class IVnfQemu(IVnf):
                      '-cpu', 'host',
                      '-drive', 'if=scsi,file=' +
                      S.getValue('GUEST_IMAGE')[self._number],
-                     '-drive',
-                     'if=scsi,file=fat:rw:%s,snapshot=off' %
-                     S.getValue('GUEST_SHARE_DIR')[self._number],
                      '-boot', 'c', '--enable-kvm',
                      '-monitor', 'unix:%s,server,nowait' % self._monitor,
                      '-object',
@@ -104,7 +95,8 @@ class IVnfQemu(IVnf):
         Start QEMU instance, login and prepare for commands.
         """
         super(IVnfQemu, self).start()
-        self._affinitize()
+        if S.getValue('VNF_AFFINITIZATION_ON'):
+            self._affinitize()
 
         if self._timeout:
             self._login()
index 0b8f90a..02d720f 100644 (file)
@@ -25,16 +25,13 @@ class IVnfQemuDpdk(IVnfQemu):
 
     def __init__(self):
         """
-        :param timeout: Time to wait for login prompt. If set to
-            0 do not wait.
-        :param number: Number of QEMU instance, used when multiple QEMU
-            instances are started at once.
-        :param args: Arguments to pass to QEMU.
-
-        :returns: None
+        Initialisation function.
         """
         super(IVnfQemuDpdk, self).__init__()
-        self._cmd += []
+        self._cmd += ['-drive',
+                      'if=scsi,file=fat:rw:%s,snapshot=off' %
+                      S.getValue('GUEST_SHARE_DIR')[self._number],
+                     ]
 
     def _modify_dpdk_makefile(self):
         """
diff --git a/vnfs/qemu/qemu_virtio_net.py b/vnfs/qemu/qemu_virtio_net.py
new file mode 100644 (file)
index 0000000..7de5ea1
--- /dev/null
@@ -0,0 +1,115 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Automation of QEMU hypervisor for launching virtio-net enabled guests.
+"""
+
+import logging
+from vnfs.qemu.qemu import IVnfQemu
+from conf import settings as S
+from conf import get_test_param
+from tools import tasks
+
+class QemuVirtioNet(IVnfQemu):
+    """
+    Control an instance of QEMU with virtio-net guest communication.
+    """
+
+    def __init__(self):
+        """
+        Initialisation function.
+        """
+        super(QemuVirtioNet, self).__init__()
+        self._logger = logging.getLogger(__name__)
+
+        # insert vanilla ovs specific modules
+        tasks.run_task(['sudo', 'modprobe', 'vhost_net'], self._logger,
+                       'Loading vhost_net module...', True)
+
+        # calculate indexes of guest devices (e.g. charx, dpdkvhostuserx)
+        i = self._number * 2
+        if1 = str(i)
+        if2 = str(i + 1)
+        self._net1 = S.getValue('VANILLA_NIC1_NAME')[self._number]
+        self._net2 = S.getValue('VANILLA_NIC2_NAME')[self._number]
+
+        self._cmd += ['-netdev',
+                      'type=tap,id=' + self._net1 +
+                      ',script=no,downscript=no,' +
+                      'ifname=tap' + if1 + ',vhost=on',
+                      '-device',
+                      'virtio-net-pci,mac=' +
+                      S.getValue('GUEST_NET1_MAC')[self._number] +
+                      ',netdev=' + self._net1 + ',csum=off,gso=off,' +
+                      'guest_tso4=off,guest_tso6=off,guest_ecn=off',
+                      '-netdev',
+                      'type=tap,id=' + self._net2 +
+                      ',script=no,downscript=no,' +
+                      'ifname=tap' + if2 + ',vhost=on',
+                      '-device',
+                      'virtio-net-pci,mac=' +
+                      S.getValue('GUEST_NET2_MAC')[self._number] +
+                      ',netdev=' + self._net2 + ',csum=off,gso=off,' +
+                      'guest_tso4=off,guest_tso6=off,guest_ecn=off',
+                     ]
+
+    # helper functions
+
+    def _config_guest_loopback(self):
+        """
+        Configure VM to perform forwarding between NICs
+        """
+
+        # Disable services (F16)
+        self.execute_and_wait('systemctl stop iptables.service')
+        self.execute_and_wait('systemctl stop irqbalance.service')
+
+        nic1_name = get_test_param('vanilla_nic1_name', self._net1)
+        self.execute('ifconfig ' + nic1_name + ' ' +
+                     S.getValue('VANILLA_NIC1_IP_CIDR')[self._number])
+
+        nic2_name = get_test_param('vanilla_nic2_name', self._net2)
+        self.execute('ifconfig ' + nic2_name + ' ' +
+                     S.getValue('VANILLA_NIC2_IP_CIDR')[self._number])
+
+        # configure linux bridge
+        self.execute('brctl addbr br0')
+        self.execute('brctl addif br0 ' + self._net1 + ' ' + self._net2)
+        self.execute('ifconfig br0 ' +
+                     S.getValue('VANILLA_BRIDGE_IP')[self._number])
+
+        # Add the arp entries for the IXIA ports and the bridge you are using.
+        # Use command line values if provided.
+        trafficgen_mac = get_test_param('vanilla_tgen_port1_mac',
+                                        S.getValue('VANILLA_TGEN_PORT1_MAC'))
+        trafficgen_ip = get_test_param('vanilla_tgen_port1_ip',
+                                       S.getValue('VANILLA_TGEN_PORT1_IP'))
+
+        self.execute('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac)
+
+        trafficgen_mac = get_test_param('vanilla_tgen_port2_mac',
+                                        S.getValue('VANILLA_TGEN_PORT2_MAC'))
+        trafficgen_ip = get_test_param('vanilla_tgen_port2_ip',
+                                       S.getValue('VANILLA_TGEN_PORT2_IP'))
+
+        self.execute('arp -s ' + trafficgen_ip + ' ' + trafficgen_mac)
+
+        # Enable forwarding
+        self.execute('sysctl -w net.ipv4.ip_forward=1')
+
+        # Controls source route verification
+        # 0 means no source validation
+        self.execute('sysctl -w net.ipv4.conf.all.rp_filter=0')
+        self.execute('sysctl -w net.ipv4.conf.' + self._net1 + '.rp_filter=0')
+        self.execute('sysctl -w net.ipv4.conf.' + self._net2 + '.rp_filter=0')
index f8d2df9..483faf3 100644 (file)
@@ -121,3 +121,13 @@ class IVnf(tasks.Process):
         """
         self.execute(cmd)
         self.wait(prompt=prompt, timeout=timeout)
+
+    @staticmethod
+    def reset_vnf_counter():
+        """
+        Reset internal VNF counters
+
+        This method is static
+        """
+        IVnf._number_vnfs = 0
+
index 1a53bd6..874cc97 100644 (file)
@@ -158,6 +158,12 @@ class OvsDpdkVhost(IVSwitch):
         bridge = self._bridges[switch_name]
         bridge.del_flow(flow)
 
+    def dump_flows(self, switch_name):
+        """See IVswitch for general description
+        """
+        bridge = self._bridges[switch_name]
+        bridge.dump_flows()
+
     @staticmethod
     def _get_port_count(bridge, param):
         """Returns the number of ports having a certain parameter
index a7d4d20..6716401 100644 (file)
@@ -20,7 +20,9 @@ from conf import settings
 from vswitches.vswitch import IVSwitch
 from src.ovs import VSwitchd, OFBridge
 from tools.module_manager import ModuleManager, KernelModuleInsertMode
+from tools import tasks
 
+_LOGGER = logging.getLogger(__name__)
 VSWITCHD_CONST_ARGS = ['--', '--log-file']
 
 class OvsVanilla(IVSwitch):
@@ -36,6 +38,7 @@ class OvsVanilla(IVSwitch):
     _logger = logging.getLogger()
     _ports = settings.getValue('VSWITCH_VANILLA_PHY_PORT_NAMES')
     _current_id = 0
+    _vport_id = 0
 
     def __init__(self):
         #vswitchd_args = VSWITCHD_CONST_ARGS
@@ -62,9 +65,18 @@ class OvsVanilla(IVSwitch):
 
         Kills ovsdb and vswitchd and removes kernel modules.
         """
+        # remove all tap interfaces
+        for i in range(self._vport_id):
+            tapx = 'tap' + str(i)
+            tasks.run_task(['sudo', 'ip', 'tuntap', 'del',
+                            tapx, 'mode', 'tap'],
+                           _LOGGER, 'Deleting ' + tapx, False)
+        self._vport_id = 0
+
         self._vswitchd.kill()
         self._module_manager.remove_modules()
 
+
     def add_switch(self, switch_name):
         """See IVswitch for general description
         """
@@ -94,16 +106,47 @@ class OvsVanilla(IVSwitch):
                                "defined in config!")
             raise
 
+        if not self._ports[self._current_id]:
+            self._logger.error("VSWITCH_VANILLA_PHY_PORT_NAMES not set")
+            raise ValueError("Invalid VSWITCH_VANILLA_PHY_PORT_NAMES")
+
         bridge = self._bridges[switch_name]
         port_name = self._ports[self._current_id]
         params = []
+
+        # For PVP only
+        tasks.run_task(['sudo', 'ifconfig', port_name, '0'],
+                       _LOGGER, 'Remove IP', False)
+
         of_port = bridge.add_port(port_name, params)
         self._current_id += 1
         return (port_name, of_port)
 
     def add_vport(self, switch_name):
-        """See IVswitch for general description"""
-        raise NotImplementedError("Not implemented for Vanilla OVS.")
+        """
+        Method adds virtual port into OVS vanilla
+
+        See IVswitch for general description
+        """
+        # Create tap devices for the VM
+        tap_name = 'tap' + str(self._vport_id)
+        self._vport_id += 1
+
+        tasks.run_task(['sudo', 'ip', 'tuntap', 'del',
+                        tap_name, 'mode', 'tap'],
+                       _LOGGER, 'Creating tap device...', False)
+
+        tasks.run_task(['sudo', 'ip', 'tuntap', 'add',
+                        tap_name, 'mode', 'tap'],
+                       _LOGGER, 'Creating tap device...', False)
+
+        tasks.run_task(['sudo', 'ifconfig', tap_name, '0'],
+                       _LOGGER, 'Bring up ' + tap_name, False)
+
+        bridge = self._bridges[switch_name]
+        of_port = bridge.add_port(tap_name, [])
+        return (tap_name, of_port)
+
 
     def get_ports(self, switch_name):
         """See IVswitch for general description
@@ -130,3 +173,9 @@ class OvsVanilla(IVSwitch):
         flow = flow or {}
         bridge = self._bridges[switch_name]
         bridge.del_flow(flow)
+
+    def dump_flows(self, switch_name):
+        """See IVswitch for general description
+        """
+        bridge = self._bridges[switch_name]
+        bridge.dump_flows()
index 713974a..dbf3e7d 100644 (file)
@@ -112,3 +112,10 @@ class IVSwitch(object):
         For flow==None, all flows are deleted
         """
         raise NotImplementedError()
+
+    def dump_flows(self, switch_name):
+        """Dump flows from the logical switch
+
+        :param switch_name: The switch on which to operate
+        """
+        raise NotImplementedError()