diff options
Diffstat (limited to 'vswitches')
-rw-r--r-- | vswitches/ovs.py | 229 | ||||
-rw-r--r-- | vswitches/ovs_dpdk_vhost.py | 130 | ||||
-rw-r--r-- | vswitches/ovs_vanilla.py | 129 |
3 files changed, 261 insertions, 227 deletions
diff --git a/vswitches/ovs.py b/vswitches/ovs.py new file mode 100644 index 00000000..06dc7a1a --- /dev/null +++ b/vswitches/ovs.py @@ -0,0 +1,229 @@ +# 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. + +"""VSPERF Open vSwitch base class +""" + +import logging +import re +from conf import settings +from vswitches.vswitch import IVSwitch +from src.ovs import OFBridge, flow_key, flow_match + +_VSWITCHD_CONST_ARGS = ['--', '--pidfile', '--log-file'] + +class IVSwitchOvs(IVSwitch): + """Open vSwitch base class implementation + + The method docstrings document only considerations specific to this + implementation. For generic information of the nature of the methods, + see the interface. + """ + + def __init__(self): + """See IVswitch for general description + """ + self._vswitchd = None + self._logger = logging.getLogger(__name__) + self._bridges = {} + self._vswitchd_args = _VSWITCHD_CONST_ARGS + + def start(self): + """See IVswitch for general description + """ + self._logger.info("Starting vswitchd...") + self._vswitchd.start() + self._logger.info("Vswitchd...Started.") + + def stop(self): + """See IVswitch for general description + """ + self._logger.info("Terminating vswitchd...") + self._vswitchd.kill() + self._logger.info("Vswitchd...Terminated.") + + def add_switch(self, switch_name, params=None): + """See IVswitch for general description + """ + bridge = OFBridge(switch_name) + bridge.create(params) + bridge.set_db_attribute('Open_vSwitch', '.', + 'other_config:max-idle', + settings.getValue('VSWITCH_FLOW_TIMEOUT')) + self._bridges[switch_name] = bridge + + def del_switch(self, switch_name): + """See IVswitch for general description + """ + bridge = self._bridges[switch_name] + self._bridges.pop(switch_name) + bridge.destroy() + + def add_phy_port(self, switch_name): + """See IVswitch for general description + """ + raise NotImplementedError + + def add_vport(self, switch_name): + """See IVswitch for general description + """ + raise NotImplementedError + + 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 + """ + bridge = self._bridges[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.del_port(port_name) + + def add_flow(self, switch_name, flow, cache='off'): + """See IVswitch for general description + """ + bridge = self._bridges[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.del_flow(flow) + + def dump_flows(self, switch_name): + """See IVswitch for general description + """ + 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 + """ + 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 + + def validate_add_switch(self, result, switch_name, params=None): + """Validate - Create a new logical switch with no ports + """ + bridge = self._bridges[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 + return True + + def validate_del_switch(self, result, switch_name): + """Validate removal of switch + """ + bridge = OFBridge('tmp') + 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 None + return True + + def validate_add_phy_port(self, result, switch_name): + """ Validate that physical port was added to bridge. + """ + bridge = self._bridges[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 + assert re.search('Interface ["\']?%s["\']?' % result[0], output[0]) is not None + return True + + def validate_add_vport(self, result, switch_name): + """ Validate that virtual port was added to bridge. + """ + return self.validate_add_phy_port(result, switch_name) + + def validate_del_port(self, result, switch_name, port_name): + """ Validate that port_name was removed from bridge. + """ + bridge = self._bridges[switch_name] + output = bridge.run_vsctl(['show'], check_error=True) + assert not output[1] # there shouldn't be any stderr, but in case + assert 'Port "%s"' % port_name not in output[0] + return True + + def validate_add_flow(self, result, switch_name, flow, cache='off'): + """ Validate insertion of the flow into the switch + """ + if 'idle_timeout' in flow: + del(flow['idle_timeout']) + + # Note: it should be possible to call `ovs-ofctl dump-flows switch flow` + # to verify flow insertion, but it doesn't accept the same flow syntax + # as add-flow, so we have to compare it the hard way + + # get dump of flows and compare them one by one + flow_src = flow_key(flow) + bridge = self._bridges[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): + # flow was added correctly + return True + return False + + def validate_del_flow(self, result, switch_name, flow=None): + """ Validate removal of the flow + """ + if not flow: + # what else we can do? + return True + return not self.validate_add_flow(result, switch_name, flow) + + def validate_dump_flows(self, result, switch_name): + """ Validate call of flow dump + """ + return True diff --git a/vswitches/ovs_dpdk_vhost.py b/vswitches/ovs_dpdk_vhost.py index 2ace64a2..9d29c9d1 100644 --- a/vswitches/ovs_dpdk_vhost.py +++ b/vswitches/ovs_dpdk_vhost.py @@ -17,13 +17,11 @@ import logging from conf import settings -from vswitches.vswitch import IVSwitch -from src.ovs import VSwitchd, OFBridge +from vswitches.ovs import IVSwitchOvs +from src.ovs import VSwitchd from src.dpdk import dpdk -_VSWITCHD_CONST_ARGS = ['--', '--pidfile', '--log-file'] - -class OvsDpdkVhost(IVSwitch): +class OvsDpdkVhost(IVSwitchOvs): """ Open vSwitch with DPDK support Generic OVS wrapper functionality in src.ovs is maximally used. This @@ -35,21 +33,19 @@ class OvsDpdkVhost(IVSwitch): see the interface. """ - _logger = logging.getLogger() - def __init__(self): - vswitchd_args = ['--dpdk'] - vswitchd_args += settings.getValue('VSWITCHD_DPDK_ARGS') - vswitchd_args += _VSWITCHD_CONST_ARGS + super(OvsDpdkVhost, self).__init__() + self._logger = logging.getLogger(__name__) + self._vswitchd_args = ['--dpdk'] + self._vswitchd_args += settings.getValue('VSWITCHD_DPDK_ARGS') if settings.getValue('VNF').endswith('Cuse'): self._logger.info("Inserting VHOST Cuse modules into kernel...") dpdk.insert_vhost_modules() - self._vswitchd = VSwitchd(vswitchd_args=vswitchd_args, + self._vswitchd = VSwitchd(vswitchd_args=self._vswitchd_args, expected_cmd= r'EAL: Master l*core \d+ is ready') - self._bridges = {} def start(self): """See IVswitch for general description @@ -57,47 +53,32 @@ class OvsDpdkVhost(IVSwitch): Activates DPDK kernel modules, ovsdb and vswitchd. """ dpdk.init() - self._vswitchd.start() + super(OvsDpdkVhost, self).start() def stop(self): """See IVswitch for general description Kills ovsdb and vswitchd and removes DPDK kernel modules. """ - self._vswitchd.kill() + super(OvsDpdkVhost, self).stop() dpdk.cleanup() dpdk.remove_vhost_modules() def add_switch(self, switch_name, params=None): """See IVswitch for general description """ - bridge = OFBridge(switch_name) - if params is None: - bridge.create(['--', 'set', 'bridge', switch_name, - 'datapath_type=netdev']) - else: - bridge.create(['--', 'set', 'bridge', switch_name, - 'datapath_type=netdev'] + params) + switch_params = ['--', 'set', 'bridge', switch_name, 'datapath_type=netdev'] + if params: + switch_params = switch_params + params - bridge.set_db_attribute('Open_vSwitch', '.', - 'other_config:max-idle', - settings.getValue('VSWITCH_FLOW_TIMEOUT')) + super(OvsDpdkVhost, self).add_switch(switch_name, switch_params) if settings.getValue('VSWITCH_AFFINITIZATION_ON') == 1: # Sets the PMD core mask to VSWITCH_PMD_CPU_MASK # for CPU core affinitization - bridge.set_db_attribute('Open_vSwitch', '.', - 'other_config:pmd-cpu-mask', - settings.getValue('VSWITCH_PMD_CPU_MASK')) - - self._bridges[switch_name] = bridge - - def del_switch(self, switch_name): - """See IVswitch for general description - """ - bridge = self._bridges[switch_name] - self._bridges.pop(switch_name) - bridge.destroy() + self._bridges[switch_name].set_db_attribute('Open_vSwitch', '.', + 'other_config:pmd-cpu-mask', + settings.getValue('VSWITCH_PMD_CPU_MASK')) def add_phy_port(self, switch_name): """See IVswitch for general description @@ -134,80 +115,3 @@ class OvsDpdkVhost(IVSwitch): of_port = bridge.add_port(port_name, params) return (port_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 - """ - bridge = self._bridges[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.del_port(port_name) - - def add_flow(self, switch_name, flow, cache='off'): - """See IVswitch for general description - """ - bridge = self._bridges[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.del_flow(flow) - - def dump_flows(self, switch_name): - """See IVswitch for general description - """ - 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/ovs_vanilla.py b/vswitches/ovs_vanilla.py index 078d7006..6a380b1b 100644 --- a/vswitches/ovs_vanilla.py +++ b/vswitches/ovs_vanilla.py @@ -17,15 +17,12 @@ import logging from conf import settings -from vswitches.vswitch import IVSwitch -from src.ovs import VSwitchd, OFBridge, DPCtl +from vswitches.ovs import IVSwitchOvs +from src.ovs import VSwitchd, DPCtl from tools.module_manager import ModuleManager from tools import tasks -_LOGGER = logging.getLogger(__name__) -VSWITCHD_CONST_ARGS = ['--', '--log-file'] - -class OvsVanilla(IVSwitch): +class OvsVanilla(IVSwitchOvs): """ Open vSwitch This is wrapper for functionality implemented in src.ovs. @@ -35,16 +32,16 @@ class OvsVanilla(IVSwitch): see the interface definition. """ - _logger = logging.getLogger() _ports = settings.getValue('VSWITCH_VANILLA_PHY_PORT_NAMES') _current_id = 0 _vport_id = 0 def __init__(self): - #vswitchd_args = VSWITCHD_CONST_ARGS - vswitchd_args = ["unix:%s" % VSwitchd.get_db_sock_path()] - vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS') - self._vswitchd = VSwitchd(vswitchd_args=vswitchd_args, + super(OvsVanilla, self).__init__() + self._logger = logging.getLogger(__name__) + self._vswitchd_args = ["unix:%s" % VSwitchd.get_db_sock_path()] + self._vswitchd_args += settings.getValue('VSWITCHD_VANILLA_ARGS') + self._vswitchd = VSwitchd(vswitchd_args=self._vswitchd_args, expected_cmd="db.sock: connected") self._bridges = {} self._module_manager = ModuleManager() @@ -56,9 +53,7 @@ class OvsVanilla(IVSwitch): """ self._module_manager.insert_modules( settings.getValue('VSWITCH_VANILLA_KERNEL_MODULES')) - self._logger.info("Starting Vswitchd...") - self._vswitchd.start() - self._logger.info("Vswitchd...Started.") + super(OvsVanilla, self).start() def stop(self): """See IVswitch for general description @@ -70,32 +65,16 @@ class OvsVanilla(IVSwitch): tapx = 'tap' + str(i) tasks.run_task(['sudo', 'ip', 'tuntap', 'del', tapx, 'mode', 'tap'], - _LOGGER, 'Deleting ' + tapx, False) + self._logger, 'Deleting ' + tapx, False) self._vport_id = 0 - self._vswitchd.kill() + super(OvsVanilla, self).stop() dpctl = DPCtl() dpctl.del_dp() self._module_manager.remove_modules() - def add_switch(self, switch_name, params=None): - """See IVswitch for general description - """ - bridge = OFBridge(switch_name) - bridge.create(params) - bridge.set_db_attribute('Open_vSwitch', '.', - 'other_config:max-idle', '60000') - self._bridges[switch_name] = bridge - - def del_switch(self, switch_name): - """See IVswitch for general description - """ - bridge = self._bridges[switch_name] - self._bridges.pop(switch_name) - bridge.destroy() - def add_phy_port(self, switch_name): """ Method adds port based on configured VSWITCH_VANILLA_PHY_PORT_NAMES @@ -119,7 +98,7 @@ class OvsVanilla(IVSwitch): # For PVP only tasks.run_task(['sudo', 'ifconfig', port_name, '0'], - _LOGGER, 'Remove IP', False) + self._logger, 'Remove IP', False) of_port = bridge.add_port(port_name, params) self._current_id += 1 @@ -137,95 +116,17 @@ class OvsVanilla(IVSwitch): tasks.run_task(['sudo', 'ip', 'tuntap', 'del', tap_name, 'mode', 'tap'], - _LOGGER, 'Creating tap device...', False) + self._logger, 'Creating tap device...', False) tasks.run_task(['sudo', 'ip', 'tuntap', 'add', tap_name, 'mode', 'tap'], - _LOGGER, 'Creating tap device...', False) + self._logger, 'Creating tap device...', False) tasks.run_task(['sudo', 'ifconfig', tap_name, '0'], - _LOGGER, 'Bring up ' + tap_name, False) + self._logger, 'Bring up ' + tap_name, False) bridge = self._bridges[switch_name] 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 - """ - bridge = self._bridges[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.del_port(port_name) - - def add_flow(self, switch_name, flow, cache='off'): - """See IVswitch for general description - """ - bridge = self._bridges[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.del_flow(flow) - - def dump_flows(self, switch_name): - """See IVswitch for general description - """ - 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 - |