diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/component_factory.py | 34 | ||||
-rw-r--r-- | core/pktfwd_controller.py | 8 | ||||
-rw-r--r-- | core/vswitch_controller.py | 44 | ||||
-rw-r--r-- | core/vswitch_controller_clean.py | 30 | ||||
-rw-r--r-- | core/vswitch_controller_op2p.py | 56 | ||||
-rw-r--r-- | core/vswitch_controller_p2p.py | 132 | ||||
-rw-r--r-- | core/vswitch_controller_ptunp.py | 60 | ||||
-rw-r--r-- | core/vswitch_controller_pxp.py | 136 |
8 files changed, 144 insertions, 356 deletions
diff --git a/core/component_factory.py b/core/component_factory.py index b6bd2677..2c51a060 100644 --- a/core/component_factory.py +++ b/core/component_factory.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. @@ -66,23 +66,23 @@ def create_vswitch(deployment_scenario, vswitch_class, traffic, :return: IVSwitchController for the deployment_scenario """ # pylint: disable=too-many-return-statements - deployment_scenario = deployment_scenario.lower() - if deployment_scenario.startswith("p2p"): - return VswitchControllerP2P(vswitch_class, traffic) - elif deployment_scenario.startswith("pvp"): - return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic) - elif deployment_scenario.startswith("pvvp"): - return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic) - elif deployment_scenario.startswith("pvpv"): - return VswitchControllerPXP(deployment_scenario, vswitch_class, traffic) - elif deployment_scenario.startswith("op2p"): - return VswitchControllerOP2P(vswitch_class, traffic, tunnel_operation) - elif deployment_scenario.startswith("ptunp"): - return VswitchControllerPtunP(vswitch_class, traffic) - elif deployment_scenario.startswith("clean"): - return VswitchControllerClean(vswitch_class, traffic) + deployment = deployment_scenario.lower() + if deployment.startswith("p2p"): + return VswitchControllerP2P(deployment, vswitch_class, traffic) + elif deployment.startswith("pvp"): + return VswitchControllerPXP(deployment, vswitch_class, traffic) + elif deployment.startswith("pvvp"): + return VswitchControllerPXP(deployment, vswitch_class, traffic) + elif deployment.startswith("pvpv"): + return VswitchControllerPXP(deployment, vswitch_class, traffic) + elif deployment.startswith("op2p"): + return VswitchControllerOP2P(deployment, vswitch_class, traffic, tunnel_operation) + elif deployment.startswith("ptunp"): + return VswitchControllerPtunP(deployment, vswitch_class, traffic) + elif deployment.startswith("clean"): + return VswitchControllerClean(deployment, vswitch_class, traffic) else: - raise RuntimeError("Unknown deployment scenario '{}'.".format(deployment_scenario)) + raise RuntimeError("Unknown deployment scenario '{}'.".format(deployment)) def create_vnf(deployment_scenario, vnf_class, extra_vnfs): diff --git a/core/pktfwd_controller.py b/core/pktfwd_controller.py index bdc91822..363302c3 100644 --- a/core/pktfwd_controller.py +++ b/core/pktfwd_controller.py @@ -1,4 +1,4 @@ -# Copyright 2016 Intel Corporation. +# Copyright 2016-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. @@ -89,9 +89,9 @@ class PktFwdController(object): """ return self._pktfwd - def dump_vswitch_flows(self): - """ Dumps flows from vswitch + def dump_vswitch_connections(self): + """ Dumps connections from vswitch """ raise NotImplementedError( "The PktFwdController does not implement the " - "\"dump_vswitch_flows\" function.") + "\"dump_vswitch_connections\" function.") diff --git a/core/vswitch_controller.py b/core/vswitch_controller.py index 855de8b2..889f14bc 100644 --- a/core/vswitch_controller.py +++ b/core/vswitch_controller.py @@ -1,4 +1,4 @@ -# Copyright 2015 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. @@ -13,33 +13,57 @@ # limitations under the License. """Interface for deployment specific vSwitch controllers """ +import logging class IVswitchController(object): - """Abstract class which defines a vSwitch controller object + """Interface class for a vSwitch controller object This interface is used to setup and control a vSwitch provider for a particular deployment scenario. """ - def __enter__(self): + def __init__(self, deployment, vswitch_class, traffic): + """Initializes up the generic prerequisites for deployment scenario. + + :deployment: the deployment scenario to configure + :vswitch_class: the vSwitch class to be used. + :traffic: dictionary with detailed traffic definition + """ + self._logger = logging.getLogger(__name__) + self._vswitch_class = vswitch_class + self._vswitch = vswitch_class() + self._deployment_scenario = deployment + self._logger.debug('Creation using %s', str(self._vswitch_class)) + self._traffic = traffic.copy() + self._bridge = None + + def setup(self): """Sets up the switch for the particular deployment scenario """ raise NotImplementedError( "The VswitchController does not implement the \"setup\" function.") - def __exit__(self, type_, value, traceback): + def stop(self): """Tears down the switch created in setup() """ raise NotImplementedError( "The VswitchController does not implement the \"stop\" function.") + def __enter__(self): + """Sets up the switch for the particular deployment scenario + """ + self.setup() + + def __exit__(self, type_, value, traceback): + """Tears down the switch created in setup() + """ + self.stop() + def get_vswitch(self): """Get the controlled vSwitch :return: The controlled IVswitch """ - raise NotImplementedError( - "The VswitchController does not implement the \"get_vswitch\" " - "function.") + return self._vswitch def get_ports_info(self): """Returns a dictionary describing all ports on the vSwitch. @@ -50,9 +74,9 @@ class IVswitchController(object): "The VswitchController does not implement the \"get_ports_info\" " "function.") - def dump_vswitch_flows(self): - """ Dumps flows from vswitch + def dump_vswitch_connections(self): + """ Dumps connections from vswitch """ raise NotImplementedError( "The VswitchController does not implement the " - "\"dump_vswitch_flows\" function.") + "\"dump_vswitch_connections\" function.") diff --git a/core/vswitch_controller_clean.py b/core/vswitch_controller_clean.py index 432406a7..7a771226 100644 --- a/core/vswitch_controller_clean.py +++ b/core/vswitch_controller_clean.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,9 +14,6 @@ """VSwitch controller for basic initialization of vswitch """ - -import logging - from core.vswitch_controller import IVswitchController class VswitchControllerClean(IVswitchController): @@ -28,18 +25,6 @@ class VswitchControllerClean(IVswitchController): _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 Clean 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 = "Clean" - self._logger.debug('Creation using %s', str(self._vswitch_class)) - self._traffic = traffic.copy() - def setup(self): """Sets up the switch for Clean. """ @@ -57,23 +42,12 @@ class VswitchControllerClean(IVswitchController): self._logger.debug('Stop using %s', 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 """ pass - def dump_vswitch_flows(self): + def dump_vswitch_connections(self): """See IVswitchController for description """ pass diff --git a/core/vswitch_controller_op2p.py b/core/vswitch_controller_op2p.py index 3f879f9f..072a690a 100644 --- a/core/vswitch_controller_op2p.py +++ b/core/vswitch_controller_op2p.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. @@ -14,39 +14,19 @@ """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 as S 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, tunnel_operation=None): - """Initializes up the prerequisites for the OP2P deployment scenario. - - :vswitch_class: the vSwitch class to be used. + def __init__(self, deployment, vswitch_class, traffic, tunnel_operation=None): + """See IVswitchController for general description """ - self._logger = logging.getLogger(__name__) - self._vswitch_class = vswitch_class - self._vswitch = vswitch_class() - self._deployment_scenario = "OP2P" - self._traffic = traffic.copy() + super().__init__(deployment, vswitch_class, traffic) self._tunnel_operation = tunnel_operation - self._logger.debug('Creation using %s', str(self._vswitch_class)) def setup(self): """ Sets up the switch for overlay P2P (tunnel encap or decap) @@ -118,10 +98,13 @@ class VswitchControllerOP2P(IVswitchController): # Test is unidirectional for now self._vswitch.del_flow(bridge) - flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number, + flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy1_number, phy2_number) self._vswitch.add_flow(bridge, flow1) - + # enable MAC learning mode at external bridge + flow_ext = S.getValue('OVS_FLOW_TEMPLATE').copy() + flow_ext.update({'actions': ['NORMAL']}) + self._vswitch.add_flow(bridge_ext, flow_ext) except: self._vswitch.stop() raise @@ -178,7 +161,7 @@ class VswitchControllerOP2P(IVswitchController): bridge) # Test is unidirectional for now self._vswitch.del_flow(bridge_ext) - flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number, + flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy3_number, phy2_number) self._vswitch.add_flow(bridge_ext, flow1) @@ -251,7 +234,7 @@ class VswitchControllerOP2P(IVswitchController): # Test is unidirectional for now self._vswitch.del_flow(bridge_ext) - flow1 = add_ports_to_flow(_FLOW_TEMPLATE, phy2_number, 'LOCAL') + flow1 = add_ports_to_flow(S.getValue('OVS_FLOW_TEMPLATE'), phy2_number, 'LOCAL') self._vswitch.add_flow(bridge_ext, flow1) except: @@ -264,17 +247,6 @@ class VswitchControllerOP2P(IVswitchController): self._logger.debug('Stop using %s', 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 """ @@ -286,8 +258,8 @@ class VswitchControllerOP2P(IVswitchController): self._vswitch.get_ports( S.getValue('TUNNEL_EXTERNAL_BRIDGE')) - def dump_vswitch_flows(self): + def dump_vswitch_connections(self): """See IVswitchController for description """ - self._vswitch.dump_flows(S.getValue('TUNNEL_INTEGRATION_BRIDGE')) - self._vswitch.dump_flows(S.getValue('TUNNEL_EXTERNAL_BRIDGE')) + self._vswitch.dump_connections(S.getValue('TUNNEL_INTEGRATION_BRIDGE')) + self._vswitch.dump_connections(S.getValue('TUNNEL_EXTERNAL_BRIDGE')) diff --git a/core/vswitch_controller_p2p.py b/core/vswitch_controller_p2p.py index eb1f57f0..d8f22e4c 100644 --- a/core/vswitch_controller_p2p.py +++ b/core/vswitch_controller_p2p.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. @@ -14,20 +14,9 @@ """VSwitch controller for Physical to Physical deployment """ - -import logging -import netaddr - from core.vswitch_controller import IVswitchController from conf import settings -_FLOW_TEMPLATE = { - 'idle_timeout': '0' -} - -_PROTO_TCP = 6 -_PROTO_UDP = 17 - class VswitchControllerP2P(IVswitchController): """VSwitch controller for P2P deployment scenario. @@ -37,17 +26,11 @@ class VswitchControllerP2P(IVswitchController): _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 P2P deployment scenario. - - :vswitch_class: the vSwitch class to be used. + def __init__(self, deployment, vswitch_class, traffic): + """See IVswitchController for general description """ - self._logger = logging.getLogger(__name__) - self._vswitch_class = vswitch_class - self._vswitch = vswitch_class() - self._deployment_scenario = "P2P" - self._logger.debug('Creation using %s', str(self._vswitch_class)) - self._traffic = traffic.copy() + super().__init__(deployment, vswitch_class, traffic) + self._bridge = settings.getValue('VSWITCH_BRIDGE_NAME') def setup(self): """Sets up the switch for p2p. @@ -57,51 +40,14 @@ class VswitchControllerP2P(IVswitchController): try: self._vswitch.start() - bridge = settings.getValue('VSWITCH_BRIDGE_NAME') - self._vswitch.add_switch(bridge) - - (_, _) = self._vswitch.add_phy_port(bridge) - (_, _) = self._vswitch.add_phy_port(bridge) - - self._vswitch.del_flow(bridge) - - # table#0 - flows designed to force 5 & 13 tuple matches go here - flow = {'table':'0', 'priority':'1', 'actions': ['goto_table:1']} - self._vswitch.add_flow(bridge, 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 + self._vswitch.add_switch(self._bridge) - # configure flows according to the TC definition - flow_template = _FLOW_TEMPLATE.copy() - if self._traffic['flow_type'] == 'IP': - flow_template.update({'dl_type':'0x0800', 'nw_src':self._traffic['l3']['srcip'], - 'nw_dst':self._traffic['l3']['dstip']}) + (port1, _) = self._vswitch.add_phy_port(self._bridge) + (port2, _) = self._vswitch.add_phy_port(self._bridge) - flow = flow_template.copy() - flow.update({'table':'1', 'priority':'1', 'in_port':'1', - 'actions': ['write_actions(output:2)', 'write_metadata:0x2', - 'goto_table:2']}) - 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:0x1', - 'goto_table:2']}) - self.process_flow_template(bridge, flow) + self._vswitch.add_connection(self._bridge, port1, port2, self._traffic) + self._vswitch.add_connection(self._bridge, port2, port1, self._traffic) - # 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']} - self._vswitch.add_flow(bridge, flow) - - # Egress table - # (TODO) 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']} - self._vswitch.add_flow(bridge, flow) except: self._vswitch.stop() raise @@ -112,65 +58,13 @@ class VswitchControllerP2P(IVswitchController): self._logger.debug('Stop using %s', 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 %s', str(self._vswitch_class)) - return self._vswitch.get_ports(settings.getValue('VSWITCH_BRIDGE_NAME')) + return self._vswitch.get_ports(self._bridge) - def dump_vswitch_flows(self): + def dump_vswitch_connections(self): """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(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(self._traffic['multistream']): - tmp_ip = netaddr.IPAddress(dst_ip_value + i) - flow_template.update({'dl_type':'0x0800', '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(self._traffic['multistream']): - flow_template.update({'dl_type':'0x0800', '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) + self._vswitch.dump_connections(self._bridge) diff --git a/core/vswitch_controller_ptunp.py b/core/vswitch_controller_ptunp.py index 853c7d5c..b10da2a9 100644 --- a/core/vswitch_controller_ptunp.py +++ b/core/vswitch_controller_ptunp.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. @@ -15,8 +15,6 @@ """VSwitch controller for Physical to VxLAN Tunnel Endpoint to Physical deployment with mod operation. """ - -import logging from netaddr import EUI, IPNetwork, mac_unix from core.vswitch_controller import IVswitchController @@ -24,10 +22,6 @@ from vswitches.utils import add_ports_to_flow from conf import settings from tools import tasks -_FLOW_TEMPLATE = { - 'idle_timeout': '0' -} - class VswitchControllerPtunP(IVswitchController): """VSwitch controller for VxLAN ptunp deployment scenario. The deployment scenario is to test VxLAN tunneling feature without using an @@ -40,16 +34,10 @@ class VswitchControllerPtunP(IVswitchController): _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 ptunp deployment scenario. - - :vswitch_class: the vSwitch class to be used. + def __init__(self, deployment, vswitch_class, traffic): + """See IVswitchController for general description """ - self._logger = logging.getLogger(__name__) - self._vswitch_class = vswitch_class - self._vswitch = vswitch_class() - self._deployment_scenario = "ptunp" - self._traffic = traffic.copy() + super().__init__(deployment, vswitch_class, traffic) self.bridge_phy1 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE1') self.bridge_phy2 = settings.getValue('TUNNEL_EXTERNAL_BRIDGE2') self.bridge_mod1 = settings.getValue('TUNNEL_MODIFY_BRIDGE1') @@ -59,7 +47,6 @@ class VswitchControllerPtunP(IVswitchController): self.br_mod_ip1 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP1') self.br_mod_ip2 = settings.getValue('TUNNEL_MODIFY_BRIDGE_IP2') self.tunnel_type = settings.getValue('TUNNEL_TYPE') - self._logger.debug('Creation using %s', str(self._vswitch_class)) def setup(self): """ Sets up the switch for VxLAN overlay PTUNP (tunnel encap or decap) @@ -156,23 +143,23 @@ class VswitchControllerPtunP(IVswitchController): self._vswitch.del_flow(self.bridge_phy2) self._vswitch.del_flow(self.bridge_mod1) self._vswitch.del_flow(self.bridge_mod2) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy1_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy1_number, phy3_number) self._vswitch.add_flow(self.bridge_phy1, flow) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy3_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy3_number, phy1_number) self._vswitch.add_flow(self.bridge_phy1, flow) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy2_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy2_number, phy4_number) self._vswitch.add_flow(self.bridge_phy2, flow) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy4_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy4_number, phy2_number) self._vswitch.add_flow(self.bridge_phy2, flow) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy5_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy5_number, 'LOCAL') self._vswitch.add_flow(self.bridge_mod1, flow) - mod_flow_template = _FLOW_TEMPLATE.copy() + mod_flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy() mod_flow_template.update({'ip':'', 'actions': ['mod_dl_src:' + str(vxlan_rem_mac2), @@ -183,10 +170,10 @@ class VswitchControllerPtunP(IVswitchController): }) flow = add_ports_to_flow(mod_flow_template, 'LOCAL', phy5_number) self._vswitch.add_flow(self.bridge_mod1, flow) - flow = add_ports_to_flow(_FLOW_TEMPLATE, phy6_number, + flow = add_ports_to_flow(settings.getValue('OVS_FLOW_TEMPLATE'), phy6_number, 'LOCAL') self._vswitch.add_flow(self.bridge_mod2, flow) - mod_flow_template = _FLOW_TEMPLATE.copy() + mod_flow_template = settings.getValue('OVS_FLOW_TEMPLATE').copy() mod_flow_template.update({'ip':'', 'actions': ['mod_dl_src:' + str(vxlan_rem_mac1), @@ -207,17 +194,6 @@ class VswitchControllerPtunP(IVswitchController): self._logger.debug('Stop using %s', 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 """ @@ -228,11 +204,11 @@ class VswitchControllerPtunP(IVswitchController): self._vswitch.get_ports(self.bridge_mod2) return ports - def dump_vswitch_flows(self): + def dump_vswitch_connections(self): """See IVswitchController for description """ - self._logger.debug('dump_flows using %s', str(self._vswitch_class)) - self._vswitch.dump_flows(self.bridge_phy1) - self._vswitch.dump_flows(self.bridge_mod1) - self._vswitch.dump_flows(self.bridge_phy2) - self._vswitch.dump_flows(self.bridge_mod2) + self._logger.debug('dump_connections using %s', str(self._vswitch_class)) + self._vswitch.dump_connections(self.bridge_phy1) + self._vswitch.dump_connections(self.bridge_mod1) + self._vswitch.dump_connections(self.bridge_phy2) + self._vswitch.dump_connections(self.bridge_mod2) diff --git a/core/vswitch_controller_pxp.py b/core/vswitch_controller_pxp.py index e3c208a3..d36ecdba 100644 --- a/core/vswitch_controller_pxp.py +++ b/core/vswitch_controller_pxp.py @@ -1,4 +1,4 @@ -# Copyright 2016 Intel Corporation. +# Copyright 2016-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,34 +14,18 @@ """VSwitch controller for multi VM scenarios with serial or parallel connection """ - -import logging import netaddr from core.vswitch_controller import IVswitchController -from vswitches.utils import add_ports_to_flow from conf import settings -_FLOW_TEMPLATE = { - 'idle_timeout': '0' -} - -_PROTO_TCP = 6 -_PROTO_UDP = 17 - class VswitchControllerPXP(IVswitchController): """VSwitch controller for PXP deployment scenario. """ def __init__(self, deployment, vswitch_class, traffic): - """Initializes up the prerequisites for the PXP deployment scenario. - - :vswitch_class: the vSwitch class to be used. - :deployment: the deployment scenario to configure - :traffic: dictionary with detailed traffic definition + """See IVswitchController for general description """ - self._logger = logging.getLogger(__name__) - self._vswitch_class = vswitch_class - self._vswitch = vswitch_class() + super().__init__(deployment, vswitch_class, traffic) self._pxp_topology = 'parallel' if deployment.startswith('pvpv') else 'serial' if deployment == 'pvp': self._pxp_vm_count = 1 @@ -55,9 +39,7 @@ class VswitchControllerPXP(IVswitchController): self._deployment_scenario = deployment - self._traffic = traffic.copy() self._bidir = True if self._traffic['bidir'] == 'True' else False - self._logger.debug('Creation using %s', str(self._vswitch_class)) self._bridge = settings.getValue('VSWITCH_BRIDGE_NAME') def setup(self): @@ -71,8 +53,8 @@ class VswitchControllerPXP(IVswitchController): self._vswitch.add_switch(self._bridge) # create physical ports - (_, phy1_number) = self._vswitch.add_phy_port(self._bridge) - (_, phy2_number) = self._vswitch.add_phy_port(self._bridge) + (phy1, _) = self._vswitch.add_phy_port(self._bridge) + (phy2, _) = self._vswitch.add_phy_port(self._bridge) # create VM ports # initialize vport array to requested number of VMs @@ -86,54 +68,42 @@ class VswitchControllerPXP(IVswitchController): self._logger.debug('Create %s vports for %s. VM with index %s', nics_nr, vmindex + 1, vmindex) for _ in range(nics_nr): - (_, vport) = self._vswitch.add_vport(self._bridge) + (vport, _) = self._vswitch.add_vport(self._bridge) vm_ports[vmindex].append(vport) - self._vswitch.del_flow(self._bridge) - - # configure flows according to the TC definition + # configure connections according to the TC definition if self._pxp_topology == 'serial': - flow = _FLOW_TEMPLATE.copy() - if self._traffic['flow_type'] == 'IP': - flow.update({'dl_type':'0x0800', - 'nw_src':self._traffic['l3']['srcip'], - 'nw_dst':self._traffic['l3']['dstip']}) + # NOTE: all traffic from VMs is sent to other ports directly + # without applying traffic options to avoid issues with MAC swapping + # and upper layer mods performed inside guests - # insert flows for phy ports first + # insert connections for phy ports first # from 1st PHY to 1st vport of 1st VM - self._add_flow(flow, - phy1_number, - vm_ports[0][0], - self._bidir) + self._vswitch.add_connection(self._bridge, phy1, vm_ports[0][0], self._traffic) + self._vswitch.add_connection(self._bridge, vm_ports[0][0], phy1) # from last vport of last VM to 2nd phy - self._add_flow(flow, - vm_ports[self._pxp_vm_count-1][-1], - phy2_number, - self._bidir) + self._vswitch.add_connection(self._bridge, vm_ports[self._pxp_vm_count-1][-1], phy2) + self._vswitch.add_connection(self._bridge, phy2, vm_ports[self._pxp_vm_count-1][-1], self._traffic) # add serial connections among VMs and VM NICs pairs if needed # in case of multiple NICs pairs per VM, the pairs are chained - # first, before flow to the next VM is created + # first, before connection to the next VM is created for vmindex in range(self._pxp_vm_count): # connect VMs NICs pairs in case of 4 and more NICs per VM connections = [(vm_ports[vmindex][2*(x+1)-1], vm_ports[vmindex][2*(x+1)]) for x in range(int(len(vm_ports[vmindex])/2)-1)] for connection in connections: - self._add_flow(flow, - connection[0], - connection[1], - self._bidir) + self._vswitch.add_connection(self._bridge, connection[0], connection[1]) + self._vswitch.add_connection(self._bridge, connection[1], connection[0]) # connect last NICs to the next VM if there is any if self._pxp_vm_count > vmindex + 1: - self._add_flow(flow, - vm_ports[vmindex][-1], - vm_ports[vmindex+1][0], - self._bidir) + self._vswitch.add_connection(self._bridge, vm_ports[vmindex][-1], vm_ports[vmindex+1][0]) + self._vswitch.add_connection(self._bridge, vm_ports[vmindex+1][0], vm_ports[vmindex][-1]) else: - proto = _PROTO_TCP if self._traffic['l3']['proto'].lower() == 'tcp' else _PROTO_UDP - dst_mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value - dst_ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value + mac_value = netaddr.EUI(self._traffic['l2']['dstmac']).value + ip_value = netaddr.IPAddress(self._traffic['l3']['dstip']).value + port_value = self._traffic['l4']['dstport'] # initialize stream index; every NIC pair of every VM uses unique stream stream = 0 for vmindex in range(self._pxp_vm_count): @@ -146,31 +116,33 @@ class VswitchControllerPXP(IVswitchController): port_pairs = [(vm_ports[vmindex][0], vm_ports[vmindex][0])] for port_pair in port_pairs: - flow_p = _FLOW_TEMPLATE.copy() - flow_v = _FLOW_TEMPLATE.copy() - - # update flow based on trafficgen settings + # override traffic options to ensure, that traffic is + # dispatched among VMs connected in parallel + options = {'multistream':1, + 'stream_type':self._traffic['stream_type'], + 'pre_installed_flows':'Yes'} + # update connection based on trafficgen settings if self._traffic['stream_type'] == 'L2': - tmp_mac = netaddr.EUI(dst_mac_value + stream) + tmp_mac = netaddr.EUI(mac_value + stream) tmp_mac.dialect = netaddr.mac_unix_expanded - flow_p.update({'dl_dst':tmp_mac}) + options.update({'l2':{'dstmac':tmp_mac}}) elif self._traffic['stream_type'] == 'L3': - tmp_ip = netaddr.IPAddress(dst_ip_value + stream) - flow_p.update({'dl_type':'0x0800', 'nw_dst':tmp_ip}) + tmp_ip = netaddr.IPAddress(ip_value + stream) + options.update({'l3':{'dstip':tmp_ip}}) elif self._traffic['stream_type'] == 'L4': - flow_p.update({'dl_type':'0x0800', 'nw_proto':proto, 'tp_dst':stream}) + options.update({'l3':{'proto':self._traffic['l3']['proto']}}) + options.update({'l4':{'dstport':(port_value + stream) % 65536}}) else: raise RuntimeError('Unknown stream_type {}'.format(self._traffic['stream_type'])) - # insert flow to dispatch traffic from physical ports + # insert connection to dispatch traffic from physical ports # to VMs based on stream type; all traffic from VMs is # sent to physical ports to avoid issues with MAC swapping # and upper layer mods performed inside guests - self._add_flow(flow_p, phy1_number, port_pair[0]) - self._add_flow(flow_v, port_pair[1], phy2_number) - if self._bidir: - self._add_flow(flow_p, phy2_number, port_pair[1]) - self._add_flow(flow_v, port_pair[0], phy1_number) + self._vswitch.add_connection(self._bridge, phy1, port_pair[0], options) + self._vswitch.add_connection(self._bridge, port_pair[1], phy2) + self._vswitch.add_connection(self._bridge, phy2, port_pair[1], options) + self._vswitch.add_connection(self._bridge, port_pair[0], phy1) # every NIC pair needs its own unique traffic stream stream += 1 @@ -185,37 +157,13 @@ class VswitchControllerPXP(IVswitchController): self._logger.debug('Stop using %s', str(self._vswitch_class)) self._vswitch.stop() - def _add_flow(self, flow, port1, port2, reverse_flow=False): - """ Helper method to insert flow into the vSwitch - """ - self._vswitch.add_flow(self._bridge, - add_ports_to_flow(flow, - port1, - port2)) - if reverse_flow: - self._vswitch.add_flow(self._bridge, - add_ports_to_flow(flow, - port2, - port1)) - - 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 %s', str(self._vswitch_class)) return self._vswitch.get_ports(self._bridge) - def dump_vswitch_flows(self): + def dump_vswitch_connections(self): """See IVswitchController for description """ - self._vswitch.dump_flows(self._bridge) + self._vswitch.dump_connections(self._bridge) |