From f463c563912abb806fe0d2fe85a4cf6825f416cc Mon Sep 17 00:00:00 2001 From: Dino Simeon Madarang Date: Mon, 19 Oct 2015 14:55:06 +0100 Subject: [PATCH] Add OVS tunnel encapsulation performance test Measure OVS DPDK and native VXLAN/GRE/GENEVE encapsulation performance. This patch creates a new deployment scenario, Overlay_P2P. The DUT is configured as a TEP (Tunnel Endpoint) which performs encapsulation of frames and sends traffic to the 2nd traffic generator port. The traffic generator in this case receives an encapsulated frame. No decapsulation is performed in this testcase. Introduce a vsperf param, --run-integration, to filter tests to integration tests. When running integration tests, variables defined in the directory conf/integration/*conf as well as the conf/*.conf are available. This test case requires DPDK 2.1.0 and OVS master - 6bb4a18 or newer. Change-Id: Ide2f418909d647119388df9b30d0d0a3656b4e53 JIRA: VSPERF-180 Signed-off-by: Dino Simeon Madarang Reviewed-by: Maryam Tahhan Reviewed-by: Al Morton --- conf/integration/01_testcases.conf | 49 +++++++++++++ conf/integration/02_vswitch.conf | 24 +++++++ conf/integration/03_traffic.conf | 20 ++++++ core/component_factory.py | 7 +- core/vnf_controller.py | 6 +- core/vswitch_controller_op2p.py | 140 +++++++++++++++++++++++++++++++++++++ docs/configguide/index.rst | 1 + docs/userguide/index.rst | 1 + docs/userguide/integration.rst | 97 +++++++++++++++++++++++++ src/ovs/ofctl.py | 50 ++++++++++++- testcases/testcase.py | 19 ++++- vsperf | 8 +++ vswitches/ovs_dpdk_vhost.py | 50 ++++++++++--- vswitches/ovs_vanilla.py | 49 ++++++++++++- vswitches/vswitch.py | 28 +++++++- 15 files changed, 528 insertions(+), 21 deletions(-) create mode 100644 conf/integration/01_testcases.conf create mode 100644 conf/integration/02_vswitch.conf create mode 100644 conf/integration/03_traffic.conf create mode 100644 core/vswitch_controller_op2p.py create mode 100755 docs/userguide/integration.rst diff --git a/conf/integration/01_testcases.conf b/conf/integration/01_testcases.conf new file mode 100644 index 00000000..99154ad3 --- /dev/null +++ b/conf/integration/01_testcases.conf @@ -0,0 +1,49 @@ +# Copyright 2015-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. + +# The 1st value of SUPPORTED_TUNNELING_PROTO is used as the default +# tunneling protocol for OP2P tests. +SUPPORTED_TUNNELING_PROTO = ['vxlan', 'gre', 'geneve'] + +# Required for OP2P tests +# "Tunnel Type": ["vxlan"|"gre"|"geneve"] # Tunnel Type defines tunneling protocol to use. +# # It can be overridden by cli option tunnel_type. +# # Values: +# # "vxlan" - iteration of destination MAC address +# # "gre" - iteration of destination IP address +# # "geneve" - iteration of destination UDP port +# # Default value is "vxlan". +# +# biDirectional testing for OP2P is not yet supported. +# biDirectional must be set to False. + +INTEGRATION_TESTS = [ + { + "Name": "overlay_p2p_tput", + "Traffic Type": "rfc2544", + "Deployment": "op2p", + "biDirectional": False, + "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], + "Description": "Overlay Encapsulation Throughput RFC2544 Test", + }, + { + "Name": "overlay_p2p_cont", + "Traffic Type": "continuous", + "Deployment": "op2p", + "biDirectional": False, + "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], + "Description": "Overlay Encapsulation Continuous Stream", + }, +] + diff --git a/conf/integration/02_vswitch.conf b/conf/integration/02_vswitch.conf new file mode 100644 index 00000000..20cec3e6 --- /dev/null +++ b/conf/integration/02_vswitch.conf @@ -0,0 +1,24 @@ +# Copyright 2015-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. + +# Tunnel endpoint for Overlay P2P deployment scenario +VTEP_IP1 = '192.168.0.1/24' +VTEP_IP2 = '192.168.240.10' +VTEP_IP2_SUBNET = '192.168.240.0/24' +TUNNEL_INTEGRATION_BRIDGE = 'br0' +TUNNEL_EXTERNAL_BRIDGE = 'br-ext' +TUNNEL_EXTERNAL_BRIDGE_IP = '192.168.240.1/24' + +# vxlan|gre|geneve +TUNNEL_TYPE = 'vxlan' diff --git a/conf/integration/03_traffic.conf b/conf/integration/03_traffic.conf new file mode 100644 index 00000000..8bef092a --- /dev/null +++ b/conf/integration/03_traffic.conf @@ -0,0 +1,20 @@ +# Copyright 2015-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. + +# For OP2P deployment scenario +TRAFFICGEN_PORT1_MAC = '02:00:00:00:00:01' +TRAFFICGEN_PORT2_MAC = '02:00:00:00:00:02' +TRAFFICGEN_PORT1_IP = '1.1.1.1' +TRAFFICGEN_PORT2_IP = '90.90.90.90' + diff --git a/core/component_factory.py b/core/component_factory.py index af237e50..1e5f2266 100644 --- a/core/component_factory.py +++ b/core/component_factory.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -19,6 +19,7 @@ from core.traffic_controller_rfc2544 import TrafficControllerRFC2544 from core.vswitch_controller_p2p import VswitchControllerP2P from core.vswitch_controller_pvp import VswitchControllerPVP from core.vswitch_controller_pvvp import VswitchControllerPVVP +from core.vswitch_controller_op2p import VswitchControllerOP2P from core.vnf_controller import VnfController from core.pktfwd_controller import PktFwdController from tools.load_gen.stress.stress import Stress @@ -61,12 +62,14 @@ def create_vswitch(deployment_scenario, vswitch_class, traffic): :return: IVSwitchController for the deployment_scenario """ deployment_scenario = deployment_scenario.lower() - if deployment_scenario.find("p2p") >= 0: + if deployment_scenario.find("p2p") == 0: return VswitchControllerP2P(vswitch_class, traffic) elif deployment_scenario.find("pvp") >= 0: return VswitchControllerPVP(vswitch_class, traffic) elif deployment_scenario.find("pvvp") >= 0: return VswitchControllerPVVP(vswitch_class, traffic) + elif deployment_scenario.find("op2p") >= 0: + return VswitchControllerOP2P(vswitch_class, traffic) def create_vnf(deployment_scenario, vnf_class): """Return a new VnfController for the deployment_scenario. diff --git a/core/vnf_controller.py b/core/vnf_controller.py index 3313e9e3..e973bc51 100644 --- a/core/vnf_controller.py +++ b/core/vnf_controller.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -43,10 +43,12 @@ class VnfController(object): self._deployment_scenario = deployment_scenario.upper() if self._deployment_scenario == 'P2P': self._vnfs = [] - if self._deployment_scenario == 'PVP': + elif self._deployment_scenario == 'PVP': self._vnfs = [vnf_class()] elif self._deployment_scenario == 'PVVP': self._vnfs = [vnf_class(), vnf_class()] + elif self._deployment_scenario == 'OP2P': + self._vnfs = [] self._logger.debug('__init__ ' + str(len(self._vnfs)) + ' VNF[s] with ' + ' '.join(map(str, self._vnfs))) diff --git a/core/vswitch_controller_op2p.py b/core/vswitch_controller_op2p.py new file mode 100644 index 00000000..69c88c35 --- /dev/null +++ b/core/vswitch_controller_op2p.py @@ -0,0 +1,140 @@ +# Copyright 2015-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. + +"""VSwitch controller for Physical to Tunnel Endpoint to Physical deployment +""" + +import logging + +from core.vswitch_controller import IVswitchController +from vswitches.utils import add_ports_to_flow +from conf import settings +from tools import tasks + +_FLOW_TEMPLATE = { + 'idle_timeout': '0' +} + +class VswitchControllerOP2P(IVswitchController): + """VSwitch controller for OP2P deployment scenario. + + Attributes: + _vswitch_class: The vSwitch class to be used. + _vswitch: The vSwitch object controlled by this controller + _deployment_scenario: A string describing the scenario to set-up in the + constructor. + """ + def __init__(self, vswitch_class, traffic): + """Initializes up the prerequisites for the OP2P deployment scenario. + + :vswitch_class: the vSwitch class to be used. + """ + self._logger = logging.getLogger(__name__) + self._vswitch_class = vswitch_class + self._vswitch = vswitch_class() + self._deployment_scenario = "OP2P" + self._traffic = traffic.copy() + self._logger.debug('Creation using ' + str(self._vswitch_class)) + + def setup(self): + """ Sets up the switch for overlay P2P + + Create 2 bridges br0 (integration bridge) and br-ext and a VXLAN port + for encapsulation. + """ + self._logger.debug('Setup using ' + str(self._vswitch_class)) + + try: + self._vswitch.start() + bridge = settings.getValue('TUNNEL_INTEGRATION_BRIDGE') + bridge_ext = settings.getValue('TUNNEL_EXTERNAL_BRIDGE') + bridge_ext_ip = settings.getValue('TUNNEL_EXTERNAL_BRIDGE_IP') + tg_port2_mac = settings.getValue('TRAFFICGEN_PORT2_MAC') + vtep_ip2 = settings.getValue('VTEP_IP2') + self._vswitch.add_switch(bridge) + + tasks.run_task(['sudo', 'ifconfig', bridge, + settings.getValue('VTEP_IP1')], + self._logger, 'Assign ' + + settings.getValue('VTEP_IP1') + ' to ' + bridge, + False) + + tunnel_type = self._traffic['tunnel_type'] + + self._vswitch.add_switch(bridge_ext) + (_, phy1_number) = self._vswitch.add_phy_port(bridge) + (_, phy2_number) = self._vswitch.add_tunnel_port(bridge, + vtep_ip2, + tunnel_type) + self._vswitch.add_phy_port(bridge_ext) + + tasks.run_task(['sudo', 'ip', 'addr', 'add', + bridge_ext_ip, + 'dev', bridge_ext], self._logger, 'Assign ' + + bridge_ext_ip + ' to ' + bridge_ext) + + tasks.run_task(['sudo', 'ip', 'link', 'set', 'dev', bridge_ext, + 'up'], self._logger, + 'Set ' + bridge_ext + 'status to up') + + self._vswitch.add_route(bridge, + settings.getValue('VTEP_IP2_SUBNET'), + bridge_ext) + + if settings.getValue('VSWITCH').endswith('Vanilla'): + tasks.run_task(['sudo', 'arp', '-s', vtep_ip2, tg_port2_mac], + self._logger, + 'Set ' + bridge_ext + 'status to up') + else: + self._vswitch.set_tunnel_arp(vtep_ip2, + tg_port2_mac, + bridge_ext) + + # Test is unidirectional for now + self._vswitch.del_flow(bridge) + flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number, + phy2_number) + self._vswitch.add_flow(bridge, flow1) + + except: + self._vswitch.stop() + raise + + def stop(self): + """Tears down the switch created in setup(). + """ + self._logger.debug('Stop using ' + str(self._vswitch_class)) + self._vswitch.stop() + + def __enter__(self): + self.setup() + + def __exit__(self, type_, value, traceback): + self.stop() + + def get_vswitch(self): + """See IVswitchController for description + """ + return self._vswitch + + def get_ports_info(self): + """See IVswitchController for description + """ + 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')) diff --git a/docs/configguide/index.rst b/docs/configguide/index.rst index 3aaf238f..7ea39cd1 100644 --- a/docs/configguide/index.rst +++ b/docs/configguide/index.rst @@ -8,3 +8,4 @@ VSPERF Installation Guide installation.rst trafficgen.rst + integration.rst diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 1e02eb21..ff4e7b52 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -7,3 +7,4 @@ VSPERF User Guide :maxdepth: 3 quickstart.rst + integration.rst diff --git a/docs/userguide/integration.rst b/docs/userguide/integration.rst new file mode 100755 index 00000000..65b86468 --- /dev/null +++ b/docs/userguide/integration.rst @@ -0,0 +1,97 @@ +Integration tests +================= + +VSPERF includes a set of integration tests defined in conf/integration. +These tests can be run by specifying --run-integration as a parameter to vsperf. +Current tests in conf/integration are Overlay tests. + + +Executing Tunnel encapsulation tests +------------------------------------ + +VSPERF supports VXLAN, GRE and GENEVE tunneling protocols. +Testing of these protocols is limited to unidirectional traffic and +P2P (Physical to Physical scenarios). + +The VXLAN OVS DPDK encapsulation tests requires IPs, MAC addresses, +bridge names and WHITELIST_NICS for DPDK. + +Default values are already provided. To customize for your environment, override +the following variables in you user_settings.py file: + +# Variables defined in conf/integration/02_vswitch.conf +# Tunnel endpoint for Overlay P2P deployment scenario +# used for br0 +VTEP_IP1 = '192.168.0.1/24' + +# Used as remote_ip in adding OVS tunnel port and +# to set ARP entry in OVS (e.g. tnl/arp/set br-ext 192.168.240.10 02:00:00:00:00:02 +VTEP_IP2 = '192.168.240.10' + +# Network to use when adding a route for inner frame data +VTEP_IP2_SUBNET = '192.168.240.0/24' + +# Bridge names +TUNNEL_INTEGRATION_BRIDGE = 'br0' +TUNNEL_EXTERNAL_BRIDGE = 'br-ext' + +# IP of br-ext +TUNNEL_EXTERNAL_BRIDGE_IP = '192.168.240.1/24' + +# vxlan|gre|geneve +TUNNEL_TYPE = 'vxlan' + +# Variables defined conf/integration/03_traffic.conf +# For OP2P deployment scenario +TRAFFICGEN_PORT1_MAC = '02:00:00:00:00:01' +TRAFFICGEN_PORT2_MAC = '02:00:00:00:00:02' +TRAFFICGEN_PORT1_IP = '1.1.1.1' +TRAFFICGEN_PORT2_IP = '192.168.240.10' + + +To run VXLAN encapsulation tests: + + .. code-block:: console + + ./vsperf --conf-file user_settings.py --run-integration --test-param 'tunnel_type=vxlan' overlay_p2p_tput + +To run GRE encapsulation tests: + + .. code-block:: console + + ./vsperf --conf-file user_settings.py --run-integration --test-param 'tunnel_type=gre' overlay_p2p_tput + +To run GENEVE encapsulation tests: + + .. code-block:: console + + ./vsperf --conf-file user_settings.py --run-integration --test-param 'tunnel_type=geneve' overlay_p2p_tput + +To run OVS NATIVE tunnel tests (VXLAN/GRE/GENEVE): + +1. Install the OVS kernel modules + + .. code:: console + + cd src/ovs/ovs + sudo -E make modules_install + +2. Set the following variables: + + .. code-block:: console + + VSWITCH = 'OvsVanilla' + VSWITCH_VANILLA_PHY_PORT_NAMES = ['nic1name', 'nic2name'] + # Specify vport_* kernel module to test. + VSWITCH_VANILLA_KERNEL_MODULES = ['vport_vxlan', + 'vport_gre', + 'vport_geneve', + os.path.join(OVS_DIR_VANILLA, 'datapath/linux/openvswitch.ko')] + +3. Run tests: + + .. code-block:: console + + ./vsperf --conf-file user_settings.py --run-integration --test-param 'tunnel_type=vxlan' overlay_p2p_tput + + diff --git a/src/ovs/ofctl.py b/src/ovs/ofctl.py index 9d16ef76..43151d3a 100644 --- a/src/ovs/ofctl.py +++ b/src/ovs/ofctl.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -31,6 +31,8 @@ _OVS_VSCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', 'ovs-vsctl') _OVS_OFCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', 'ovs-ofctl') +_OVS_APPCTL_BIN = os.path.join(settings.getValue('OVS_DIR'), 'utilities', + 'ovs-appctl') _OVS_BRIDGE_NAME = settings.getValue('VSWITCH_BRIDGE_NAME') @@ -63,6 +65,22 @@ class OFBase(object): return tasks.run_task( cmd, self.logger, 'Running ovs-vsctl...', check_error) + + def run_appctl(self, args, check_error=False): + """Run ``ovs-appctl`` with supplied arguments. + + :param args: Arguments to pass to ``ovs-appctl`` + :param check_error: Throw exception on error + + :return: None + """ + cmd = ['sudo', _OVS_APPCTL_BIN, + '--timeout', + str(self.timeout)] + args + return tasks.run_task( + cmd, self.logger, 'Running ovs-appctl...', check_error) + + # datapath management def add_br(self, br_name=_OVS_BRIDGE_NAME, params=None): @@ -90,6 +108,32 @@ class OFBase(object): self.logger.debug('delete bridge') self.run_vsctl(['del-br', br_name]) + # Route and ARP functions + + def add_route(self, network, destination): + """Add route to tunneling routing table. + + :param network: Network + :param destination: Gateway + + :return: None + """ + self.logger.debug('add ovs/route') + self.run_appctl(['ovs/route/add', network, destination]) + + + def set_tunnel_arp(self, ip_addr, mac_addr, br_name=_OVS_BRIDGE_NAME): + """Add OVS arp entry for tunneling + + :param ip: IP of bridge + :param mac_addr: MAC address of the bridge + :param br_name: Name of the bridge + + :return: None + """ + self.logger.debug('tnl/arp/set') + self.run_appctl(['tnl/arp/set', br_name, ip_addr, mac_addr]) + class OFBridge(OFBase): """Control a bridge instance using ``ovs-vsctl`` and ``ovs-ofctl``. @@ -330,10 +374,10 @@ def flow_key(flow): field_params.append('%(field)s=%(value)s' % {'field': key, 'value': default}) - field_params = ','.join(field_params) + field_params_str = ','.join(field_params) _flow_key_param = { - 'fields': field_params, + 'fields': field_params_str, } # no actions == delete key diff --git a/testcases/testcase.py b/testcases/testcase.py index d470d951..945b8537 100644 --- a/testcases/testcase.py +++ b/testcases/testcase.py @@ -28,8 +28,8 @@ from core.loader import Loader from tools import tasks from tools import hugepages from tools.report import report -from conf import settings as S from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS +from conf import settings as S from conf import get_test_param class TestCase(object): @@ -64,6 +64,11 @@ class TestCase(object): self.deployment = cfg['Deployment'] self._frame_mod = cfg.get('Frame Modification', None) + tunnel_type = None + if 'Tunnel Type' in cfg: + tunnel_type = cfg['Tunnel Type'] + tunnel_type = get_test_param('tunnel_type', tunnel_type) + # identify guest loopback method, so it can be added into reports self.guest_loopback = [] if self.deployment in ['pvp', 'pvvp']: @@ -102,6 +107,7 @@ class TestCase(object): self._traffic.update({'traffic_type': traffic_type, 'flow_type': cfg.get('Flow Type', 'port'), 'bidir': bidirectional, + 'tunnel_type': tunnel_type, 'multistream': int(multistream), 'stream_type': stream_type, 'pre_installed_flows' : pre_installed_flows, @@ -130,6 +136,17 @@ class TestCase(object): # copy sources of l2 forwarding tools into VM shared dir if needed self._copy_fwd_tools_for_guest() + if self.deployment == "op2p": + self._traffic['l2'].update({'srcmac': + S.getValue('TRAFFICGEN_PORT1_MAC'), + 'dstmac': + S.getValue('TRAFFICGEN_PORT2_MAC')}) + + self._traffic['l3'].update({'srcip': + S.getValue('TRAFFICGEN_PORT1_IP'), + 'dstip': + S.getValue('TRAFFICGEN_PORT2_IP')}) + self._logger.debug("Controllers:") loader = Loader() traffic_ctl = component_factory.create_traffic( diff --git a/vsperf b/vsperf index 4b1d86d0..71ca2eb0 100755 --- a/vsperf +++ b/vsperf @@ -154,6 +154,7 @@ def parse_arguments(): name contains RFC2544 less those containing "p2p"') group.add_argument('--verbosity', choices=list_logging_levels(), help='debug level') + group.add_argument('--run-integration', action='store_true', help='run integration tests') group.add_argument('--trafficgen', help='traffic generator to use') group.add_argument('--vswitch', help='vswitch implementation to use') group.add_argument('--fwdapp', help='packet forwarding application to use') @@ -325,6 +326,10 @@ def main(): settings.load_from_dir('conf') + # Load non performance/integration tests + if args['run_integration']: + settings.load_from_dir('conf/integration') + # load command line parameters first in case there are settings files # to be used settings.load_from_dict(args) @@ -455,6 +460,9 @@ def main(): else: # configure tests testcases = settings.getValue('PERFORMANCE_TESTS') + if args['run_integration']: + testcases = settings.getValue('INTEGRATION_TESTS') + all_tests = [] for cfg in testcases: try: diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py index 2c7b81ff..074e15f8 100644 --- a/vswitches/ovs_dpdk_vhost.py +++ b/vswitches/ovs_dpdk_vhost.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -21,7 +21,7 @@ from vswitches.vswitch import IVSwitch from src.ovs import VSwitchd, OFBridge from src.dpdk import dpdk -_VSWITCHD_CONST_ARGS = ['--', '--log-file'] +_VSWITCHD_CONST_ARGS = ['--', '--pidfile', '--log-file'] class OvsDpdkVhost(IVSwitch): """VSwitch implementation using DPDK and vhost ports @@ -77,7 +77,7 @@ class OvsDpdkVhost(IVSwitch): 'datapath_type=netdev']) else: bridge.create(['--', 'set', 'bridge', switch_name, - 'datapath_type=netdev'] + params) + 'datapath_type=netdev'] + params) bridge.set_db_attribute('Open_vSwitch', '.', 'other_config:max-idle', @@ -106,7 +106,7 @@ class OvsDpdkVhost(IVSwitch): The new port is named dpdk where n is an integer starting from 0. """ bridge = self._bridges[switch_name] - dpdk_count = self._get_port_count(bridge, 'type=dpdk') + dpdk_count = self._get_port_count('type=dpdk') port_name = 'dpdk' + str(dpdk_count) params = ['--', 'set', 'Interface', port_name, 'type=dpdk'] of_port = bridge.add_port(port_name, params) @@ -123,11 +123,11 @@ class OvsDpdkVhost(IVSwitch): bridge = self._bridges[switch_name] # Changed dpdkvhost to dpdkvhostuser to be able to run in Qemu 2.2 if settings.getValue('VNF').endswith('Cuse'): - vhost_count = self._get_port_count(bridge, 'type=dpdkvhostcuse') + vhost_count = self._get_port_count('type=dpdkvhostcuse') port_name = 'dpdkvhostcuse' + str(vhost_count) params = ['--', 'set', 'Interface', port_name, 'type=dpdkvhostcuse'] else: - vhost_count = self._get_port_count(bridge, 'type=dpdkvhostuser') + vhost_count = self._get_port_count('type=dpdkvhostuser') port_name = 'dpdkvhostuser' + str(vhost_count) params = ['--', 'set', 'Interface', port_name, 'type=dpdkvhostuser'] @@ -135,6 +135,17 @@ class OvsDpdkVhost(IVSwitch): return (port_name, of_port) + def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan'): + """Creates tunneling port + """ + bridge = self._bridges[switch_name] + pcount = str(self._get_port_count('type=' + tunnel_type)) + port_name = tunnel_type + pcount + params = ['--', 'set', 'Interface', port_name, 'type=' + tunnel_type, + 'options:remote_ip=' + remote_ip] + of_port = bridge.add_port(port_name, params) + return (port_name, of_port) + def get_ports(self, switch_name): """See IVswitch for general description """ @@ -167,14 +178,31 @@ class OvsDpdkVhost(IVSwitch): bridge = self._bridges[switch_name] bridge.dump_flows() - @staticmethod - def _get_port_count(bridge, param): + def add_route(self, switch_name, network, destination): + """See IVswitch for general description + """ + bridge = self._bridges[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.set_tunnel_arp(ip_addr, mac_addr, switch_name) + + def _get_port_count(self, param): """Returns the number of ports having a certain parameter :param bridge: The src.ovs.ofctl.OFBridge on which to operate :param param: The parameter to search for :returns: Count of matches """ - port_params = [c for (_, (_, c)) in list(bridge.get_ports().items())] - param_hits = [i for i in port_params if param in i] - return len(param_hits) + cnt = 0 + for k in self._bridges: + pparams = [c for (_, (_, c)) in list(self._bridges[k].get_ports().items())] + phits = [i for i in pparams if param in i] + cnt += len(phits) + + if cnt is None: + cnt = 0 + return cnt diff --git a/vswitches/ovs_vanilla.py b/vswitches/ovs_vanilla.py index 3078de02..77d3deaf 100644 --- a/vswitches/ovs_vanilla.py +++ b/vswitches/ovs_vanilla.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -150,6 +150,22 @@ class OvsVanilla(IVSwitch): of_port = bridge.add_port(tap_name, []) return (tap_name, of_port) + def add_tunnel_port(self, switch_name, remote_ip, tunnel_type='vxlan', + params=None): + """Creates tunneling port + """ + bridge = self._bridges[switch_name] + pcount = str(self._get_port_count('type=' + tunnel_type)) + port_name = tunnel_type + pcount + local_params = ['--', 'set', 'Interface', port_name, + 'type=' + tunnel_type, + 'options:remote_ip=' + remote_ip] + + if params is not None: + local_params = local_params + params + + of_port = bridge.add_port(port_name, local_params) + return (port_name, of_port) def get_ports(self, switch_name): """See IVswitch for general description @@ -182,3 +198,34 @@ class OvsVanilla(IVSwitch): """ bridge = self._bridges[switch_name] bridge.dump_flows() + + def add_route(self, switch_name, network, destination): + """See IVswitch for general description + """ + bridge = self._bridges[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.set_tunnel_arp(ip_addr, mac_addr, switch_name) + + def _get_port_count(self, param): + """Returns the number of ports having a certain parameter + + :param bridge: The src.ovs.ofctl.OFBridge on which to operate + :param param: The parameter to search for + :returns: Count of matches + """ + cnt = 0 + for k in self._bridges: + pparams = [c for (_, (_, c)) in list(self._bridges[k].get_ports().items())] + phits = [i for i in pparams if param in i] + cnt += len(phits) + + if cnt is None: + cnt = 0 + return cnt + + diff --git a/vswitches/vswitch.py b/vswitches/vswitch.py index a28c0f6b..73e0a0c3 100644 --- a/vswitches/vswitch.py +++ b/vswitches/vswitch.py @@ -1,4 +1,4 @@ -# Copyright 2015 Intel Corporation. +# Copyright 2015-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. @@ -71,6 +71,14 @@ class IVSwitch(object): """ raise NotImplementedError() + def add_tunnel_port(self, switch_name, remote_ip, tunnel_type, params=None): + """Create a new port to the logical switch for tunneling + + :param switch_name: The switch where the port is attached to + :returns: (port name, OpenFlow port number) + """ + raise NotImplementedError() + def get_ports(self, switch_name): """Return a list of tuples describing the ports of the logical switch @@ -128,3 +136,21 @@ class IVSwitch(object): :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 + + :param switch_name: The switch on which to operate + :param network: Target destination network + :param destination: Gateway IP + """ + raise NotImplementedError() + + def set_tunnel_arp(self, ip_addr, mac_addr, switch_name): + """Add arp entry for tunneling + + :param ip_addr: IP of bridge + :param mac_addr: MAC address of the bridge + :param switch_name: Name of the bridge + """ + raise NotImplementedError() -- 2.16.6