From 1a089e6059a381a9cb90a17cf17d44e144d30430 Mon Sep 17 00:00:00 2001 From: Adelina Tuvenie Date: Tue, 24 Mar 2015 09:29:45 -0700 Subject: [PATCH] Moves ovs_lib to agent/common This patch moves ovs_lib from agent/linux to agent/common since it will be used by ovs_neutron_agent on both Linux and Windows platforms. To provide compatibility with out of tree code, a placeholder has been left in agent/linux. Unit tests are updated accordingly. Partially implements blueprint: hyper-v-ovs-agent Change-Id: I009f7f5e3b014633541ed5a45628aa1b2287e22b --- neutron/agent/common/ovs_lib.py | 524 ++++++++++++++++++ neutron/agent/linux/interface.py | 2 +- neutron/agent/linux/ovs_lib.py | 518 +---------------- neutron/agent/ovsdb/impl_idl.py | 2 +- neutron/cmd/netns_cleanup.py | 2 +- neutron/cmd/ovs_cleanup.py | 2 +- neutron/cmd/sanity/checks.py | 2 +- .../plugins/ibm/agent/sdnve_neutron_agent.py | 2 +- .../agent/nvsd_neutron_agent.py | 2 +- .../openvswitch/agent/ovs_neutron_agent.py | 2 +- neutron/tests/functional/agent/linux/base.py | 2 +- .../tests/functional/agent/test_l3_agent.py | 2 +- .../tests/functional/agent/test_ovs_lib.py | 2 +- .../agent/{linux => common}/test_ovs_lib.py | 2 +- .../unit/oneconvergence/test_nvsd_agent.py | 2 +- .../openvswitch/test_ovs_dvr_neutron_agent.py | 32 +- .../openvswitch/test_ovs_neutron_agent.py | 26 +- .../tests/unit/openvswitch/test_ovs_tunnel.py | 2 +- neutron/tests/unit/test_linux_interface.py | 6 +- neutron/tests/unit/test_netns_cleanup.py | 10 +- neutron/tests/unit/test_ovs_cleanup.py | 8 +- 21 files changed, 590 insertions(+), 562 deletions(-) create mode 100644 neutron/agent/common/ovs_lib.py mode change 100755 => 100644 neutron/tests/functional/agent/test_l3_agent.py rename neutron/tests/unit/agent/{linux => common}/test_ovs_lib.py (99%) diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py new file mode 100644 index 000000000..8ab1888bc --- /dev/null +++ b/neutron/agent/common/ovs_lib.py @@ -0,0 +1,524 @@ +# Copyright 2011 VMware, Inc. +# All Rights Reserved. +# +# 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. + +import collections +import itertools +import operator + +from oslo_config import cfg +from oslo_log import log as logging +from oslo_utils import excutils +import retrying +import six + +from neutron.agent.linux import ip_lib +from neutron.agent.linux import utils +from neutron.agent.ovsdb import api as ovsdb +from neutron.common import exceptions +from neutron.i18n import _LE, _LI, _LW +from neutron.plugins.common import constants + +# Default timeout for ovs-vsctl command +DEFAULT_OVS_VSCTL_TIMEOUT = 10 + +# Special return value for an invalid OVS ofport +INVALID_OFPORT = -1 +UNASSIGNED_OFPORT = [] + +# OVS bridge fail modes +FAILMODE_SECURE = 'secure' + +OPTS = [ + cfg.IntOpt('ovs_vsctl_timeout', + default=DEFAULT_OVS_VSCTL_TIMEOUT, + help=_('Timeout in seconds for ovs-vsctl commands')), +] +cfg.CONF.register_opts(OPTS) + +LOG = logging.getLogger(__name__) + + +def _ofport_result_pending(result): + """Return True if ovs-vsctl indicates the result is still pending.""" + # ovs-vsctl can return '[]' for an ofport that has not yet been assigned + try: + int(result) + return False + except (ValueError, TypeError): + return True + + +def _ofport_retry(fn): + """Decorator for retrying when OVS has yet to assign an ofport. + + The instance's vsctl_timeout is used as the max waiting time. This relies + on the fact that instance methods receive self as the first argument. + """ + @six.wraps(fn) + def wrapped(*args, **kwargs): + self = args[0] + new_fn = retrying.retry( + retry_on_result=_ofport_result_pending, + stop_max_delay=self.vsctl_timeout * 1000, + wait_exponential_multiplier=10, + wait_exponential_max=1000, + retry_on_exception=lambda _: False)(fn) + return new_fn(*args, **kwargs) + return wrapped + + +class VifPort(object): + def __init__(self, port_name, ofport, vif_id, vif_mac, switch): + self.port_name = port_name + self.ofport = ofport + self.vif_id = vif_id + self.vif_mac = vif_mac + self.switch = switch + + def __str__(self): + return ("iface-id=" + self.vif_id + ", vif_mac=" + + self.vif_mac + ", port_name=" + self.port_name + + ", ofport=" + str(self.ofport) + ", bridge_name=" + + self.switch.br_name) + + +class BaseOVS(object): + + def __init__(self): + self.vsctl_timeout = cfg.CONF.ovs_vsctl_timeout + self.ovsdb = ovsdb.API.get(self) + + def add_bridge(self, bridge_name): + self.ovsdb.add_br(bridge_name).execute() + br = OVSBridge(bridge_name) + # Don't return until vswitchd sets up the internal port + br.get_port_ofport(bridge_name) + return br + + def delete_bridge(self, bridge_name): + self.ovsdb.del_br(bridge_name).execute() + + def bridge_exists(self, bridge_name): + return self.ovsdb.br_exists(bridge_name).execute() + + def port_exists(self, port_name): + cmd = self.ovsdb.db_get('Port', port_name, 'name') + return bool(cmd.execute(check_error=False, log_errors=False)) + + def get_bridge_for_iface(self, iface): + return self.ovsdb.iface_to_br(iface).execute() + + def get_bridges(self): + return self.ovsdb.list_br().execute(check_error=True) + + def get_bridge_external_bridge_id(self, bridge): + return self.ovsdb.br_get_external_id(bridge, 'bridge-id').execute() + + def set_db_attribute(self, table_name, record, column, value, + check_error=False): + self.ovsdb.db_set(table_name, record, (column, value)).execute( + check_error=check_error) + + def clear_db_attribute(self, table_name, record, column): + self.ovsdb.db_clear(table_name, record, column).execute() + + def db_get_val(self, table, record, column, check_error=False): + return self.ovsdb.db_get(table, record, column).execute( + check_error=check_error) + + +class OVSBridge(BaseOVS): + def __init__(self, br_name): + super(OVSBridge, self).__init__() + self.br_name = br_name + + def set_controller(self, controllers): + self.ovsdb.set_controller(self.br_name, + controllers).execute(check_error=True) + + def del_controller(self): + self.ovsdb.del_controller(self.br_name).execute(check_error=True) + + def get_controller(self): + return self.ovsdb.get_controller(self.br_name).execute( + check_error=True) + + def set_secure_mode(self): + self.ovsdb.set_fail_mode(self.br_name, FAILMODE_SECURE).execute( + check_error=True) + + def set_protocols(self, protocols): + self.set_db_attribute('Bridge', self.br_name, 'protocols', protocols, + check_error=True) + + def create(self): + self.ovsdb.add_br(self.br_name).execute() + # Don't return until vswitchd sets up the internal port + self.get_port_ofport(self.br_name) + + def destroy(self): + self.delete_bridge(self.br_name) + + def reset_bridge(self, secure_mode=False): + with self.ovsdb.transaction() as txn: + txn.add(self.ovsdb.del_br(self.br_name)) + txn.add(self.ovsdb.add_br(self.br_name)) + if secure_mode: + txn.add(self.ovsdb.set_fail_mode(self.br_name, + FAILMODE_SECURE)) + + def add_port(self, port_name, *interface_attr_tuples): + with self.ovsdb.transaction() as txn: + txn.add(self.ovsdb.add_port(self.br_name, port_name)) + if interface_attr_tuples: + txn.add(self.ovsdb.db_set('Interface', port_name, + *interface_attr_tuples)) + return self.get_port_ofport(port_name) + + def replace_port(self, port_name, *interface_attr_tuples): + """Replace existing port or create it, and configure port interface.""" + with self.ovsdb.transaction() as txn: + txn.add(self.ovsdb.del_port(port_name)) + txn.add(self.ovsdb.add_port(self.br_name, port_name, + may_exist=False)) + if interface_attr_tuples: + txn.add(self.ovsdb.db_set('Interface', port_name, + *interface_attr_tuples)) + # Don't return until the port has been assigned by vswitchd + self.get_port_ofport(port_name) + + def delete_port(self, port_name): + self.ovsdb.del_port(port_name, self.br_name).execute() + + def run_ofctl(self, cmd, args, process_input=None): + full_args = ["ovs-ofctl", cmd, self.br_name] + args + try: + return utils.execute(full_args, run_as_root=True, + process_input=process_input) + except Exception as e: + LOG.error(_LE("Unable to execute %(cmd)s. Exception: " + "%(exception)s"), + {'cmd': full_args, 'exception': e}) + + def count_flows(self): + flow_list = self.run_ofctl("dump-flows", []).split("\n")[1:] + return len(flow_list) - 1 + + def remove_all_flows(self): + self.run_ofctl("del-flows", []) + + @_ofport_retry + def _get_port_ofport(self, port_name): + return self.db_get_val("Interface", port_name, "ofport") + + def get_port_ofport(self, port_name): + """Get the port's assigned ofport, retrying if not yet assigned.""" + ofport = INVALID_OFPORT + try: + ofport = self._get_port_ofport(port_name) + except retrying.RetryError as e: + LOG.exception(_LE("Timed out retrieving ofport on port %(pname)s. " + "Exception: %(exception)s"), + {'pname': port_name, 'exception': e}) + return ofport + + def get_datapath_id(self): + return self.db_get_val('Bridge', + self.br_name, 'datapath_id') + + def do_action_flows(self, action, kwargs_list): + flow_strs = [_build_flow_expr_str(kw, action) for kw in kwargs_list] + self.run_ofctl('%s-flows' % action, ['-'], '\n'.join(flow_strs)) + + def add_flow(self, **kwargs): + self.do_action_flows('add', [kwargs]) + + def mod_flow(self, **kwargs): + self.do_action_flows('mod', [kwargs]) + + def delete_flows(self, **kwargs): + self.do_action_flows('del', [kwargs]) + + def dump_flows_for_table(self, table): + retval = None + flow_str = "table=%s" % table + flows = self.run_ofctl("dump-flows", [flow_str]) + if flows: + retval = '\n'.join(item for item in flows.splitlines() + if 'NXST' not in item) + return retval + + def deferred(self, **kwargs): + return DeferredOVSBridge(self, **kwargs) + + def add_tunnel_port(self, port_name, remote_ip, local_ip, + tunnel_type=constants.TYPE_GRE, + vxlan_udp_port=constants.VXLAN_UDP_PORT, + dont_fragment=True): + attrs = [('type', tunnel_type)] + # TODO(twilson) This is an OrderedDict solely to make a test happy + options = collections.OrderedDict() + vxlan_uses_custom_udp_port = ( + tunnel_type == constants.TYPE_VXLAN and + vxlan_udp_port != constants.VXLAN_UDP_PORT + ) + if vxlan_uses_custom_udp_port: + options['dst_port'] = vxlan_udp_port + options['df_default'] = str(dont_fragment).lower() + options['remote_ip'] = remote_ip + options['local_ip'] = local_ip + options['in_key'] = 'flow' + options['out_key'] = 'flow' + attrs.append(('options', options)) + + return self.add_port(port_name, *attrs) + + def add_patch_port(self, local_name, remote_name): + attrs = [('type', 'patch'), + ('options', {'peer': remote_name})] + return self.add_port(local_name, *attrs) + + def get_port_name_list(self): + return self.ovsdb.list_ports(self.br_name).execute(check_error=True) + + def get_port_stats(self, port_name): + return self.db_get_val("Interface", port_name, "statistics") + + def get_xapi_iface_id(self, xs_vif_uuid): + args = ["xe", "vif-param-get", "param-name=other-config", + "param-key=nicira-iface-id", "uuid=%s" % xs_vif_uuid] + try: + return utils.execute(args, run_as_root=True).strip() + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_LE("Unable to execute %(cmd)s. " + "Exception: %(exception)s"), + {'cmd': args, 'exception': e}) + + # returns a VIF object for each VIF port + def get_vif_ports(self): + edge_ports = [] + port_names = self.get_port_name_list() + for name in port_names: + external_ids = self.db_get_val("Interface", name, "external_ids", + check_error=True) + ofport = self.db_get_val("Interface", name, "ofport", + check_error=True) + if "iface-id" in external_ids and "attached-mac" in external_ids: + p = VifPort(name, ofport, external_ids["iface-id"], + external_ids["attached-mac"], self) + edge_ports.append(p) + elif ("xs-vif-uuid" in external_ids and + "attached-mac" in external_ids): + # if this is a xenserver and iface-id is not automatically + # synced to OVS from XAPI, we grab it from XAPI directly + iface_id = self.get_xapi_iface_id(external_ids["xs-vif-uuid"]) + p = VifPort(name, ofport, iface_id, + external_ids["attached-mac"], self) + edge_ports.append(p) + + return edge_ports + + def get_vif_port_set(self): + edge_ports = set() + port_names = self.get_port_name_list() + cmd = self.ovsdb.db_list( + 'Interface', port_names, + columns=['name', 'external_ids', 'ofport'], if_exists=True) + results = cmd.execute(check_error=True) + for result in results: + if result['ofport'] == UNASSIGNED_OFPORT: + LOG.warn(_LW("Found not yet ready openvswitch port: %s"), + result['name']) + elif result['ofport'] == INVALID_OFPORT: + LOG.warn(_LW("Found failed openvswitch port: %s"), + result['name']) + elif 'attached-mac' in result['external_ids']: + external_ids = result['external_ids'] + if 'iface-id' in external_ids: + edge_ports.add(external_ids['iface-id']) + elif 'xs-vif-uuid' in external_ids: + iface_id = self.get_xapi_iface_id( + external_ids['xs-vif-uuid']) + edge_ports.add(iface_id) + return edge_ports + + def get_port_tag_dict(self): + """Get a dict of port names and associated vlan tags. + + e.g. the returned dict is of the following form:: + + {u'int-br-eth2': [], + u'patch-tun': [], + u'qr-76d9e6b6-21': 1, + u'tapce5318ff-78': 1, + u'tape1400310-e6': 1} + + The TAG ID is only available in the "Port" table and is not available + in the "Interface" table queried by the get_vif_port_set() method. + + """ + port_names = self.get_port_name_list() + cmd = self.ovsdb.db_list('Port', port_names, columns=['name', 'tag']) + results = cmd.execute(check_error=True) + return {p['name']: p['tag'] for p in results} + + def get_vif_port_by_id(self, port_id): + ports = self.ovsdb.db_find( + 'Interface', ('external_ids', '=', {'iface-id': port_id}), + ('external_ids', '!=', {'attached-mac': ''}), + columns=['external_ids', 'name', 'ofport']).execute() + for port in ports: + if self.br_name != self.get_bridge_for_iface(port['name']): + continue + if port['ofport'] in [UNASSIGNED_OFPORT, INVALID_OFPORT]: + LOG.warn(_LW("ofport: %(ofport)s for VIF: %(vif)s is not a" + " positive integer"), + {'ofport': port['ofport'], 'vif': port_id}) + continue + mac = port['external_ids'].get('attached-mac') + return VifPort(port['name'], port['ofport'], port_id, mac, self) + LOG.info(_LI("Port %(port_id)s not present in bridge %(br_name)s"), + {'port_id': port_id, 'br_name': self.br_name}) + + def delete_ports(self, all_ports=False): + if all_ports: + port_names = self.get_port_name_list() + else: + port_names = (port.port_name for port in self.get_vif_ports()) + + for port_name in port_names: + self.delete_port(port_name) + + def get_local_port_mac(self): + """Retrieve the mac of the bridge's local port.""" + address = ip_lib.IPDevice(self.br_name).link.address + if address: + return address + else: + msg = _('Unable to determine mac address for %s') % self.br_name + raise Exception(msg) + + def __enter__(self): + self.create() + return self + + def __exit__(self, exc_type, exc_value, exc_tb): + self.destroy() + + +class DeferredOVSBridge(object): + '''Deferred OVSBridge. + + This class wraps add_flow, mod_flow and delete_flows calls to an OVSBridge + and defers their application until apply_flows call in order to perform + bulk calls. It wraps also ALLOWED_PASSTHROUGHS calls to avoid mixing + OVSBridge and DeferredOVSBridge uses. + This class can be used as a context, in such case apply_flows is called on + __exit__ except if an exception is raised. + This class is not thread-safe, that's why for every use a new instance + must be implemented. + ''' + ALLOWED_PASSTHROUGHS = 'add_port', 'add_tunnel_port', 'delete_port' + + def __init__(self, br, full_ordered=False, + order=('add', 'mod', 'del')): + '''Constructor. + + :param br: wrapped bridge + :param full_ordered: Optional, disable flow reordering (slower) + :param order: Optional, define in which order flow are applied + ''' + + self.br = br + self.full_ordered = full_ordered + self.order = order + if not self.full_ordered: + self.weights = dict((y, x) for x, y in enumerate(self.order)) + self.action_flow_tuples = [] + + def __getattr__(self, name): + if name in self.ALLOWED_PASSTHROUGHS: + return getattr(self.br, name) + raise AttributeError(name) + + def add_flow(self, **kwargs): + self.action_flow_tuples.append(('add', kwargs)) + + def mod_flow(self, **kwargs): + self.action_flow_tuples.append(('mod', kwargs)) + + def delete_flows(self, **kwargs): + self.action_flow_tuples.append(('del', kwargs)) + + def apply_flows(self): + action_flow_tuples = self.action_flow_tuples + self.action_flow_tuples = [] + if not action_flow_tuples: + return + + if not self.full_ordered: + action_flow_tuples.sort(key=lambda af: self.weights[af[0]]) + + grouped = itertools.groupby(action_flow_tuples, + key=operator.itemgetter(0)) + itemgetter_1 = operator.itemgetter(1) + for action, action_flow_list in grouped: + flows = map(itemgetter_1, action_flow_list) + self.br.do_action_flows(action, flows) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + self.apply_flows() + else: + LOG.exception(_LE("OVS flows could not be applied on bridge %s"), + self.br.br_name) + + +def _build_flow_expr_str(flow_dict, cmd): + flow_expr_arr = [] + actions = None + + if cmd == 'add': + flow_expr_arr.append("hard_timeout=%s" % + flow_dict.pop('hard_timeout', '0')) + flow_expr_arr.append("idle_timeout=%s" % + flow_dict.pop('idle_timeout', '0')) + flow_expr_arr.append("priority=%s" % + flow_dict.pop('priority', '1')) + elif 'priority' in flow_dict: + msg = _("Cannot match priority on flow deletion or modification") + raise exceptions.InvalidInput(error_message=msg) + + if cmd != 'del': + if "actions" not in flow_dict: + msg = _("Must specify one or more actions on flow addition" + " or modification") + raise exceptions.InvalidInput(error_message=msg) + actions = "actions=%s" % flow_dict.pop('actions') + + for key, value in flow_dict.iteritems(): + if key == 'proto': + flow_expr_arr.append(value) + else: + flow_expr_arr.append("%s=%s" % (key, str(value))) + + if actions: + flow_expr_arr.append(actions) + + return ','.join(flow_expr_arr) diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py index d3eb2f10c..43f8b091f 100644 --- a/neutron/agent/linux/interface.py +++ b/neutron/agent/linux/interface.py @@ -21,8 +21,8 @@ from oslo_log import log as logging from oslo_utils import importutils import six +from neutron.agent.common import ovs_lib from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils from neutron.common import constants as n_const from neutron.common import exceptions diff --git a/neutron/agent/linux/ovs_lib.py b/neutron/agent/linux/ovs_lib.py index 8ab1888bc..13a79dcf8 100644 --- a/neutron/agent/linux/ovs_lib.py +++ b/neutron/agent/linux/ovs_lib.py @@ -1,4 +1,4 @@ -# Copyright 2011 VMware, Inc. +# Copyright 2015 Cloudbase Solutions. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -13,512 +13,14 @@ # License for the specific language governing permissions and limitations # under the License. -import collections -import itertools -import operator +# This is a placeholder so that the vendor code that import the ovs_lib +# module from agent/linux doesn't fail +# TODO(atuvenie) remove this module after opening the liberty cycle -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import excutils -import retrying -import six +from neutron.agent.common import ovs_lib -from neutron.agent.linux import ip_lib -from neutron.agent.linux import utils -from neutron.agent.ovsdb import api as ovsdb -from neutron.common import exceptions -from neutron.i18n import _LE, _LI, _LW -from neutron.plugins.common import constants - -# Default timeout for ovs-vsctl command -DEFAULT_OVS_VSCTL_TIMEOUT = 10 - -# Special return value for an invalid OVS ofport -INVALID_OFPORT = -1 -UNASSIGNED_OFPORT = [] - -# OVS bridge fail modes -FAILMODE_SECURE = 'secure' - -OPTS = [ - cfg.IntOpt('ovs_vsctl_timeout', - default=DEFAULT_OVS_VSCTL_TIMEOUT, - help=_('Timeout in seconds for ovs-vsctl commands')), -] -cfg.CONF.register_opts(OPTS) - -LOG = logging.getLogger(__name__) - - -def _ofport_result_pending(result): - """Return True if ovs-vsctl indicates the result is still pending.""" - # ovs-vsctl can return '[]' for an ofport that has not yet been assigned - try: - int(result) - return False - except (ValueError, TypeError): - return True - - -def _ofport_retry(fn): - """Decorator for retrying when OVS has yet to assign an ofport. - - The instance's vsctl_timeout is used as the max waiting time. This relies - on the fact that instance methods receive self as the first argument. - """ - @six.wraps(fn) - def wrapped(*args, **kwargs): - self = args[0] - new_fn = retrying.retry( - retry_on_result=_ofport_result_pending, - stop_max_delay=self.vsctl_timeout * 1000, - wait_exponential_multiplier=10, - wait_exponential_max=1000, - retry_on_exception=lambda _: False)(fn) - return new_fn(*args, **kwargs) - return wrapped - - -class VifPort(object): - def __init__(self, port_name, ofport, vif_id, vif_mac, switch): - self.port_name = port_name - self.ofport = ofport - self.vif_id = vif_id - self.vif_mac = vif_mac - self.switch = switch - - def __str__(self): - return ("iface-id=" + self.vif_id + ", vif_mac=" + - self.vif_mac + ", port_name=" + self.port_name + - ", ofport=" + str(self.ofport) + ", bridge_name=" + - self.switch.br_name) - - -class BaseOVS(object): - - def __init__(self): - self.vsctl_timeout = cfg.CONF.ovs_vsctl_timeout - self.ovsdb = ovsdb.API.get(self) - - def add_bridge(self, bridge_name): - self.ovsdb.add_br(bridge_name).execute() - br = OVSBridge(bridge_name) - # Don't return until vswitchd sets up the internal port - br.get_port_ofport(bridge_name) - return br - - def delete_bridge(self, bridge_name): - self.ovsdb.del_br(bridge_name).execute() - - def bridge_exists(self, bridge_name): - return self.ovsdb.br_exists(bridge_name).execute() - - def port_exists(self, port_name): - cmd = self.ovsdb.db_get('Port', port_name, 'name') - return bool(cmd.execute(check_error=False, log_errors=False)) - - def get_bridge_for_iface(self, iface): - return self.ovsdb.iface_to_br(iface).execute() - - def get_bridges(self): - return self.ovsdb.list_br().execute(check_error=True) - - def get_bridge_external_bridge_id(self, bridge): - return self.ovsdb.br_get_external_id(bridge, 'bridge-id').execute() - - def set_db_attribute(self, table_name, record, column, value, - check_error=False): - self.ovsdb.db_set(table_name, record, (column, value)).execute( - check_error=check_error) - - def clear_db_attribute(self, table_name, record, column): - self.ovsdb.db_clear(table_name, record, column).execute() - - def db_get_val(self, table, record, column, check_error=False): - return self.ovsdb.db_get(table, record, column).execute( - check_error=check_error) - - -class OVSBridge(BaseOVS): - def __init__(self, br_name): - super(OVSBridge, self).__init__() - self.br_name = br_name - - def set_controller(self, controllers): - self.ovsdb.set_controller(self.br_name, - controllers).execute(check_error=True) - - def del_controller(self): - self.ovsdb.del_controller(self.br_name).execute(check_error=True) - - def get_controller(self): - return self.ovsdb.get_controller(self.br_name).execute( - check_error=True) - - def set_secure_mode(self): - self.ovsdb.set_fail_mode(self.br_name, FAILMODE_SECURE).execute( - check_error=True) - - def set_protocols(self, protocols): - self.set_db_attribute('Bridge', self.br_name, 'protocols', protocols, - check_error=True) - - def create(self): - self.ovsdb.add_br(self.br_name).execute() - # Don't return until vswitchd sets up the internal port - self.get_port_ofport(self.br_name) - - def destroy(self): - self.delete_bridge(self.br_name) - - def reset_bridge(self, secure_mode=False): - with self.ovsdb.transaction() as txn: - txn.add(self.ovsdb.del_br(self.br_name)) - txn.add(self.ovsdb.add_br(self.br_name)) - if secure_mode: - txn.add(self.ovsdb.set_fail_mode(self.br_name, - FAILMODE_SECURE)) - - def add_port(self, port_name, *interface_attr_tuples): - with self.ovsdb.transaction() as txn: - txn.add(self.ovsdb.add_port(self.br_name, port_name)) - if interface_attr_tuples: - txn.add(self.ovsdb.db_set('Interface', port_name, - *interface_attr_tuples)) - return self.get_port_ofport(port_name) - - def replace_port(self, port_name, *interface_attr_tuples): - """Replace existing port or create it, and configure port interface.""" - with self.ovsdb.transaction() as txn: - txn.add(self.ovsdb.del_port(port_name)) - txn.add(self.ovsdb.add_port(self.br_name, port_name, - may_exist=False)) - if interface_attr_tuples: - txn.add(self.ovsdb.db_set('Interface', port_name, - *interface_attr_tuples)) - # Don't return until the port has been assigned by vswitchd - self.get_port_ofport(port_name) - - def delete_port(self, port_name): - self.ovsdb.del_port(port_name, self.br_name).execute() - - def run_ofctl(self, cmd, args, process_input=None): - full_args = ["ovs-ofctl", cmd, self.br_name] + args - try: - return utils.execute(full_args, run_as_root=True, - process_input=process_input) - except Exception as e: - LOG.error(_LE("Unable to execute %(cmd)s. Exception: " - "%(exception)s"), - {'cmd': full_args, 'exception': e}) - - def count_flows(self): - flow_list = self.run_ofctl("dump-flows", []).split("\n")[1:] - return len(flow_list) - 1 - - def remove_all_flows(self): - self.run_ofctl("del-flows", []) - - @_ofport_retry - def _get_port_ofport(self, port_name): - return self.db_get_val("Interface", port_name, "ofport") - - def get_port_ofport(self, port_name): - """Get the port's assigned ofport, retrying if not yet assigned.""" - ofport = INVALID_OFPORT - try: - ofport = self._get_port_ofport(port_name) - except retrying.RetryError as e: - LOG.exception(_LE("Timed out retrieving ofport on port %(pname)s. " - "Exception: %(exception)s"), - {'pname': port_name, 'exception': e}) - return ofport - - def get_datapath_id(self): - return self.db_get_val('Bridge', - self.br_name, 'datapath_id') - - def do_action_flows(self, action, kwargs_list): - flow_strs = [_build_flow_expr_str(kw, action) for kw in kwargs_list] - self.run_ofctl('%s-flows' % action, ['-'], '\n'.join(flow_strs)) - - def add_flow(self, **kwargs): - self.do_action_flows('add', [kwargs]) - - def mod_flow(self, **kwargs): - self.do_action_flows('mod', [kwargs]) - - def delete_flows(self, **kwargs): - self.do_action_flows('del', [kwargs]) - - def dump_flows_for_table(self, table): - retval = None - flow_str = "table=%s" % table - flows = self.run_ofctl("dump-flows", [flow_str]) - if flows: - retval = '\n'.join(item for item in flows.splitlines() - if 'NXST' not in item) - return retval - - def deferred(self, **kwargs): - return DeferredOVSBridge(self, **kwargs) - - def add_tunnel_port(self, port_name, remote_ip, local_ip, - tunnel_type=constants.TYPE_GRE, - vxlan_udp_port=constants.VXLAN_UDP_PORT, - dont_fragment=True): - attrs = [('type', tunnel_type)] - # TODO(twilson) This is an OrderedDict solely to make a test happy - options = collections.OrderedDict() - vxlan_uses_custom_udp_port = ( - tunnel_type == constants.TYPE_VXLAN and - vxlan_udp_port != constants.VXLAN_UDP_PORT - ) - if vxlan_uses_custom_udp_port: - options['dst_port'] = vxlan_udp_port - options['df_default'] = str(dont_fragment).lower() - options['remote_ip'] = remote_ip - options['local_ip'] = local_ip - options['in_key'] = 'flow' - options['out_key'] = 'flow' - attrs.append(('options', options)) - - return self.add_port(port_name, *attrs) - - def add_patch_port(self, local_name, remote_name): - attrs = [('type', 'patch'), - ('options', {'peer': remote_name})] - return self.add_port(local_name, *attrs) - - def get_port_name_list(self): - return self.ovsdb.list_ports(self.br_name).execute(check_error=True) - - def get_port_stats(self, port_name): - return self.db_get_val("Interface", port_name, "statistics") - - def get_xapi_iface_id(self, xs_vif_uuid): - args = ["xe", "vif-param-get", "param-name=other-config", - "param-key=nicira-iface-id", "uuid=%s" % xs_vif_uuid] - try: - return utils.execute(args, run_as_root=True).strip() - except Exception as e: - with excutils.save_and_reraise_exception(): - LOG.error(_LE("Unable to execute %(cmd)s. " - "Exception: %(exception)s"), - {'cmd': args, 'exception': e}) - - # returns a VIF object for each VIF port - def get_vif_ports(self): - edge_ports = [] - port_names = self.get_port_name_list() - for name in port_names: - external_ids = self.db_get_val("Interface", name, "external_ids", - check_error=True) - ofport = self.db_get_val("Interface", name, "ofport", - check_error=True) - if "iface-id" in external_ids and "attached-mac" in external_ids: - p = VifPort(name, ofport, external_ids["iface-id"], - external_ids["attached-mac"], self) - edge_ports.append(p) - elif ("xs-vif-uuid" in external_ids and - "attached-mac" in external_ids): - # if this is a xenserver and iface-id is not automatically - # synced to OVS from XAPI, we grab it from XAPI directly - iface_id = self.get_xapi_iface_id(external_ids["xs-vif-uuid"]) - p = VifPort(name, ofport, iface_id, - external_ids["attached-mac"], self) - edge_ports.append(p) - - return edge_ports - - def get_vif_port_set(self): - edge_ports = set() - port_names = self.get_port_name_list() - cmd = self.ovsdb.db_list( - 'Interface', port_names, - columns=['name', 'external_ids', 'ofport'], if_exists=True) - results = cmd.execute(check_error=True) - for result in results: - if result['ofport'] == UNASSIGNED_OFPORT: - LOG.warn(_LW("Found not yet ready openvswitch port: %s"), - result['name']) - elif result['ofport'] == INVALID_OFPORT: - LOG.warn(_LW("Found failed openvswitch port: %s"), - result['name']) - elif 'attached-mac' in result['external_ids']: - external_ids = result['external_ids'] - if 'iface-id' in external_ids: - edge_ports.add(external_ids['iface-id']) - elif 'xs-vif-uuid' in external_ids: - iface_id = self.get_xapi_iface_id( - external_ids['xs-vif-uuid']) - edge_ports.add(iface_id) - return edge_ports - - def get_port_tag_dict(self): - """Get a dict of port names and associated vlan tags. - - e.g. the returned dict is of the following form:: - - {u'int-br-eth2': [], - u'patch-tun': [], - u'qr-76d9e6b6-21': 1, - u'tapce5318ff-78': 1, - u'tape1400310-e6': 1} - - The TAG ID is only available in the "Port" table and is not available - in the "Interface" table queried by the get_vif_port_set() method. - - """ - port_names = self.get_port_name_list() - cmd = self.ovsdb.db_list('Port', port_names, columns=['name', 'tag']) - results = cmd.execute(check_error=True) - return {p['name']: p['tag'] for p in results} - - def get_vif_port_by_id(self, port_id): - ports = self.ovsdb.db_find( - 'Interface', ('external_ids', '=', {'iface-id': port_id}), - ('external_ids', '!=', {'attached-mac': ''}), - columns=['external_ids', 'name', 'ofport']).execute() - for port in ports: - if self.br_name != self.get_bridge_for_iface(port['name']): - continue - if port['ofport'] in [UNASSIGNED_OFPORT, INVALID_OFPORT]: - LOG.warn(_LW("ofport: %(ofport)s for VIF: %(vif)s is not a" - " positive integer"), - {'ofport': port['ofport'], 'vif': port_id}) - continue - mac = port['external_ids'].get('attached-mac') - return VifPort(port['name'], port['ofport'], port_id, mac, self) - LOG.info(_LI("Port %(port_id)s not present in bridge %(br_name)s"), - {'port_id': port_id, 'br_name': self.br_name}) - - def delete_ports(self, all_ports=False): - if all_ports: - port_names = self.get_port_name_list() - else: - port_names = (port.port_name for port in self.get_vif_ports()) - - for port_name in port_names: - self.delete_port(port_name) - - def get_local_port_mac(self): - """Retrieve the mac of the bridge's local port.""" - address = ip_lib.IPDevice(self.br_name).link.address - if address: - return address - else: - msg = _('Unable to determine mac address for %s') % self.br_name - raise Exception(msg) - - def __enter__(self): - self.create() - return self - - def __exit__(self, exc_type, exc_value, exc_tb): - self.destroy() - - -class DeferredOVSBridge(object): - '''Deferred OVSBridge. - - This class wraps add_flow, mod_flow and delete_flows calls to an OVSBridge - and defers their application until apply_flows call in order to perform - bulk calls. It wraps also ALLOWED_PASSTHROUGHS calls to avoid mixing - OVSBridge and DeferredOVSBridge uses. - This class can be used as a context, in such case apply_flows is called on - __exit__ except if an exception is raised. - This class is not thread-safe, that's why for every use a new instance - must be implemented. - ''' - ALLOWED_PASSTHROUGHS = 'add_port', 'add_tunnel_port', 'delete_port' - - def __init__(self, br, full_ordered=False, - order=('add', 'mod', 'del')): - '''Constructor. - - :param br: wrapped bridge - :param full_ordered: Optional, disable flow reordering (slower) - :param order: Optional, define in which order flow are applied - ''' - - self.br = br - self.full_ordered = full_ordered - self.order = order - if not self.full_ordered: - self.weights = dict((y, x) for x, y in enumerate(self.order)) - self.action_flow_tuples = [] - - def __getattr__(self, name): - if name in self.ALLOWED_PASSTHROUGHS: - return getattr(self.br, name) - raise AttributeError(name) - - def add_flow(self, **kwargs): - self.action_flow_tuples.append(('add', kwargs)) - - def mod_flow(self, **kwargs): - self.action_flow_tuples.append(('mod', kwargs)) - - def delete_flows(self, **kwargs): - self.action_flow_tuples.append(('del', kwargs)) - - def apply_flows(self): - action_flow_tuples = self.action_flow_tuples - self.action_flow_tuples = [] - if not action_flow_tuples: - return - - if not self.full_ordered: - action_flow_tuples.sort(key=lambda af: self.weights[af[0]]) - - grouped = itertools.groupby(action_flow_tuples, - key=operator.itemgetter(0)) - itemgetter_1 = operator.itemgetter(1) - for action, action_flow_list in grouped: - flows = map(itemgetter_1, action_flow_list) - self.br.do_action_flows(action, flows) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - if exc_type is None: - self.apply_flows() - else: - LOG.exception(_LE("OVS flows could not be applied on bridge %s"), - self.br.br_name) - - -def _build_flow_expr_str(flow_dict, cmd): - flow_expr_arr = [] - actions = None - - if cmd == 'add': - flow_expr_arr.append("hard_timeout=%s" % - flow_dict.pop('hard_timeout', '0')) - flow_expr_arr.append("idle_timeout=%s" % - flow_dict.pop('idle_timeout', '0')) - flow_expr_arr.append("priority=%s" % - flow_dict.pop('priority', '1')) - elif 'priority' in flow_dict: - msg = _("Cannot match priority on flow deletion or modification") - raise exceptions.InvalidInput(error_message=msg) - - if cmd != 'del': - if "actions" not in flow_dict: - msg = _("Must specify one or more actions on flow addition" - " or modification") - raise exceptions.InvalidInput(error_message=msg) - actions = "actions=%s" % flow_dict.pop('actions') - - for key, value in flow_dict.iteritems(): - if key == 'proto': - flow_expr_arr.append(value) - else: - flow_expr_arr.append("%s=%s" % (key, str(value))) - - if actions: - flow_expr_arr.append(actions) - - return ','.join(flow_expr_arr) +INVALID_OFPORT = ovs_lib.INVALID_OFPORT +BaseOVS = ovs_lib.BaseOVS +OVSBridge = ovs_lib.OVSBridge +VifPort = ovs_lib.VifPort +_build_flow_expr_str = ovs_lib._build_flow_expr_str diff --git a/neutron/agent/ovsdb/impl_idl.py b/neutron/agent/ovsdb/impl_idl.py index 49d9605e6..39a010cda 100644 --- a/neutron/agent/ovsdb/impl_idl.py +++ b/neutron/agent/ovsdb/impl_idl.py @@ -34,7 +34,7 @@ OPTS = [ ] cfg.CONF.register_opts(OPTS, 'OVS') # TODO(twilson) DEFAULT.ovs_vsctl_timeout should be OVS.vsctl_timeout -cfg.CONF.import_opt('ovs_vsctl_timeout', 'neutron.agent.linux.ovs_lib') +cfg.CONF.import_opt('ovs_vsctl_timeout', 'neutron.agent.common.ovs_lib') LOG = logging.getLogger(__name__) diff --git a/neutron/cmd/netns_cleanup.py b/neutron/cmd/netns_cleanup.py index 41ca1edd6..c2b74355f 100644 --- a/neutron/cmd/netns_cleanup.py +++ b/neutron/cmd/netns_cleanup.py @@ -21,6 +21,7 @@ from oslo_log import log as logging from oslo_utils import importutils from neutron.agent.common import config as agent_config +from neutron.agent.common import ovs_lib from neutron.agent.dhcp import config as dhcp_config from neutron.agent.l3 import agent as l3_agent from neutron.agent.l3 import dvr @@ -29,7 +30,6 @@ from neutron.agent.linux import dhcp from neutron.agent.linux import external_process from neutron.agent.linux import interface from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.api.v2 import attributes from neutron.common import config from neutron.i18n import _LE diff --git a/neutron/cmd/ovs_cleanup.py b/neutron/cmd/ovs_cleanup.py index 180fae8ec..6a8a7e3b5 100644 --- a/neutron/cmd/ovs_cleanup.py +++ b/neutron/cmd/ovs_cleanup.py @@ -17,10 +17,10 @@ from oslo_config import cfg from oslo_log import log as logging from neutron.agent.common import config as agent_config +from neutron.agent.common import ovs_lib from neutron.agent.l3 import config as l3_config from neutron.agent.linux import interface from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.common import config from neutron.i18n import _LI diff --git a/neutron/cmd/sanity/checks.py b/neutron/cmd/sanity/checks.py index 5519e16d1..aaeddbb19 100644 --- a/neutron/cmd/sanity/checks.py +++ b/neutron/cmd/sanity/checks.py @@ -19,9 +19,9 @@ import netaddr from oslo_log import log as logging import six +from neutron.agent.common import ovs_lib from neutron.agent.linux import ip_lib from neutron.agent.linux import ip_link_support -from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils as agent_utils from neutron.common import utils from neutron.i18n import _LE diff --git a/neutron/plugins/ibm/agent/sdnve_neutron_agent.py b/neutron/plugins/ibm/agent/sdnve_neutron_agent.py index f76a7ca76..71c4a2a78 100644 --- a/neutron/plugins/ibm/agent/sdnve_neutron_agent.py +++ b/neutron/plugins/ibm/agent/sdnve_neutron_agent.py @@ -26,8 +26,8 @@ from oslo_config import cfg from oslo_log import log as logging import oslo_messaging +from neutron.agent.common import ovs_lib from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent import rpc as agent_rpc from neutron.common import config as common_config from neutron.common import constants as n_const diff --git a/neutron/plugins/oneconvergence/agent/nvsd_neutron_agent.py b/neutron/plugins/oneconvergence/agent/nvsd_neutron_agent.py index 63dbae439..3ee3b7bf8 100644 --- a/neutron/plugins/oneconvergence/agent/nvsd_neutron_agent.py +++ b/neutron/plugins/oneconvergence/agent/nvsd_neutron_agent.py @@ -24,7 +24,7 @@ eventlet.monkey_patch() from oslo_log import log as logging import oslo_messaging -from neutron.agent.linux import ovs_lib +from neutron.agent.common import ovs_lib from neutron.agent import rpc as agent_rpc from neutron.agent import securitygroups_rpc as sg_rpc from neutron.common import config as common_config diff --git a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py index 5bacef114..9b8aabb72 100644 --- a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py @@ -26,9 +26,9 @@ import oslo_messaging from six import moves from neutron.agent.common import config +from neutron.agent.common import ovs_lib from neutron.agent import l2population_rpc from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent.linux import polling from neutron.agent.linux import utils from neutron.agent import rpc as agent_rpc diff --git a/neutron/tests/functional/agent/linux/base.py b/neutron/tests/functional/agent/linux/base.py index 96e2e1b96..de7638540 100644 --- a/neutron/tests/functional/agent/linux/base.py +++ b/neutron/tests/functional/agent/linux/base.py @@ -15,9 +15,9 @@ import netaddr import testscenarios +from neutron.agent.common import ovs_lib from neutron.agent.linux import bridge_lib from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.common import constants as n_const from neutron.tests.common import base from neutron.tests.common import net_helpers diff --git a/neutron/tests/functional/agent/test_l3_agent.py b/neutron/tests/functional/agent/test_l3_agent.py old mode 100755 new mode 100644 index 3dafa10ae..83d521e96 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -26,6 +26,7 @@ import webob.dec import webob.exc from neutron.agent.common import config as agent_config +from neutron.agent.common import ovs_lib from neutron.agent.l3 import agent as neutron_l3_agent from neutron.agent.l3 import dvr_snat_ns from neutron.agent.l3 import namespaces @@ -33,7 +34,6 @@ from neutron.agent import l3_agent as l3_agent_main from neutron.agent.linux import dhcp from neutron.agent.linux import external_process from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils from neutron.common import config as common_config from neutron.common import constants as l3_constants diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py index 7c709b380..ad5b17004 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -15,7 +15,7 @@ import collections -from neutron.agent.linux import ovs_lib +from neutron.agent.common import ovs_lib from neutron.tests.common import net_helpers from neutron.tests.functional.agent.linux import base diff --git a/neutron/tests/unit/agent/linux/test_ovs_lib.py b/neutron/tests/unit/agent/common/test_ovs_lib.py similarity index 99% rename from neutron/tests/unit/agent/linux/test_ovs_lib.py rename to neutron/tests/unit/agent/common/test_ovs_lib.py index 3924dbfcb..0690bad54 100644 --- a/neutron/tests/unit/agent/linux/test_ovs_lib.py +++ b/neutron/tests/unit/agent/common/test_ovs_lib.py @@ -17,7 +17,7 @@ import mock from oslo_serialization import jsonutils import testtools -from neutron.agent.linux import ovs_lib +from neutron.agent.common import ovs_lib from neutron.agent.linux import utils from neutron.common import exceptions from neutron.openstack.common import uuidutils diff --git a/neutron/tests/unit/oneconvergence/test_nvsd_agent.py b/neutron/tests/unit/oneconvergence/test_nvsd_agent.py index 309ba2414..6cd2615e1 100644 --- a/neutron/tests/unit/oneconvergence/test_nvsd_agent.py +++ b/neutron/tests/unit/oneconvergence/test_nvsd_agent.py @@ -19,7 +19,7 @@ import mock from oslo_config import cfg import testtools -from neutron.agent.linux import ovs_lib +from neutron.agent.common import ovs_lib from neutron.agent import securitygroups_rpc as sg_rpc from neutron.common import topics from neutron.extensions import securitygroup as ext_sg diff --git a/neutron/tests/unit/openvswitch/test_ovs_dvr_neutron_agent.py b/neutron/tests/unit/openvswitch/test_ovs_dvr_neutron_agent.py index 13d252114..35f54a4c8 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_dvr_neutron_agent.py +++ b/neutron/tests/unit/openvswitch/test_ovs_dvr_neutron_agent.py @@ -60,16 +60,16 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.' 'OVSNeutronAgent.setup_ancillary_bridges', return_value=[]), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'create'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_secure_mode'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'get_local_port_mac', return_value='00:00:00:00:00:01'), mock.patch('neutron.agent.linux.utils.get_interface_mac', return_value='00:00:00:00:00:01'), - mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.get_bridges'), + mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges'), mock.patch('neutron.openstack.common.loopingcall.' 'FixedIntervalLoopingCall', new=MockFixedIntervalLoopingCall)): @@ -129,11 +129,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): physical_network = self._physical_network segmentation_id = self._segmentation_id network_type = p_const.TYPE_VLAN - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object(self.agent.dvr_agent.plugin_rpc, @@ -249,11 +249,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): self._compute_port.vif_mac = '77:88:99:00:11:22' physical_network = self._physical_network segmentation_id = self._segmentation_id - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object(self.agent.dvr_agent.plugin_rpc, @@ -381,11 +381,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10): self._setup_for_dvr_test() - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( @@ -429,11 +429,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( @@ -510,11 +510,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): else: gateway_ip = '2001:100::1' cidr = '2001:100::0/64' - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( @@ -587,11 +587,11 @@ class TestOvsDvrNeutronAgent(base.BaseTestCase): def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10): self._setup_for_dvr_test() - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True): with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=self._old_local_vlan), mock.patch.object( diff --git a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py index e2893a27e..1df71fe84 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/openvswitch/test_ovs_neutron_agent.py @@ -22,9 +22,9 @@ from oslo_config import cfg from oslo_log import log import testtools +from neutron.agent.common import ovs_lib from neutron.agent.linux import async_process from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils from neutron.common import constants as n_const from neutron.plugins.common import constants as p_const @@ -115,16 +115,16 @@ class TestOvsNeutronAgent(base.BaseTestCase): mock.patch('neutron.plugins.openvswitch.agent.ovs_neutron_agent.' 'OVSNeutronAgent.setup_ancillary_bridges', return_value=[]), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'create'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_secure_mode'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'get_local_port_mac', return_value='00:00:00:00:00:01'), mock.patch('neutron.agent.linux.utils.get_interface_mac', return_value='00:00:00:00:00:01'), - mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.get_bridges'), + mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges'), mock.patch('neutron.openstack.common.loopingcall.' 'FixedIntervalLoopingCall', new=MockFixedIntervalLoopingCall)): @@ -147,9 +147,9 @@ class TestOvsNeutronAgent(base.BaseTestCase): ovs_neutron_agent.LocalVLANMapping( old_local_vlan, None, None, None)) with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=old_local_vlan), mock.patch.object(self.agent.int_br, 'delete_flows') ) as (set_ovs_db_func, get_ovs_db_func, delete_flows_func): @@ -191,9 +191,9 @@ class TestOvsNeutronAgent(base.BaseTestCase): port = mock.Mock() port.ofport = 1 with contextlib.nested( - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_db_attribute', return_value=True), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'db_get_val', return_value=cur_tag), mock.patch.object(self.agent.int_br, 'add_flow') ) as (set_ovs_db_func, get_ovs_db_func, add_flow_func): @@ -1121,14 +1121,14 @@ class AncillaryBridgesTest(base.BaseTestCase): 'OVSNeutronAgent.setup_integration_br'), mock.patch('neutron.agent.linux.utils.get_interface_mac', return_value='00:00:00:00:00:01'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'get_local_port_mac', return_value='00:00:00:00:00:01'), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.' + mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'set_secure_mode'), - mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.get_bridges', + mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges', return_value=bridges), - mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.' + mock.patch('neutron.agent.common.ovs_lib.BaseOVS.' 'get_bridge_external_bridge_id', side_effect=pullup_side_effect)): self.agent = ovs_neutron_agent.OVSNeutronAgent(**self.kwargs) diff --git a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py index c2fe7db59..561ca80e9 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py +++ b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py @@ -21,8 +21,8 @@ import mock from oslo_config import cfg from oslo_log import log +from neutron.agent.common import ovs_lib from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.plugins.common import constants as p_const from neutron.plugins.openvswitch.agent import ovs_neutron_agent from neutron.plugins.openvswitch.common import constants diff --git a/neutron/tests/unit/test_linux_interface.py b/neutron/tests/unit/test_linux_interface.py index 29b64e8cd..fd0d73f89 100644 --- a/neutron/tests/unit/test_linux_interface.py +++ b/neutron/tests/unit/test_linux_interface.py @@ -16,9 +16,9 @@ import mock from neutron.agent.common import config +from neutron.agent.common import ovs_lib from neutron.agent.linux import interface from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.agent.linux import utils from neutron.common import constants from neutron.extensions import flavor @@ -273,7 +273,7 @@ class TestOVSInterfaceDriver(TestBase): def test_unplug(self, bridge=None): if not bridge: bridge = 'br-int' - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge') as ovs_br: + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge') as ovs_br: ovs = interface.OVSInterfaceDriver(self.conf) ovs.unplug('tap0') ovs_br.assert_has_calls([mock.call(bridge), @@ -347,7 +347,7 @@ class TestOVSInterfaceDriverWithVeth(TestOVSInterfaceDriver): def test_unplug(self, bridge=None): if not bridge: bridge = 'br-int' - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge') as ovs_br: + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge') as ovs_br: ovs = interface.OVSInterfaceDriver(self.conf) ovs.unplug('ns-0', bridge=bridge) ovs_br.assert_has_calls([mock.call(bridge), diff --git a/neutron/tests/unit/test_netns_cleanup.py b/neutron/tests/unit/test_netns_cleanup.py index 9b28fac04..2da02c77f 100644 --- a/neutron/tests/unit/test_netns_cleanup.py +++ b/neutron/tests/unit/test_netns_cleanup.py @@ -96,9 +96,10 @@ class TestNetnsCleanup(base.BaseTestCase): device.name = 'tap1' device.link.delete.side_effect = RuntimeError - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge') as ovs_br_cls: + with mock.patch( + 'neutron.agent.common.ovs_lib.OVSBridge') as ovs_br_cls: br_patch = mock.patch( - 'neutron.agent.linux.ovs_lib.BaseOVS.get_bridge_for_iface') + 'neutron.agent.common.ovs_lib.BaseOVS.get_bridge_for_iface') with br_patch as mock_get_bridge_for_iface: mock_get_bridge_for_iface.return_value = 'br-int' ovs_bridge = mock.Mock() @@ -119,9 +120,10 @@ class TestNetnsCleanup(base.BaseTestCase): device.name = 'tap1' device.link.delete.side_effect = RuntimeError - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge') as ovs_br_cls: + with mock.patch( + 'neutron.agent.common.ovs_lib.OVSBridge') as ovs_br_cls: br_patch = mock.patch( - 'neutron.agent.linux.ovs_lib.BaseOVS.get_bridge_for_iface') + 'neutron.agent.common.ovs_lib.BaseOVS.get_bridge_for_iface') with br_patch as mock_get_bridge_for_iface: with mock.patch.object(util.LOG, 'debug') as debug: mock_get_bridge_for_iface.return_value = None diff --git a/neutron/tests/unit/test_ovs_cleanup.py b/neutron/tests/unit/test_ovs_cleanup.py index 591f9204c..6e650dd28 100644 --- a/neutron/tests/unit/test_ovs_cleanup.py +++ b/neutron/tests/unit/test_ovs_cleanup.py @@ -17,8 +17,8 @@ import contextlib import itertools import mock +from neutron.agent.common import ovs_lib from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib from neutron.cmd import ovs_cleanup as util from neutron.openstack.common import uuidutils from neutron.tests import base @@ -37,9 +37,9 @@ class TestOVSCleanup(base.BaseTestCase): mock.patch('neutron.common.config.setup_logging'), mock.patch('neutron.cmd.ovs_cleanup.setup_conf', return_value=conf), - mock.patch('neutron.agent.linux.ovs_lib.BaseOVS.get_bridges', + mock.patch('neutron.agent.common.ovs_lib.BaseOVS.get_bridges', return_value=bridges), - mock.patch('neutron.agent.linux.ovs_lib.OVSBridge'), + mock.patch('neutron.agent.common.ovs_lib.OVSBridge'), mock.patch.object(util, 'collect_neutron_ports', return_value=ports), mock.patch.object(util, 'delete_neutron_ports') @@ -60,7 +60,7 @@ class TestOVSCleanup(base.BaseTestCase): '99:00:aa:bb:cc:dd', 'br') ports = [[port1, port2], [port3]] portnames = [p.port_name for p in itertools.chain(*ports)] - with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge') as ovs: + with mock.patch('neutron.agent.common.ovs_lib.OVSBridge') as ovs: ovs.return_value.get_vif_ports.side_effect = ports bridges = ['br-int', 'br-ex'] ret = util.collect_neutron_ports(bridges) -- 2.45.2