aboutsummaryrefslogtreecommitdiffstats
path: root/vswitches
diff options
context:
space:
mode:
authorMartin Klozik <martin.klozik@tieto.com>2018-05-15 01:42:35 -0700
committerMartin Klozik <martin.klozik@tieto.com>2018-05-28 05:48:23 -0700
commit63b56ed1d74657129006f066a3f118c4c369d23c (patch)
tree33624c57bbf9800668647da82bb9d6edbd1bcd93 /vswitches
parentc79adfe7660ffa43f597af794412c0616a785943 (diff)
connections: Introduction of generic API
Redesign of vSwitch and vSwitch controller classes, to use generic connection methods for configuration of vSwitch. This API is more generic and vSwitch agnostic, thus deployment scenarios like P2P, PVP, PVVP (i.e. PVVPx) can be used for all (currently) supported vSwitches. Usage of new API will simplify an introduction of new vSwitches in the future. This patchset introduces following changes: * OVS: implementation of add_, del_, dump_ connection(s) and their validation methods * VPP: bidir parameter removed - it is up to the deployment scenario implementation to take care about bidirectional connections * P2P and PXP controllers were updated to use connection methods instead of flow related methods. Thus standard TCs will support both OVS and VPP. NOTE, PVPV is not supported for VPP (yet?). * refactoring of vSwitch interfaces and inherited classes * VPP step driven TCs were replaced by standard TCs with appropriate deployment scenarios. This is for backward compatibility with TC reporting. Once reporting of VPP TC results into results DB will be modified, this TCs can be removed. * OVS routing tables support was generalized to support P2P and PXP deployments and step driven TCs. Usage of OVS routing tables is now configurable (turned off by default) for better comparison of results among various vSwitches. * Multistream pre_installed_flows feature was generalized to support P2P and PXP deployments and step driven TCs. * IxNet: TRAFFIC['l4']['dstport'] will be used as a start value for port iteration if L4 multistream feature is enabled. * OVS: default flow template is now configurable via OVS_FLOW_TEMPLATE * OVS: support of TRAFFIC['flow_type']='ip' was generalized to work with connection methods (i.e. with P2P and PXP deployments and step driven TCs) * integration TCs: modification of integration TCs and their macros to utilize new generic connection based API * CI: list of TCs for VERIFY & MERGE jobs was changed to run the same generic tests for both OVS & VPP * documentation update * small fixes and improvements JIRA: VSPERF-579 Change-Id: If4e6e6037929eab9f16c2bbcb8a0fb30e5d6f9b0 Signed-off-by: Martin Klozik <martin.klozik@tieto.com> Reviewed-by: Richard Elias <richard.elias@tieto.com> Reviewed-by: Al Morton <acmorton@att.com> Reviewed-by: Christian Trautman <ctrautma@redhat.com> Reviewed-by: Sridhar Rao <sridhar.rao@spirent.com>
Diffstat (limited to 'vswitches')
-rw-r--r--vswitches/ovs.py208
-rw-r--r--vswitches/ovs_dpdk_vhost.py32
-rw-r--r--vswitches/ovs_vanilla.py25
-rw-r--r--vswitches/vpp_dpdk_vhost.py79
-rw-r--r--vswitches/vswitch.py59
5 files changed, 222 insertions, 181 deletions
diff --git a/vswitches/ovs.py b/vswitches/ovs.py
index be7b77df..6dbf0cf8 100644
--- a/vswitches/ovs.py
+++ b/vswitches/ovs.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Intel Corporation, Tieto and Others.
+# 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,31 +141,57 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
def stop(self):
"""See IVswitch for general description
"""
- for switch_name in list(self._bridges):
+ 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]
+ bridge = self._switches[switch_name]
bridge.del_flow({})
for port in list(bridge.get_ports()):
bridge.del_port(port)
- self._bridges.pop(switch_name)
+ self._switches.pop(switch_name)
bridge.destroy()
def add_phy_port(self, switch_name):
@@ -173,8 +212,8 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
if switch_name is None or remote_switch_name is None:
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
@@ -200,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,
@@ -216,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)
@@ -276,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
@@ -287,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
@@ -298,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
@@ -309,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
@@ -417,7 +526,7 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
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
@@ -437,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
@@ -452,12 +561,35 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
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_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
"""
@@ -471,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):
@@ -495,25 +627,25 @@ class IVSwitchOvs(IVSwitch, tasks.Process):
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):
""" 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):
""" 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):
""" 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):
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 15e32f32..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.")
@@ -269,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,
@@ -291,33 +280,33 @@ 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)
- 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, port1, port2, _dummy_bidir=False):
+ def del_xconnect(self, port1, port2):
"""Remove xconnect connection between given ports
"""
self.run_vppctl(['set', 'interface', 'l3', port1])
@@ -329,20 +318,21 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
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
@@ -417,13 +407,13 @@ class VppDpdkVhost(IVSwitch, tasks.Process):
# pylint: disable=no-self-use
def validate_add_connection(self, _dummy_result, _dummy_switch_name, _dummy_port1,
- _dummy_port2, _dummy_bidir=False):
+ _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):
+ _dummy_port2):
""" Validate that connection was deleted
"""
return True
@@ -442,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