aboutsummaryrefslogtreecommitdiffstats
path: root/vswitches
diff options
context:
space:
mode:
Diffstat (limited to 'vswitches')
-rw-r--r--vswitches/__init__.py1
-rw-r--r--vswitches/ovs.py239
-rw-r--r--vswitches/ovs_dpdk_vhost.py32
-rw-r--r--vswitches/ovs_vanilla.py25
-rw-r--r--vswitches/vpp_dpdk_vhost.py116
-rw-r--r--vswitches/vswitch.py59
6 files changed, 261 insertions, 211 deletions
diff --git a/vswitches/__init__.py b/vswitches/__init__.py
index a34475be..20a715e0 100644
--- a/vswitches/__init__.py
+++ b/vswitches/__init__.py
@@ -17,4 +17,3 @@
This package contains an interface the VSPERF core uses for controlling
vSwitches and vSwitch-specific implementation modules of this interface.
"""
-
diff --git a/vswitches/ovs.py b/vswitches/ovs.py
index 76cabb0d..6dbf0cf8 100644
--- a/vswitches/ovs.py
+++ b/vswitches/ovs.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,12 +15,13 @@
"""VSPERF Open vSwitch base class
"""
-import logging
import os
import re
import time
import datetime
import random
+import socket
+import netaddr
import pexpect
from conf import settings
@@ -28,6 +29,10 @@ from src.ovs import OFBridge, flow_key, flow_match
from vswitches.vswitch import IVSwitch
from tools import tasks
from tools.module_manager import ModuleManager
+
+# enable caching of flows if their number exceeds given limit
+_CACHE_FLOWS_LIMIT = 10
+
# pylint: disable=too-many-public-methods
class IVSwitchOvs(IVSwitch, tasks.Process):
"""Open vSwitch base class implementation
@@ -41,23 +46,31 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def __init__(self):
"""See IVswitch for general description
"""
+ super().__init__()
self._logfile = os.path.join(settings.getValue('LOG_DIR'),
settings.getValue('LOG_FILE_VSWITCHD'))
self._ovsdb_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
"ovsdb-server.pid")
self._vswitchd_pidfile_path = os.path.join(settings.getValue('TOOLS')['ovs_var_tmp'],
"{}.pid".format(self._proc_name))
- self._logger = logging.getLogger(__name__)
# sign '|' must be escaped or avoided, otherwise it is handled as 'or' by regex
self._expect = r'bridge.INFO.{}'.format(self._proc_name)
- self._timeout = 30
- self._bridges = {}
self._vswitchd_args = ['--pidfile=' + self._vswitchd_pidfile_path,
'--overwrite-pidfile', '--log-file=' + self._logfile]
- self._cmd = []
self._cmd_template = ['sudo', '-E', settings.getValue('TOOLS')['ovs-vswitchd']]
- self._stamp = None
self._module_manager = ModuleManager()
+ self._flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy()
+ self._flow_actions = ['output:{}']
+
+ # if routing tables are enabled, then flows should go into table 1
+ # see design document for details about Routing Tables feature
+ if settings.getValue('OVS_ROUTING_TABLES'):
+ # flows should be added into table 1
+ self._flow_template.update({'table':'1', 'priority':'1'})
+ # and chosen port will be propagated via metadata
+ self._flow_actions = ['write_actions(output:{})',
+ 'write_metadata:{}',
+ 'goto_table:2']
def start(self):
""" Start ``ovsdb-server`` and ``ovs-vswitchd`` instance.
@@ -85,7 +98,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
tasks.Process.start(self)
self.relinquish()
except (pexpect.EOF, pexpect.TIMEOUT) as exc:
- logging.error("Exception during VSwitch start.")
+ self._logger.error("Exception during VSwitch start.")
self._kill_ovsdb()
raise exc
@@ -107,7 +120,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
tasks.Process.start(self)
self.relinquish()
except (pexpect.EOF, pexpect.TIMEOUT) as exc:
- logging.error("Exception during VSwitch start.")
+ self._logger.error("Exception during VSwitch start.")
self._kill_ovsdb()
raise exc
self._logger.info("Vswitchd...Started.")
@@ -128,26 +141,57 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def stop(self):
"""See IVswitch for general description
"""
+ for switch_name in list(self._switches):
+ self.del_switch(switch_name)
self._logger.info("Terminating vswitchd...")
self.kill()
- self._bridges = {}
+ self._switches = {}
self._logger.info("Vswitchd...Terminated.")
def add_switch(self, switch_name, params=None):
"""See IVswitch for general description
"""
+ # create and configure new ovs bridge and delete all default flows
bridge = OFBridge(switch_name)
bridge.create(params)
+ bridge.del_flow({})
bridge.set_db_attribute('Open_vSwitch', '.',
'other_config:max-idle',
settings.getValue('VSWITCH_FLOW_TIMEOUT'))
- self._bridges[switch_name] = bridge
+ self._switches[switch_name] = bridge
+ if settings.getValue('OVS_ROUTING_TABLES'):
+ # table#0 - flows designed to force 5 & 13 tuple matches go here
+ flow = {'table':'0', 'priority':'1', 'actions': ['goto_table:1']}
+ bridge.add_flow(flow)
+
+ # table#1 - flows to route packets between ports goes here. The
+ # chosen port is communicated to subsequent tables by setting the
+ # metadata value to the egress port number
+ #
+ # A placeholder - flows are added into this table by deployments
+ # or by TestSteps via add_connection() method
+
+ # table#2 - frame modification table. Frame modification flow rules are
+ # isolated in this table so that they can be turned on or off
+ # without affecting the routing or tuple-matching flow rules.
+ flow = {'table':'2', 'priority':'1', 'actions': ['goto_table:3']}
+ bridge.add_flow(flow)
+
+ # table#3 - egress table
+ # (NOTE) Billy O'Mahony - the drop action here actually required in
+ # order to egress the packet. This is the subject of a thread on
+ # ovs-discuss 2015-06-30.
+ flow = {'table':'3', 'priority':'1', 'actions': ['drop']}
+ bridge.add_flow(flow)
def del_switch(self, switch_name):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
- self._bridges.pop(switch_name)
+ bridge = self._switches[switch_name]
+ bridge.del_flow({})
+ for port in list(bridge.get_ports()):
+ bridge.del_port(port)
+ self._switches.pop(switch_name)
bridge.destroy()
def add_phy_port(self, switch_name):
@@ -166,10 +210,10 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
"""
if switch_name is None or remote_switch_name is None:
- return
+ return None
- bridge = self._bridges[switch_name]
- remote_bridge = self._bridges[remote_switch_name]
+ bridge = self._switches[switch_name]
+ remote_bridge = self._switches[remote_switch_name]
pcount = str(self._get_port_count('type=patch'))
# NOTE ::: What if interface name longer than allowed width??
local_port_name = switch_name + '-' + remote_switch_name + '-' + pcount
@@ -195,7 +239,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', params=None):
"""Creates tunneling port
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
pcount = str(self._get_port_count('type=' + tunnel_type))
port_name = tunnel_type + pcount
local_params = ['--', 'set', 'Interface', port_name,
@@ -211,53 +255,123 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def get_ports(self, switch_name):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
ports = list(bridge.get_ports().items())
return [(name, of_port) for (name, (of_port, _)) in ports]
def del_port(self, switch_name, port_name):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.del_port(port_name)
def add_flow(self, switch_name, flow, cache='off'):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.add_flow(flow, cache=cache)
def del_flow(self, switch_name, flow=None):
"""See IVswitch for general description
"""
flow = flow or {}
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.del_flow(flow)
def dump_flows(self, switch_name):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.dump_flows()
+ def _prepare_flows(self, operation, switch_name, port1, port2, traffic=None):
+ """Prepare flows for add_connection, del_connection and validate methods
+ It returns a list of flows based on given parameters.
+ """
+ flows = []
+ if operation == 'add':
+ bridge = self._switches[switch_name]
+ flow = self._flow_template.copy()
+ actions = [action.format(bridge.get_ports()[port2][0]) for action in self._flow_actions]
+ flow.update({'in_port': bridge.get_ports()[port1][0], 'actions': actions})
+ # check if stream specific connection(s) should be crated for multistream feature
+ if traffic and traffic['pre_installed_flows'].lower() == 'yes':
+ for stream in range(traffic['multistream']):
+ tmp_flow = flow.copy()
+ # update flow based on trafficgen settings
+ if traffic['stream_type'] == 'L2':
+ dst_mac_value = netaddr.EUI(traffic['l2']['dstmac']).value
+ tmp_mac = netaddr.EUI(dst_mac_value + stream)
+ tmp_mac.dialect = netaddr.mac_unix_expanded
+ tmp_flow.update({'dl_dst':tmp_mac})
+ elif traffic['stream_type'] == 'L3':
+ dst_ip_value = netaddr.IPAddress(traffic['l3']['dstip']).value
+ tmp_ip = netaddr.IPAddress(dst_ip_value + stream)
+ tmp_flow.update({'dl_type':'0x0800', 'nw_dst':tmp_ip})
+ elif traffic['stream_type'] == 'L4':
+ tmp_flow.update({'dl_type':'0x0800',
+ 'nw_proto':socket.getprotobyname(traffic['l3']['proto'].lower()),
+ 'tp_dst':(traffic['l4']['dstport'] + stream) % 65536})
+ flows.append(tmp_flow)
+ elif traffic and traffic['flow_type'].lower() == 'ip':
+ flow.update({'dl_type':'0x0800', 'nw_src':traffic['l3']['srcip'],
+ 'nw_dst':traffic['l3']['dstip']})
+ flows.append(flow)
+ else:
+ flows.append(flow)
+ elif operation == 'del' and port1:
+ bridge = self._switches[switch_name]
+ flows.append({'in_port': bridge.get_ports()[port1][0]})
+ else:
+ flows.append({})
+
+ return flows
+
+ def add_connection(self, switch_name, port1, port2, traffic=None):
+ """See IVswitch for general description
+ """
+ flows = self._prepare_flows('add', switch_name, port1, port2, traffic)
+
+ # enable flows caching for large number of flows
+ cache = 'on' if len(flows) > _CACHE_FLOWS_LIMIT else 'off'
+
+ for flow in flows:
+ self.add_flow(switch_name, flow, cache)
+
+ if cache == 'on':
+ self.add_flow(switch_name, [], cache='flush')
+
+ def del_connection(self, switch_name, port1=None, port2=None):
+ """See IVswitch for general description
+ """
+ flows = self._prepare_flows('del', switch_name, port1, port2)
+
+ for flow in flows:
+ self.del_flow(switch_name, flow)
+
+ def dump_connections(self, switch_name):
+ """See IVswitch for general description
+ """
+ self.dump_flows(switch_name)
+
def add_route(self, switch_name, network, destination):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.add_route(network, destination)
def set_tunnel_arp(self, ip_addr, mac_addr, switch_name):
"""See IVswitch for general description
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.set_tunnel_arp(ip_addr, mac_addr, switch_name)
def _get_port_count(self, param):
"""Returns the number of ports having a certain parameter
"""
cnt = 0
- for k in self._bridges:
- pparams = [c for (_, (_, c)) in list(self._bridges[k].get_ports().items())]
+ for k in self._switches:
+ pparams = [c for (_, (_, c)) in list(self._switches[k].get_ports().items())]
phits = [i for i in pparams if param in i]
cnt += len(phits)
@@ -271,7 +385,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
:param switch_name: bridge to disable stp
:return: None
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.set_stp(False)
self._logger.info('Sleeping for 50 secs to allow stp to stop.')
time.sleep(50) # needs time to disable
@@ -282,7 +396,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
:param switch_name: bridge to enable stp
:return: None
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.set_stp(True)
self._logger.info('Sleeping for 50 secs to allow stp to start.')
time.sleep(50) # needs time to enable
@@ -293,7 +407,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
:param switch_name: bridge to disable rstp
:return: None
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.set_rstp(False)
self._logger.info('Sleeping for 15 secs to allow rstp to stop.')
time.sleep(15) # needs time to disable
@@ -304,7 +418,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
:param switch_name: bridge to enable rstp
:return: None
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
bridge.set_rstp(True)
self._logger.info('Sleeping for 15 secs to allow rstp to start.')
time.sleep(15) # needs time to enable
@@ -382,7 +496,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
with open(self._ovsdb_pidfile_path, "r") as pidfile:
ovsdb_pid = pidfile.read().strip()
- self._logger.info("Killing ovsdb with pid: " + ovsdb_pid)
+ self._logger.info("Killing ovsdb with pid: %s", ovsdb_pid)
if ovsdb_pid:
tasks.terminate_task(ovsdb_pid, logger=self._logger)
@@ -409,10 +523,10 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
#
# validate methods required for integration testcases
#
- def validate_add_switch(self, dummy_result, switch_name, dummy_params=None):
+ def validate_add_switch(self, _dummy_result, switch_name, _dummy_params=None):
"""Validate - Create a new logical switch with no ports
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
output = bridge.run_vsctl(['show'], check_error=True)
assert not output[1] # there shouldn't be any stderr, but in case
assert re.search('Bridge ["\']?%s["\']?' % switch_name, output[0]) is not None
@@ -420,7 +534,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
# Method could be a function
# pylint: disable=no-self-use
- def validate_del_switch(self, dummy_result, switch_name):
+ def validate_del_switch(self, _dummy_result, switch_name):
"""Validate removal of switch
"""
bridge = OFBridge('tmp')
@@ -432,7 +546,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def validate_add_phy_port(self, result, switch_name):
""" Validate that physical port was added to bridge.
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
output = bridge.run_vsctl(['show'], check_error=True)
assert not output[1] # there shouldn't be any stderr, but in case
assert re.search('Port ["\']?%s["\']?' % result[0], output[0]) is not None
@@ -444,16 +558,39 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
"""
return self.validate_add_phy_port(result, switch_name)
- def validate_del_port(self, dummy_result, switch_name, port_name):
+ def validate_del_port(self, _dummy_result, switch_name, port_name):
""" Validate that port_name was removed from bridge.
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
output = bridge.run_vsctl(['show'], check_error=True)
assert not output[1] # there shouldn't be any stderr, but in case
assert 'Port "%s"' % port_name not in output[0]
return True
- def validate_add_flow(self, dummy_result, switch_name, flow, dummy_cache='off'):
+ def validate_add_connection(self, result, switch_name, port1, port2, traffic=None):
+ """ Validate that connection was added
+ """
+ for flow in self._prepare_flows('add', switch_name, port1, port2, traffic):
+ if not self.validate_add_flow(result, switch_name, flow):
+ return False
+
+ return True
+
+ def validate_del_connection(self, result, switch_name, port1, port2):
+ """ Validate that connection was deleted
+ """
+ for flow in self._prepare_flows('del', switch_name, port1, port2):
+ if not self.validate_del_flow(result, switch_name, flow):
+ return False
+
+ return True
+
+ def validate_dump_connections(self, _dummy_result, _dummy_switch_name):
+ """ Validate dump connections call
+ """
+ return True
+
+ def validate_add_flow(self, _dummy_result, switch_name, flow, _dummy_cache='off'):
""" Validate insertion of the flow into the switch
"""
@@ -466,7 +603,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
# get dump of flows and compare them one by one
flow_src = flow_key(flow)
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
output = bridge.run_ofctl(['dump-flows', switch_name], check_error=True)
for flow_dump in output[0].split('\n'):
if flow_match(flow_dump, flow_src):
@@ -474,44 +611,44 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
return True
return False
- def validate_del_flow(self, dummy_result, switch_name, flow=None):
+ def validate_del_flow(self, _dummy_result, switch_name, flow=None):
""" Validate removal of the flow
"""
if not flow:
# what else we can do?
return True
- return not self.validate_add_flow(dummy_result, switch_name, flow)
+ return not self.validate_add_flow(_dummy_result, switch_name, flow)
- def validate_dump_flows(self, dummy_result, dummy_switch_name):
+ def validate_dump_flows(self, _dummy_result, _dummy_switch_name):
""" Validate call of flow dump
"""
return True
- def validate_disable_rstp(self, dummy_result, switch_name):
+ def validate_disable_rstp(self, _dummy_result, switch_name):
""" Validate rstp disable
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
return 'rstp_enable : false' in ''.join(bridge.bridge_info())
- def validate_enable_rstp(self, dummy_result, switch_name):
+ def validate_enable_rstp(self, _dummy_result, switch_name):
""" Validate rstp enable
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
return 'rstp_enable : true' in ''.join(bridge.bridge_info())
- def validate_disable_stp(self, dummy_result, switch_name):
+ def validate_disable_stp(self, _dummy_result, switch_name):
""" Validate stp disable
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
return 'stp_enable : false' in ''.join(bridge.bridge_info())
- def validate_enable_stp(self, dummy_result, switch_name):
+ def validate_enable_stp(self, _dummy_result, switch_name):
""" Validate stp enable
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
return 'stp_enable : true' in ''.join(bridge.bridge_info())
- def validate_restart(self, dummy_result):
+ def validate_restart(self, _dummy_result):
""" Validate restart
"""
return True
diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py
index 6deb0c25..8da043c6 100644
--- a/vswitches/ovs_dpdk_vhost.py
+++ b/vswitches/ovs_dpdk_vhost.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
"""VSPERF VSwitch implementation using DPDK and vhost ports
"""
-import logging
import subprocess
from src.ovs import OFBridge
@@ -36,9 +35,7 @@ class OvsDpdkVhost(IVSwitchOvs):
"""
def __init__(self):
- super(OvsDpdkVhost, self).__init__()
- self._logger = logging.getLogger(__name__)
-
+ super().__init__()
vswitchd_args = []
# legacy DPDK configuration through --dpdk option of vswitchd
@@ -104,9 +101,9 @@ class OvsDpdkVhost(IVSwitchOvs):
if S.getValue('VSWITCH_AFFINITIZATION_ON') == 1:
# Sets the PMD core mask to VSWITCH_PMD_CPU_MASK
# for CPU core affinitization
- self._bridges[switch_name].set_db_attribute('Open_vSwitch', '.',
- 'other_config:pmd-cpu-mask',
- S.getValue('VSWITCH_PMD_CPU_MASK'))
+ self._switches[switch_name].set_db_attribute('Open_vSwitch', '.',
+ 'other_config:pmd-cpu-mask',
+ S.getValue('VSWITCH_PMD_CPU_MASK'))
def add_phy_port(self, switch_name):
"""See IVswitch for general description
@@ -115,7 +112,7 @@ class OvsDpdkVhost(IVSwitchOvs):
The new port is named dpdk<n> where n is an integer starting from 0.
"""
_nics = S.getValue('NICS')
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
dpdk_count = self._get_port_count('type=dpdk')
if dpdk_count == len(_nics):
raise RuntimeError("Can't add phy port! There are only {} ports defined "
@@ -144,7 +141,7 @@ class OvsDpdkVhost(IVSwitchOvs):
The new port is named dpdkvhost<n> where n is an integer starting
from 0
"""
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
nic_type = 'dpdkvhostuser'
@@ -177,18 +174,3 @@ class OvsDpdkVhost(IVSwitchOvs):
return True
except subprocess.CalledProcessError:
return False
-
- def add_connection(self, switch_name, port1, port2, bidir=False):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def del_connection(self, switch_name, port1, port2, bidir=False):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def dump_connections(self, switch_name):
- """See IVswitch for general description
- """
- raise NotImplementedError()
diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py
index 83c52050..d23a0c61 100644
--- a/vswitches/ovs_vanilla.py
+++ b/vswitches/ovs_vanilla.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2017 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
"""VSPERF Vanilla OVS implementation
"""
-import logging
import time
from conf import settings
from vswitches.ovs import IVSwitchOvs
@@ -36,9 +35,8 @@ class OvsVanilla(IVSwitchOvs):
_vport_id = 0
def __init__(self):
- super(OvsVanilla, self).__init__()
+ super().__init__()
self._ports = list(nic['device'] for nic in settings.getValue('NICS'))
- self._logger = logging.getLogger(__name__)
self._vswitchd_args += ["unix:%s" % self.get_db_sock_path()]
self._vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS')
@@ -81,7 +79,7 @@ class OvsVanilla(IVSwitchOvs):
self._logger.error("Can't detect device name for NIC %s", self._current_id)
raise ValueError("Invalid device name for %s" % self._current_id)
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
port_name = self._ports[self._current_id]
params = []
@@ -129,21 +127,6 @@ class OvsVanilla(IVSwitchOvs):
tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', tap_name, 'up'],
self._logger, 'Bring up ' + tap_name, False)
- bridge = self._bridges[switch_name]
+ bridge = self._switches[switch_name]
of_port = bridge.add_port(tap_name, [])
return (tap_name, of_port)
-
- def add_connection(self, switch_name, port1, port2, bidir=False):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def del_connection(self, switch_name, port1, port2, bidir=False):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def dump_connections(self, switch_name):
- """See IVswitch for general description
- """
- raise NotImplementedError()
diff --git a/vswitches/vpp_dpdk_vhost.py b/vswitches/vpp_dpdk_vhost.py
index 58d6bf51..5d676a01 100644
--- a/vswitches/vpp_dpdk_vhost.py
+++ b/vswitches/vpp_dpdk_vhost.py
@@ -1,4 +1,4 @@
-# Copyright 2017 Intel Corporation.
+# Copyright 2017-2018 Intel Corporation., Tieto
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
"""VSPERF VPP implementation using DPDK and vhostuser vports
"""
-import logging
import os
import copy
import re
@@ -37,19 +36,13 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
def __init__(self):
"""See IVswitch for general description
"""
+ super().__init__()
self._logfile = os.path.join(S.getValue('LOG_DIR'),
S.getValue('LOG_FILE_VPP'))
- self._logger = logging.getLogger(__name__)
self._expect = r'vpp#'
- self._timeout = 30
- self._vswitch_args = []
- self._cmd = []
self._cmd_template = ['sudo', '-E', S.getValue('TOOLS')['vpp']]
- self._stamp = None
- self._logger = logging.getLogger(__name__)
self._phy_ports = []
self._virt_ports = []
- self._switches = {}
self._vpp_ctl = ['sudo', S.getValue('TOOLS')['vppctl']]
# configure DPDK NICs
@@ -151,7 +144,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
tasks.Process.start(self)
self.relinquish()
except (pexpect.EOF, pexpect.TIMEOUT) as exc:
- logging.error("Exception during VPP start.")
+ self._logger.error("Exception during VPP start.")
raise exc
self._logger.info("VPP...Started.")
@@ -205,6 +198,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
def add_switch(self, switch_name, dummy_params=None):
"""See IVswitch for general description
"""
+ # pylint: disable=unused-argument
if switch_name in self._switches:
self._logger.warning("switch %s already exists...", switch_name)
else:
@@ -221,6 +215,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
"""See IVswitch for general description
:raises: RuntimeError
"""
+ # pylint: disable=unused-argument
# get list of physical interfaces with PCI addresses
vpp_nics = self._get_nic_info(key='Pci')
# check if there are any NICs left
@@ -239,6 +234,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
def add_vport(self, dummy_switch_name):
"""See IVswitch for general description
"""
+ # pylint: disable=unused-argument
socket_name = S.getValue('TOOLS')['ovs_var_tmp'] + 'dpdkvhostuser' + str(len(self._virt_ports))
if S.getValue('VSWITCH_VHOSTUSER_SERVER_MODE'):
mode = ['server']
@@ -266,21 +262,17 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
else:
self._logger.warning("Port %s is not configured.", port_name)
- def add_l2patch(self, port1, port2, bidir=False):
+ def add_l2patch(self, port1, port2):
"""Create l2patch connection between given ports
"""
self.run_vppctl(['test', 'l2patch', 'rx', port1, 'tx', port2])
- if bidir:
- self.run_vppctl(['test', 'l2patch', 'rx', port2, 'tx', port1])
- def add_xconnect(self, port1, port2, bidir=False):
+ def add_xconnect(self, port1, port2):
"""Create l2patch connection between given ports
"""
self.run_vppctl(['set', 'interface', 'l2', 'xconnect', port1, port2])
- if bidir:
- self.run_vppctl(['set', 'interface', 'l2', 'xconnect', port2, port1])
- def add_bridge(self, switch_name, port1, port2, dummy_bidir=False):
+ def add_bridge(self, switch_name, port1, port2):
"""Add given ports to bridge ``switch_name``
"""
self.run_vppctl(['set', 'interface', 'l2', 'bridge', port1,
@@ -288,56 +280,59 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
self.run_vppctl(['set', 'interface', 'l2', 'bridge', port2,
str(self._switches[switch_name])])
- def add_connection(self, switch_name, port1, port2, bidir=False):
+ def add_connection(self, switch_name, port1, port2, traffic=None):
"""See IVswitch for general description
:raises: RuntimeError
"""
+ if traffic:
+ self._logger.warning("VPP add_connection() does not support 'traffic' options.")
+
mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
if mode == 'l2patch':
- self.add_l2patch(port1, port2, bidir)
+ self.add_l2patch(port1, port2)
elif mode == 'xconnect':
- self.add_xconnect(port1, port2, bidir)
+ self.add_xconnect(port1, port2)
elif mode == 'bridge':
self.add_bridge(switch_name, port1, port2)
else:
- raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s' % mode)
- def del_l2patch(self, port1, port2, bidir=False):
+ def del_l2patch(self, port1, port2):
"""Remove l2patch connection between given ports
:param port1: port to be used in connection
:param port2: port to be used in connection
- :param bidir: switch between uni and bidirectional traffic
"""
self.run_vppctl(['test', 'l2patch', 'rx', port1, 'tx', port2, 'del'])
- if bidir:
- self.run_vppctl(['test', 'l2patch', 'rx', port2, 'tx', port1, 'del'])
- def del_xconnect(self, dummy_port1, dummy_port2, dummy_bidir=False):
+ def del_xconnect(self, port1, port2):
"""Remove xconnect connection between given ports
"""
- self._logger.warning('VPP: Removal of l2 xconnect is not implemented.')
+ self.run_vppctl(['set', 'interface', 'l3', port1])
+ self.run_vppctl(['set', 'interface', 'l3', port2])
- def del_bridge(self, dummy_switch_name, dummy_port1, dummy_port2):
+ def del_bridge(self, _dummy_switch_name, port1, port2):
"""Remove given ports from the bridge
"""
- self._logger.warning('VPP: Removal of interfaces from bridge is not implemented.')
+ self.run_vppctl(['set', 'interface', 'l3', port1])
+ self.run_vppctl(['set', 'interface', 'l3', port2])
- def del_connection(self, switch_name, port1, port2, bidir=False):
+ def del_connection(self, switch_name, port1=None, port2=None):
"""See IVswitch for general description
:raises: RuntimeError
"""
- mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
- if mode == 'l2patch':
- self.del_l2patch(port1, port2, bidir)
- elif mode == 'xconnect':
- self.del_xconnect(port1, port2, bidir)
- elif mode == 'bridge':
- self.del_bridge(switch_name, port1, port2)
- else:
- raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+ if port1 and port2:
+ mode = S.getValue('VSWITCH_VPP_L2_CONNECT_MODE')
+ if mode == 'l2patch':
+ self.del_l2patch(port1, port2)
+ elif mode == 'xconnect':
+ self.del_xconnect(port1, port2)
+ elif mode == 'bridge':
+ self.del_bridge(switch_name, port1, port2)
+ else:
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s' % mode)
def dump_l2patch(self):
"""Dump l2patch connections
@@ -347,7 +342,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
def dump_xconnect(self):
"""Dump l2 xconnect connections
"""
- self._logger.warning("VPP: Dump of l2 xconnections is not supported.")
+ self.run_vppctl(['show', 'mode'] + self._phy_ports + self._virt_ports)
def dump_bridge(self, switch_name):
"""Show bridge details
@@ -369,7 +364,7 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
elif mode == 'bridge':
self.dump_bridge(switch_name)
else:
- raise RuntimeError('VPP: Unsupported l2 connection mode detected %s', mode)
+ raise RuntimeError('VPP: Unsupported l2 connection mode detected %s' % mode)
def run_vppctl(self, args, check_error=False):
"""Run ``vppctl`` with supplied arguments.
@@ -385,50 +380,50 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
#
# Validate methods
#
- def validate_add_switch(self, dummy_result, switch_name, dummy_params=None):
+ def validate_add_switch(self, _dummy_result, switch_name, _dummy_params=None):
"""Validate - Create a new logical switch with no ports
"""
return switch_name in self._switches
- def validate_del_switch(self, dummy_result, switch_name):
+ def validate_del_switch(self, _dummy_result, switch_name):
"""Validate removal of switch
"""
- return not self.validate_add_switch(dummy_result, switch_name)
+ return not self.validate_add_switch(_dummy_result, switch_name)
- def validate_add_phy_port(self, result, dummy_switch_name):
+ def validate_add_phy_port(self, result, _dummy_switch_name):
""" Validate that physical port was added to bridge.
"""
return result[0] in self._phy_ports
- def validate_add_vport(self, result, dummy_switch_name):
+ def validate_add_vport(self, result, _dummy_switch_name):
""" Validate that virtual port was added to bridge.
"""
return result[0] in self._virt_ports
- def validate_del_port(self, dummy_result, dummy_switch_name, port_name):
+ def validate_del_port(self, _dummy_result, _dummy_switch_name, port_name):
""" Validate that port_name was removed from bridge.
"""
return not (port_name in self._phy_ports or port_name in self._virt_ports)
# pylint: disable=no-self-use
- def validate_add_connection(self, dummy_result, dummy_switch_name, dummy_port1,
- dummy_port2, dummy_bidir=False):
+ def validate_add_connection(self, _dummy_result, _dummy_switch_name, _dummy_port1,
+ _dummy_port2, _dummy_traffic=None):
""" Validate that connection was added
"""
return True
- def validate_del_connection(self, dummy_result, dummy_switch_name, dummy_port1,
- dummy_port2, dummy_bidir=False):
+ def validate_del_connection(self, _dummy_result, _dummy_switch_name, _dummy_port1,
+ _dummy_port2):
""" Validate that connection was deleted
"""
return True
- def validate_dump_connections(self, dummy_result, dummy_switch_name):
+ def validate_dump_connections(self, _dummy_result, _dummy_switch_name):
""" Validate dump connections call
"""
return True
- def validate_run_vppctl(self, result, dummy_args, dummy_check_error=False):
+ def validate_run_vppctl(self, result, _dummy_args, _dummy_check_error=False):
"""validate execution of ``vppctl`` with supplied arguments.
"""
# there shouldn't be any stderr
@@ -437,21 +432,6 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
#
# Non implemented methods
#
- def add_flow(self, switch_name, flow, cache='off'):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def del_flow(self, switch_name, flow=None):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
- def dump_flows(self, switch_name):
- """See IVswitch for general description
- """
- raise NotImplementedError()
-
def add_route(self, switch_name, network, destination):
"""See IVswitch for general description
"""
diff --git a/vswitches/vswitch.py b/vswitches/vswitch.py
index efa3a349..a3d4e974 100644
--- a/vswitches/vswitch.py
+++ b/vswitches/vswitch.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2016 Intel Corporation.
+# Copyright 2015-2018 Intel Corporation., Tieto
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,12 +14,23 @@
"""Generic interface VSPERF uses for controlling a vSwitch
"""
+import logging
class IVSwitch(object):
"""Interface class that is implemented by vSwitch-specific classes
Other methods are called only between start() and stop()
"""
+ def __init__(self):
+ """Initialization of vswitch class
+ """
+ self._timeout = 30
+ self._switches = {}
+ self._logger = logging.getLogger(__name__)
+ self._cmd = []
+ self._vswitch_args = []
+ self._stamp = None
+
def get_version(self):
"""Return version of vSwitch and DPDK (if used by vSwitch)
This method should be implemented in case, that version
@@ -112,58 +123,23 @@ class IVSwitch(object):
"""
raise NotImplementedError()
- def add_flow(self, switch_name, flow, cache='off'):
- """Add a flow rule to the logical switch
-
- :param switch_name: The switch on which to operate
- :param flow: Flow description as a dictionary
- :param cache: Optional. Specifies if flow should be inserted
- to the switch or cached to increase performance during manipulation
- with large number of flows.
- Values:
- 'off' - cache is off and flow is inserted directly to the switch
- 'on' - cache is on and flow is inserted into the cache
- 'flush' - cache content will be inserted into the switch
-
- Example flow dictionary:
- flow = {
- 'in_port': '1',
- 'idle_timeout': '0',
- 'actions': ['output:3']
- }
- """
- raise NotImplementedError()
-
- def del_flow(self, switch_name, flow=None):
- """Delete the flow rule from the logical switch
-
- :param switch_name: The switch on which to operate
- :param flow: Flow description as a dictionary
-
- For flow dictionary description, see add_flow
- For flow==None, all flows are deleted
- """
- raise NotImplementedError()
-
- def add_connection(self, switch_name, port1, port2, bidir=False):
+ def add_connection(self, switch_name, port1, port2, traffic=None):
"""Creates connection between given ports.
:param switch_name: switch on which to operate
:param port1: port to be used in connection
:param port2: port to be used in connection
- :param bidir: switch between uni and bidirectional traffic
:raises: RuntimeError
"""
raise NotImplementedError()
- def del_connection(self, switch_name, port1, port2, bidir=False):
+ def del_connection(self, switch_name, port1=None, port2=None):
"""Remove connection between two interfaces.
:param switch_name: switch on which to operate
:param port1: port to be used in connection
:param port2: port to be used in connection
- :param bidir: switch between uni and bidirectional traffic
:raises: RuntimeError
"""
@@ -178,13 +154,6 @@ class IVSwitch(object):
"""
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()
-
def add_route(self, switch_name, network, destination):
"""Add a route for tunneling routing table