aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconf/01_testcases.conf12
-rw-r--r--core/vswitch_controller_p2p.py49
-rw-r--r--requirements.txt1
-rw-r--r--src/ovs/ofctl.py34
-rw-r--r--testcases/testcase.py3
-rw-r--r--vswitches/ovs_dpdk_vhost.py4
-rw-r--r--vswitches/ovs_vanilla.py4
-rw-r--r--vswitches/vswitch.py9
8 files changed, 102 insertions, 14 deletions
diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf
index fd268bed..b855405d 100755
--- a/conf/01_testcases.conf
+++ b/conf/01_testcases.conf
@@ -43,6 +43,18 @@
# # "L3" - iteration of destination IP address
# # "L4" - iteration of destination UDP port
# # Default value is "L4".
+# "Pre-installed Flows": ["Yes"|"No"]
+# # Optional. Pre-installed Flows is an extension
+# # of the "MultiStream" feature. If MultiStream
+# # is disabled, then Pre-installed Flows will be
+# # ignored. It defines if stream specific flows
+# # will be inserted into OVS or not.
+# # It can be overridden by cli option
+# # pre-installed_flows
+# # Values:
+# # "Yes" - flows will be inserted into OVS
+# # "No" - flows won't be inserted into OVS
+# # Default value is "No".
# "Flow Type": ["port"|"IP"] # Optional. Defines flows complexity. In case
# # it isn't specified, then "port" will be used.
# # Values:
diff --git a/core/vswitch_controller_p2p.py b/core/vswitch_controller_p2p.py
index 236a443a..91c4e8a0 100644
--- a/core/vswitch_controller_p2p.py
+++ b/core/vswitch_controller_p2p.py
@@ -16,6 +16,7 @@
"""
import logging
+import netaddr
from core.vswitch_controller import IVswitchController
from conf import settings
@@ -24,6 +25,9 @@ _FLOW_TEMPLATE = {
'idle_timeout': '0'
}
+_PROTO_TCP = 6
+_PROTO_UDP = 17
+
class VswitchControllerP2P(IVswitchController):
"""VSwitch controller for P2P deployment scenario.
@@ -79,12 +83,12 @@ class VswitchControllerP2P(IVswitchController):
flow.update({'table':'1', 'priority':'1', 'in_port':'1',
'actions': ['write_actions(output:2)', 'write_metadata:2',
'goto_table:2']})
- self._vswitch.add_flow(bridge, flow)
+ self.process_flow_template(bridge, flow)
flow = flow_template.copy()
flow.update({'table':'1', 'priority':'1', 'in_port':'2',
'actions': ['write_actions(output:1)', 'write_metadata:1',
'goto_table:2']})
- self._vswitch.add_flow(bridge, flow)
+ self.process_flow_template(bridge, flow)
# Frame modification table. Frame modification flow rules are
# isolated in this table so that they can be turned on or off
@@ -129,3 +133,44 @@ class VswitchControllerP2P(IVswitchController):
"""See IVswitchController for description
"""
self._vswitch.dump_flows(settings.getValue('VSWITCH_BRIDGE_NAME'))
+
+ def process_flow_template(self, bridge, flow_template):
+ """Method adds flows into the vswitch based on given flow template
+ and configuration of multistream feature.
+ """
+ if ('pre_installed_flows' in self._traffic and
+ self._traffic['pre_installed_flows'].lower() == 'yes' and
+ 'multistream' in self._traffic and self._traffic['multistream'] > 0 and
+ 'stream_type' in self._traffic):
+ # multistream feature is enabled and flows should be inserted into OVS
+ # so generate flows based on template and multistream configuration
+ if self._traffic['stream_type'] == 'L2':
+ # iterate through destimation MAC address
+ dst_mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value
+ for i in range(int(self._traffic['multistream'])):
+ tmp_mac = netaddr.EUI(dst_mac_value + i)
+ tmp_mac.dialect = netaddr.mac_unix_expanded
+ flow_template.update({'dl_dst':tmp_mac})
+ # optimize flow insertion by usage of cache
+ self._vswitch.add_flow(bridge, flow_template, cache='on')
+ elif self._traffic['stream_type'] == 'L3':
+ # iterate through destimation IP address
+ dst_ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value
+ for i in range(int(self._traffic['multistream'])):
+ tmp_ip = netaddr.IPAddress(dst_ip_value + i)
+ flow_template.update({'dl_type':'0x800', 'nw_dst':tmp_ip})
+ # optimize flow insertion by usage of cache
+ self._vswitch.add_flow(bridge, flow_template, cache='on')
+ elif self._traffic['stream_type'] == 'L4':
+ # read transport protocol from configuration and iterate through its destination port
+ proto = _PROTO_TCP if self._traffic['l3']['proto'].lower() == 'tcp' else _PROTO_UDP
+ for i in range(int(self._traffic['multistream'])):
+ flow_template.update({'dl_type':'0x800', 'nw_proto':proto, 'tp_dst':i})
+ # optimize flow insertion by usage of cache
+ self._vswitch.add_flow(bridge, flow_template, cache='on')
+ else:
+ self._logger.error('Stream type is set to uknown value %s', self._traffic['stream_type'])
+ # insert cached flows into the OVS
+ self._vswitch.add_flow(bridge, [], cache='flush')
+ else:
+ self._vswitch.add_flow(bridge, flow_template)
diff --git a/requirements.txt b/requirements.txt
index 39f0a090..16b7ba1f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@ tox==1.8.1
jinja2==2.7.3
xmlrunner==1.7.7
requests==2.8.1
+netaddr==0.7.18
diff --git a/src/ovs/ofctl.py b/src/ovs/ofctl.py
index c052f85c..9d16ef76 100644
--- a/src/ovs/ofctl.py
+++ b/src/ovs/ofctl.py
@@ -34,6 +34,8 @@ _OVS_OFCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities',
_OVS_BRIDGE_NAME = settings.getValue('VSWITCH_BRIDGE_NAME')
+_CACHE_FILE_NAME = '/tmp/vsperf_flows_cache'
+
class OFBase(object):
"""Add/remove/show datapaths using ``ovs-ofctl``.
"""
@@ -103,6 +105,7 @@ class OFBridge(OFBase):
super(OFBridge, self).__init__(timeout)
self.br_name = br_name
self._ports = {}
+ self._cache_file = None
# context manager
@@ -121,7 +124,7 @@ class OFBridge(OFBase):
# helpers
- def run_ofctl(self, args, check_error=False):
+ def run_ofctl(self, args, check_error=False, timeout=None):
"""Run ``ovs-ofctl`` with supplied arguments.
:param args: Arguments to pass to ``ovs-ofctl``
@@ -129,8 +132,9 @@ class OFBridge(OFBase):
:return: None
"""
+ tmp_timeout = self.timeout if timeout == None else timeout
cmd = ['sudo', _OVS_OFCTL_BIN, '-O', 'OpenFlow13', '--timeout',
- str(self.timeout)] + args
+ str(tmp_timeout)] + args
return tasks.run_task(
cmd, self.logger, 'Running ovs-ofctl...', check_error)
@@ -233,7 +237,7 @@ class OFBridge(OFBase):
# flow mangement
- def add_flow(self, flow):
+ def add_flow(self, flow, cache='off'):
"""Add flow to bridge.
:param flow: Flow description as a dictionary
@@ -241,14 +245,32 @@ class OFBridge(OFBase):
:return: None
"""
+ # insert flows from cache into OVS if needed
+ if cache == 'flush':
+ if self._cache_file == None:
+ self.logger.error('flow cache flush called, but nothing is cached')
+ return
+ self.logger.debug('flows cached in %s will be added to the bridge', _CACHE_FILE_NAME)
+ self._cache_file.close()
+ self._cache_file = None
+ self.run_ofctl(['add-flows', self.br_name, _CACHE_FILE_NAME], timeout=600)
+ return
+
if not flow.get('actions'):
self.logger.error('add flow requires actions')
return
- self.logger.debug('add flow')
_flow_key = flow_key(flow)
self.logger.debug('key : %s', _flow_key)
- self.run_ofctl(['add-flow', self.br_name, _flow_key])
+
+ # insert flow to the cache or OVS
+ if cache == 'on':
+ # create and open cache file if needed
+ if self._cache_file == None:
+ self._cache_file = open(_CACHE_FILE_NAME, 'w')
+ self._cache_file.write(_flow_key + '\n')
+ else:
+ self.run_ofctl(['add-flow', self.br_name, _flow_key])
def del_flow(self, flow):
"""Delete flow from bridge.
@@ -274,7 +296,7 @@ class OFBridge(OFBase):
"""Dump all flows from bridge.
"""
self.logger.debug('dump flows')
- self.run_ofctl(['dump-flows', self.br_name])
+ self.run_ofctl(['dump-flows', self.br_name], timeout=120)
#
# helper functions
diff --git a/testcases/testcase.py b/testcases/testcase.py
index 986fbe4b..a152f91e 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -70,7 +70,8 @@ class TestCase(object):
multistream = get_test_param('multistream', multistream)
stream_type = cfg.get('Stream Type', 'L4')
stream_type = get_test_param('stream_type', stream_type)
- pre_installed_flows = False # placeholder for VSPERF-83 implementation
+ pre_installed_flows = cfg.get('Pre-installed Flows', 'No')
+ pre_installed_flows = get_test_param('pre-installed_flows', pre_installed_flows)
# check if test requires background load and which generator it uses
diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py
index cf60a5e2..2c7b81ff 100644
--- a/vswitches/ovs_dpdk_vhost.py
+++ b/vswitches/ovs_dpdk_vhost.py
@@ -148,11 +148,11 @@ class OvsDpdkVhost(IVSwitch):
bridge = self._bridges[switch_name]
bridge.del_port(port_name)
- def add_flow(self, switch_name, flow):
+ def add_flow(self, switch_name, flow, cache='off'):
"""See IVswitch for general description
"""
bridge = self._bridges[switch_name]
- bridge.add_flow(flow)
+ bridge.add_flow(flow, cache=cache)
def del_flow(self, switch_name, flow=None):
"""See IVswitch for general description
diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py
index c6617404..3078de02 100644
--- a/vswitches/ovs_vanilla.py
+++ b/vswitches/ovs_vanilla.py
@@ -164,11 +164,11 @@ class OvsVanilla(IVSwitch):
bridge = self._bridges[switch_name]
bridge.del_port(port_name)
- def add_flow(self, switch_name, flow):
+ def add_flow(self, switch_name, flow, cache='off'):
"""See IVswitch for general description
"""
bridge = self._bridges[switch_name]
- bridge.add_flow(flow)
+ bridge.add_flow(flow, cache=cache)
def del_flow(self, switch_name, flow=None):
"""See IVswitch for general description
diff --git a/vswitches/vswitch.py b/vswitches/vswitch.py
index fbec861a..a28c0f6b 100644
--- a/vswitches/vswitch.py
+++ b/vswitches/vswitch.py
@@ -89,11 +89,18 @@ class IVSwitch(object):
"""
raise NotImplementedError()
- def add_flow(self, switch_name, flow):
+ 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 = {