diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index 0b3adec0004..9fa098f25b9 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -33,6 +33,8 @@ from neutron.plugins.common import constants as p_const from neutron.plugins.ml2.drivers.openvswitch.agent.common \ import constants +UINT64_BITMASK = (1 << 64) - 1 + # Default timeout for ovs-vsctl command DEFAULT_OVS_VSCTL_TIMEOUT = 10 @@ -177,10 +179,14 @@ class OVSBridge(BaseOVS): super(OVSBridge, self).__init__() self.br_name = br_name self.datapath_type = datapath_type - self.agent_uuid_stamp = 0 + self._default_cookie = generate_random_cookie() + + @property + def default_cookie(self): + return self._default_cookie def set_agent_uuid_stamp(self, val): - self.agent_uuid_stamp = val + self._default_cookie = val def set_controller(self, controllers): self.ovsdb.set_controller(self.br_name, @@ -286,7 +292,7 @@ class OVSBridge(BaseOVS): if action != 'del': for kw in kwargs_list: if 'cookie' not in kw: - kw['cookie'] = self.agent_uuid_stamp + kw['cookie'] = self._default_cookie flow_strs = [_build_flow_expr_str(kw, action) for kw in kwargs_list] self.run_ofctl('%s-flows' % action, ['-'], '\n'.join(flow_strs)) @@ -300,8 +306,15 @@ class OVSBridge(BaseOVS): self.do_action_flows('del', [kwargs]) def dump_flows_for_table(self, table): + return self.dump_flows_for(table=table) + + def dump_flows_for(self, **kwargs): retval = None - flow_str = "table=%s" % table + if "cookie" in kwargs: + kwargs["cookie"] = check_cookie_mask(str(kwargs["cookie"])) + flow_str = ",".join("=".join([key, str(val)]) + for key, val in kwargs.items()) + flows = self.run_ofctl("dump-flows", [flow_str]) if flows: retval = '\n'.join(item for item in flows.splitlines() @@ -680,3 +693,14 @@ def _build_flow_expr_str(flow_dict, cmd): flow_expr_arr.append(actions) return ','.join(flow_expr_arr) + + +def generate_random_cookie(): + return uuid.uuid4().int & UINT64_BITMASK + + +def check_cookie_mask(cookie): + if '/' not in cookie: + return cookie + '/-1' + else: + return cookie diff --git a/neutron/agent/l2/agent_extension.py b/neutron/agent/l2/agent_extension.py index d77ea84ebf2..8604b000c33 100644 --- a/neutron/agent/l2/agent_extension.py +++ b/neutron/agent/l2/agent_extension.py @@ -57,3 +57,12 @@ class AgentCoreResourceExtension(object): :param context: rpc context :param data: port data """ + + def consume_api(self, agent_api): + """Consume the AgentAPI instance from the AgentExtensionsManager + + This allows extensions to gain access to resources limited to the + NeutronAgent. + + :param agent_api: An instance of an agent specific API + """ diff --git a/neutron/agent/l2/extensions/manager.py b/neutron/agent/l2/extensions/manager.py index 2f0436dfe80..181de860f58 100644 --- a/neutron/agent/l2/extensions/manager.py +++ b/neutron/agent/l2/extensions/manager.py @@ -43,7 +43,7 @@ class AgentExtensionsManager(stevedore.named.NamedExtensionManager): invoke_on_load=True, name_order=True) LOG.info(_LI("Loaded agent extensions: %s"), self.names()) - def initialize(self, connection, driver_type): + def initialize(self, connection, driver_type, agent_api=None): """Initialize enabled L2 agent extensions. :param connection: RPC connection that can be reused by extensions to @@ -51,10 +51,14 @@ class AgentExtensionsManager(stevedore.named.NamedExtensionManager): :param driver_type: a string that defines the agent type to the extension. Can be used by the extension to choose the right backend implementation. + :param agent_api: an AgentAPI instance that provides an API to + interact with the agent that the manager + is running in. """ # Initialize each agent extension in the list. for extension in self: LOG.info(_LI("Initializing agent extension '%s'"), extension.name) + extension.obj.consume_api(agent_api) extension.obj.initialize(connection, driver_type) def handle_port(self, context, data): diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/br_cookie.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/br_cookie.py new file mode 100644 index 00000000000..eafba8f54f5 --- /dev/null +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/br_cookie.py @@ -0,0 +1,49 @@ +# Copyright 2016 Intel Corporation. +# 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. + +from neutron.agent.common import ovs_lib + + +class OVSBridgeCookieMixin(object): + '''Mixin to provide cookie retention functionality + to the OVSAgentBridge + ''' + + def __init__(self, *args, **kwargs): + super(OVSBridgeCookieMixin, self).__init__(*args, **kwargs) + self._reserved_cookies = set() + + @property + def reserved_cookies(self): + if self._default_cookie not in self._reserved_cookies: + self._reserved_cookies.add(self._default_cookie) + return set(self._reserved_cookies) + + def request_cookie(self): + if self._default_cookie not in self._reserved_cookies: + self._reserved_cookies.add(self._default_cookie) + + uuid_stamp = ovs_lib.generate_random_cookie() + while uuid_stamp in self._reserved_cookies: + uuid_stamp = ovs_lib.generate_random_cookie() + + self._reserved_cookies.add(uuid_stamp) + return uuid_stamp + + def set_agent_uuid_stamp(self, val): + self._reserved_cookies.add(val) + if self._default_cookie in self._reserved_cookies: + self._reserved_cookies.remove(self._default_cookie) + super(OVSBridgeCookieMixin, self).set_agent_uuid_stamp(val) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py index 6682eb12560..eed5eac0b4b 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_tun.py @@ -108,7 +108,7 @@ class OVSTunnelBridge(ovs_bridge.OVSAgentBridge, ] actions = [ ofpp.NXActionLearn(table_id=constants.UCAST_TO_TUN, - cookie=self.agent_uuid_stamp, + cookie=self.default_cookie, priority=1, hard_timeout=300, specs=flow_specs), diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py index 42572ee4849..d19dc83d8ce 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ofswitch.py @@ -135,10 +135,9 @@ class OpenFlowSwitchMixin(object): return flows def cleanup_flows(self): - cookies = set([f.cookie for f in self.dump_flows()]) + cookies = set([f.cookie for f in self.dump_flows()]) - \ + self.reserved_cookies for c in cookies: - if c == self.agent_uuid_stamp: - continue LOG.warn(_LW("Deleting flow with cookie 0x%(cookie)x") % { 'cookie': c}) self.delete_flows(cookie=c, cookie_mask=((1 << 64) - 1)) @@ -182,7 +181,7 @@ class OpenFlowSwitchMixin(object): match = self._match(ofp, ofpp, match, **match_kwargs) msg = ofpp.OFPFlowMod(dp, table_id=table_id, - cookie=self.agent_uuid_stamp, + cookie=self.default_cookie, match=match, priority=priority, instructions=instructions) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge.py index 1c4f8a894c9..26cfb3e5d0a 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge.py @@ -21,6 +21,8 @@ from neutron._i18n import _LI from neutron.agent.common import ovs_lib from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts +from neutron.plugins.ml2.drivers.openvswitch.agent.openflow \ + import br_cookie from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \ import ofswitch @@ -28,7 +30,8 @@ from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \ LOG = logging.getLogger(__name__) -class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin, ovs_lib.OVSBridge): +class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin, + br_cookie.OVSBridgeCookieMixin, ovs_lib.OVSBridge): """Common code for bridges used by OVS agent""" _cached_dpid = None diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_tun.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_tun.py index b7625760564..d3e6534e8c3 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_tun.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/br_tun.py @@ -107,7 +107,7 @@ class OVSTunnelBridge(ovs_bridge.OVSAgentBridge, "load:0->NXM_OF_VLAN_TCI[]," "load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[]," "output:NXM_OF_IN_PORT[]" % - {'cookie': self.agent_uuid_stamp, + {'cookie': self.default_cookie, 'table': constants.UCAST_TO_TUN}) # Once remote mac addresses are learnt, output packet to patch_int deferred_br.add_flow(table=constants.LEARN_FROM_TUN, diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ofswitch.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ofswitch.py index de523664ed3..9f4654820ff 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ofswitch.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ofswitch.py @@ -85,8 +85,9 @@ class OpenFlowSwitchMixin(object): super(OpenFlowSwitchMixin, self).remove_all_flows() def _filter_flows(self, flows): - LOG.debug("Agent uuid stamp used to filter flows: %s", - self.agent_uuid_stamp) + cookie_list = self.reserved_cookies + LOG.debug("Bridge cookies used to filter flows: %s", + cookie_list) cookie_re = re.compile('cookie=(0x[A-Fa-f0-9]*)') table_re = re.compile('table=([0-9]*)') for flow in flows: @@ -94,7 +95,7 @@ class OpenFlowSwitchMixin(object): if not fl_cookie: continue fl_cookie = fl_cookie.group(1) - if int(fl_cookie, 16) != self.agent_uuid_stamp: + if int(fl_cookie, 16) not in cookie_list: fl_table = table_re.search(flow) if not fl_table: continue diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ovs_bridge.py b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ovs_bridge.py index 428d8a71a5c..d86a39230ca 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ovs_bridge.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/ovs_bridge.py @@ -18,11 +18,14 @@ from neutron.agent.common import ovs_lib from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \ as ovs_consts +from neutron.plugins.ml2.drivers.openvswitch.agent.openflow \ + import br_cookie from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \ import ofswitch -class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin, ovs_lib.OVSBridge): +class OVSAgentBridge(ofswitch.OpenFlowSwitchMixin, + br_cookie.OVSBridgeCookieMixin, ovs_lib.OVSBridge): """Common code for bridges used by OVS agent""" def setup_controllers(self, conf): diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_agent_extension_api.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_agent_extension_api.py new file mode 100644 index 00000000000..5f3903cfa65 --- /dev/null +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_agent_extension_api.py @@ -0,0 +1,100 @@ +# Copyright 2016 Intel Corporation. +# 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. + +from neutron.agent.common import ovs_lib + + +class OVSCookieBridge(object): + '''Passthrough bridge adding cookies before calling the underlying bridge + + This class creates a bridge that will pass all calls to its underlying + bridge, except (add/mod/del/dump)_flow calls for which a cookie (reserved + at init from the underlying bridge) will be added before calling the + underlying bridge. + ''' + + def __init__(self, bridge): + """:param bridge: underlying bridge + :type bridge: OVSBridge + """ + self.bridge = bridge + self._cookie = self.bridge.request_cookie() + + @property + def default_cookie(self): + return self._cookie + + def do_action_flows(self, action, kwargs_list): + # NOTE(tmorin): the OVSBridge code is excluding the 'del' + # action from this step where a cookie + # is added, but I think we need to keep it so that + # an extension does not delete flows of another + # extension + for kw in kwargs_list: + kw.setdefault('cookie', self._cookie) + + if action is 'mod' or action is 'del': + kw['cookie'] = ovs_lib.check_cookie_mask(str(kw['cookie'])) + + self.bridge.do_action_flows(action, kwargs_list) + + 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 __getattr__(self, name): + # for all other methods this class is a passthrough + return getattr(self.bridge, name) + + def deferred(self, **kwargs): + # NOTE(tmorin): we can't passthrough for deferred() or else the + # resulting DeferredOVSBridge apply_flows method would call + # the (non-cookie-filtered) do_action_flow of the underlying bridge + return ovs_lib.DeferredOVSBridge(self, **kwargs) + + +class OVSAgentExtensionAPI(object): + '''Implements the Agent API for Open vSwitch agent. + + Extensions can gain access to this API by overriding the consume_api + method which has been added to the AgentCoreResourceExtension class. + ''' + + def __init__(self, int_br, tun_br): + super(OVSAgentExtensionAPI, self).__init__() + self.br_int = int_br + self.br_tun = tun_br + + def request_int_br(self): + """Allows extensions to request an integration bridge to use for + extension specific flows. + """ + return OVSCookieBridge(self.br_int) + + def request_tun_br(self): + """Allows extensions to request a tunnel bridge to use for + extension specific flows. + + If tunneling is not enabled, this method will return None. + """ + if not self.br_tun: + return None + + return OVSCookieBridge(self.br_tun) diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index 6e0289a74a3..13b5ced2621 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -18,7 +18,6 @@ import functools import signal import sys import time -import uuid import netaddr from oslo_config import cfg @@ -50,6 +49,8 @@ from neutron.plugins.common import utils as p_utils from neutron.plugins.ml2.drivers.l2pop.rpc_manager import l2population_rpc from neutron.plugins.ml2.drivers.openvswitch.agent.common \ import constants +from neutron.plugins.ml2.drivers.openvswitch.agent \ + import ovs_agent_extension_api as ovs_ext_api from neutron.plugins.ml2.drivers.openvswitch.agent \ import ovs_dvr_neutron_agent @@ -62,7 +63,6 @@ cfg.CONF.import_group('OVS', 'neutron.plugins.ml2.drivers.openvswitch.agent.' # A placeholder for dead vlans. DEAD_VLAN_TAG = p_const.MAX_VLAN_TAG + 1 -UINT64_BITMASK = (1 << 64) - 1 class _mac_mydialect(netaddr.mac_unix): @@ -178,8 +178,6 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, # Keep track of int_br's device count for use by _report_state() self.int_br_device_count = 0 - self.agent_uuid_stamp = uuid.uuid4().int & UINT64_BITMASK - self.int_br = self.br_int_cls(ovs_conf.integration_bridge) self.setup_integration_br() # Stores port update notifications for processing in main rpc loop @@ -191,7 +189,6 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, # keeps association between ports and ofports to detect ofport change self.vifname_to_ofport_map = {} self.setup_rpc() - self.init_extension_manager(self.connection) self.bridge_mappings = self._parse_bridge_mappings( ovs_conf.bridge_mappings) self.setup_physical_bridges(self.bridge_mappings) @@ -217,6 +214,8 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, # here inside the call to setup_tunnel_br() self.setup_tunnel_br(ovs_conf.tunnel_bridge) + self.init_extension_manager(self.connection) + self.dvr_agent = ovs_dvr_neutron_agent.OVSDVRNeutronAgent( self.context, self.dvr_plugin_rpc, @@ -384,8 +383,11 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, ext_manager.register_opts(self.conf) self.ext_manager = ( ext_manager.AgentExtensionsManager(self.conf)) + self.agent_api = ovs_ext_api.OVSAgentExtensionAPI(self.int_br, + self.tun_br) self.ext_manager.initialize( - connection, constants.EXTENSION_DRIVER_TYPE) + connection, constants.EXTENSION_DRIVER_TYPE, + self.agent_api) def get_net_uuid(self, vif_id): for network_id, vlan_mapping in six.iteritems(self.local_vlan_map): @@ -969,7 +971,6 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, '''Setup the integration bridge. ''' - self.int_br.set_agent_uuid_stamp(self.agent_uuid_stamp) # Ensure the integration bridge is created. # ovs_lib.OVSBridge.create() will run # ovs-vsctl -- --may-exist add-br BRIDGE_NAME @@ -1019,7 +1020,6 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, ''' if not self.tun_br: self.tun_br = self.br_tun_cls(tun_br_name) - self.tun_br.set_agent_uuid_stamp(self.agent_uuid_stamp) # tun_br.create() won't recreate bridge if it exists, but will handle # cases where something like datapath_type has changed diff --git a/neutron/tests/unit/agent/common/test_ovs_lib.py b/neutron/tests/unit/agent/common/test_ovs_lib.py index 370b799c151..ec4189d0379 100644 --- a/neutron/tests/unit/agent/common/test_ovs_lib.py +++ b/neutron/tests/unit/agent/common/test_ovs_lib.py @@ -891,15 +891,20 @@ class TestDeferredOVSBridge(base.BaseTestCase): with ovs_lib.DeferredOVSBridge(self.br) as deferred_br: self.assertRaises(AttributeError, getattr, deferred_br, 'failure') + def test_default_cookie(self): + self.br = ovs_lib.OVSBridge("br-tun") + uuid_stamp1 = self.br.default_cookie + self.assertEqual(uuid_stamp1, self.br.default_cookie) + def test_cookie_passed_to_addmod(self): self.br = ovs_lib.OVSBridge("br-tun") - self.br.set_agent_uuid_stamp(1234) + stamp = str(self.br.default_cookie) expected_calls = [ mock.call('add-flows', ['-'], 'hard_timeout=0,idle_timeout=0,priority=1,' - 'cookie=1234,actions=drop'), + 'cookie=' + stamp + ',actions=drop'), mock.call('mod-flows', ['-'], - 'cookie=1234,actions=drop') + 'cookie=' + stamp + ',actions=drop') ] with mock.patch.object(self.br, 'run_ofctl') as f: with ovs_lib.DeferredOVSBridge(self.br) as deferred_br: diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge_test_base.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge_test_base.py index d879ba3b9b6..9586c724cda 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge_test_base.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/ovs_bridge_test_base.py @@ -34,6 +34,7 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase): def setup_bridge_mock(self, name, cls): self.br = cls(name) + self.stamp = self.br.default_cookie self.dp = mock.Mock() self.ofp = importutils.import_module(self._OFP_MODULE) self.ofpp = importutils.import_module(self._OFPP_MODULE) @@ -59,7 +60,7 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase): expected = [ call._send_msg( ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(in_port=in_port), priority=2, @@ -77,7 +78,7 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase): expected = [ call._send_msg( ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=dest_table_id), ], @@ -95,7 +96,7 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase): expected = [ call._send_msg( ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(in_port=in_port), priority=priority, @@ -111,7 +112,7 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase): expected = [ call._send_msg( ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0) @@ -139,7 +140,7 @@ class OVSDVRProcessTestMixin(object): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch( eth_type=self.ether_types.ETH_TYPE_ARP, @@ -173,7 +174,7 @@ class OVSDVRProcessTestMixin(object): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch( eth_src=gateway_mac, @@ -213,7 +214,7 @@ class OVSDVRProcessTestMixin(object): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch( eth_dst=vif_mac, @@ -221,7 +222,7 @@ class OVSDVRProcessTestMixin(object): priority=2, table_id=self.dvr_process_table_id)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField(eth_src=dvr_mac_address), diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py index 17a865a5566..32086ff2751 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_int.py @@ -27,13 +27,14 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): def setUp(self): super(OVSIntegrationBridgeTest, self).setUp() self.setup_bridge_mock('br-int', self.br_int_cls) + self.stamp = self.br.default_cookie def test_setup_default_table(self): self.br.setup_default_table() (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions( ofp.OFPIT_APPLY_ACTIONS, [ @@ -44,13 +45,13 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): priority=0, table_id=0)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=23)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, @@ -67,7 +68,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField( @@ -92,7 +93,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPushVlan(), @@ -149,7 +150,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPopVlan(), @@ -195,7 +196,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPopVlan(), @@ -234,7 +235,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=2), ], @@ -262,7 +263,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=1), ], @@ -290,7 +291,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0), @@ -306,7 +307,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): priority=2, table_id=24)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0), @@ -322,7 +323,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): priority=2, table_id=24)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=24), ], @@ -344,7 +345,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0), @@ -358,7 +359,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): priority=2, table_id=24)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0), @@ -372,7 +373,7 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase): priority=2, table_id=24)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=24), ], diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_phys.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_phys.py index a478f9a8b61..2b33862ef80 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_phys.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_phys.py @@ -33,6 +33,7 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, def setUp(self): super(OVSPhysicalBridgeTest, self).setUp() self.setup_bridge_mock('br-phys', self.br_phys_cls) + self.stamp = self.br.default_cookie def test_setup_default_table(self): self.br.setup_default_table() @@ -40,7 +41,7 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, expected = [ call.delete_flows(), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(ofp.OFPP_NORMAL, 0), @@ -63,7 +64,7 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField( @@ -90,7 +91,7 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPopVlan(), @@ -125,7 +126,7 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(port, 0), diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_tun.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_tun.py index 91b0af60895..3d1e5581501 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_tun.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/native/test_br_tun.py @@ -33,6 +33,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, def setUp(self): super(OVSTunnelBridgeTest, self).setUp() self.setup_bridge_mock('br-tun', self.br_tun_cls) + self.stamp = self.br.default_cookie def test_setup_default_table(self): patch_int_ofport = 5555 @@ -42,50 +43,50 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=2)], match=ofpp.OFPMatch(in_port=patch_int_ofport), priority=1, table_id=0)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=0)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=20)], match=ofpp.OFPMatch( eth_dst=('00:00:00:00:00:00', '01:00:00:00:00:00')), priority=0, table_id=2)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=22)], match=ofpp.OFPMatch( eth_dst=('01:00:00:00:00:00', '01:00:00:00:00:00')), priority=0, table_id=2)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=3)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=4)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=6)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.NXActionLearn( - cookie=0, + cookie=self.stamp, hard_timeout=300, priority=1, specs=[ @@ -118,13 +119,13 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, priority=1, table_id=10)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=22)], match=ofpp.OFPMatch(), priority=0, table_id=20)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, @@ -140,17 +141,17 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=2)], match=ofpp.OFPMatch(in_port=patch_int_ofport), priority=1, table_id=0)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=0)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=21)], match=ofpp.OFPMatch( eth_dst='ff:ff:ff:ff:ff:ff', @@ -158,40 +159,40 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, priority=1, table_id=2)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=20)], match=ofpp.OFPMatch( eth_dst=('00:00:00:00:00:00', '01:00:00:00:00:00')), priority=0, table_id=2)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=22)], match=ofpp.OFPMatch( eth_dst=('01:00:00:00:00:00', '01:00:00:00:00:00')), priority=0, table_id=2)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=3)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=4)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, table_id=6)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.NXActionLearn( - cookie=0, + cookie=self.stamp, hard_timeout=300, priority=1, specs=[ @@ -224,19 +225,19 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, priority=1, table_id=10)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=22)], match=ofpp.OFPMatch(), priority=0, table_id=20)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ofpp.OFPInstructionGotoTable(table_id=22)], match=ofpp.OFPMatch(), priority=0, table_id=21)), call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[], match=ofpp.OFPMatch(), priority=0, @@ -255,7 +256,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPushVlan(), @@ -293,7 +294,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPopVlan(), @@ -328,7 +329,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionPopVlan(), @@ -374,7 +375,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionSetField(arp_op=self.arp.ARP_REPLY), @@ -436,7 +437,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionGotoTable(table_id=4), ], @@ -462,7 +463,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, (dp, ofp, ofpp) = self._get_dp() expected = [ call._send_msg(ofpp.OFPFlowMod(dp, - cookie=0, + cookie=self.stamp, instructions=[ ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, [ ofpp.OFPActionOutput(port, 0), diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_tun.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_tun.py index 6c77d311519..b19a225e93e 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_tun.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/ovs_ofctl/test_br_tun.py @@ -34,6 +34,7 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, def setUp(self): super(OVSTunnelBridgeTest, self).setUp() self.setup_bridge_mock('br-tun', self.br_tun_cls) + self.stamp = self.br.default_cookie def test_setup_default_table(self): patch_int_ofport = 5555 @@ -55,8 +56,9 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, {'priority': 0, 'table': 4, 'actions': 'drop'}, {'priority': 0, 'table': 6, 'actions': 'drop'}, {'priority': 1, 'table': 10, - 'actions': 'learn(cookie=0,table=20,priority=1,' - 'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],' + 'actions': 'learn(cookie=' + str(self.stamp) + + ',table=20,priority=1,hard_timeout=300,' + 'NXM_OF_VLAN_TCI[0..11],' 'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],' 'load:0->NXM_OF_VLAN_TCI[],' 'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],' @@ -90,8 +92,9 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase, {'priority': 0, 'table': 4, 'actions': 'drop'}, {'priority': 0, 'table': 6, 'actions': 'drop'}, {'priority': 1, 'table': 10, - 'actions': 'learn(cookie=0,table=20,priority=1,' - 'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],' + 'actions': 'learn(cookie=' + str(self.stamp) + + ',table=20,priority=1,hard_timeout=300,' + 'NXM_OF_VLAN_TCI[0..11],' 'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],' 'load:0->NXM_OF_VLAN_TCI[],' 'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],' diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/test_br_cookie.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/test_br_cookie.py new file mode 100644 index 00000000000..0f9d6799e3f --- /dev/null +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/openflow/test_br_cookie.py @@ -0,0 +1,60 @@ +# Copyright 2016 Intel Corporation. +# 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. + +from neutron.agent.common import ovs_lib +from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \ + import ovs_bridge +from neutron.tests import base + + +class TestBRCookieOpenflow(base.BaseTestCase): + + def setUp(self): + super(TestBRCookieOpenflow, self).setUp() + self.br = ovs_bridge.OVSAgentBridge('br-int') + + def test_reserved_cookies(self): + def_cookie = self.br.default_cookie + self.assertIn(def_cookie, self.br.reserved_cookies) + + def test_request_cookie(self): + default_cookie = self.br.default_cookie + requested_cookie = self.br.request_cookie() + self.assertEqual(default_cookie, self.br.default_cookie) + self.assertIn(default_cookie, self.br.reserved_cookies) + self.assertIn(requested_cookie, self.br.reserved_cookies) + + def test_set_agent_uuid_stamp(self): + self.br = ovs_bridge.OVSAgentBridge('br-int') + def_cookie = self.br.default_cookie + new_cookie = ovs_lib.generate_random_cookie() + + self.br.set_agent_uuid_stamp(new_cookie) + + self.assertEqual(new_cookie, self.br.default_cookie) + self.assertIn(new_cookie, self.br.reserved_cookies) + self.assertNotIn(def_cookie, self.br.reserved_cookies) + + def test_set_agent_uuid_stamp_with_reserved_cookie(self): + self.br = ovs_bridge.OVSAgentBridge('br-int') + def_cookie = self.br.default_cookie + new_cookie = self.br.request_cookie() + + self.br.set_agent_uuid_stamp(new_cookie) + + self.assertEqual(new_cookie, self.br.default_cookie) + self.assertIn(new_cookie, self.br.reserved_cookies) + self.assertNotIn(def_cookie, self.br.reserved_cookies) + self.assertEqual(set([new_cookie]), self.br.reserved_cookies) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_agent_extension_api.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_agent_extension_api.py new file mode 100644 index 00000000000..62c8b7f6c12 --- /dev/null +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_agent_extension_api.py @@ -0,0 +1,181 @@ +# Copyright 2012 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 mock + +from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.ovs_ofctl \ + import ovs_bridge +from neutron.plugins.ml2.drivers.openvswitch.agent \ + import ovs_agent_extension_api as ovs_ext_agt + +from neutron.tests import base + + +class TestOVSAgentExtensionAPI(base.BaseTestCase): + + def setUp(self): + super(base.BaseTestCase, self).setUp() + self.br_int = ovs_bridge.OVSAgentBridge("br-int") + self.br_tun = ovs_bridge.OVSAgentBridge("br-tun") + + def _test_bridge(self, orig_bridge, new_bridge): + self.assertIsNotNone(new_bridge) + self.assertEqual(orig_bridge.br_name, new_bridge.br_name) + self.assertIn(new_bridge.default_cookie, + orig_bridge.reserved_cookies) + self.assertNotEqual(orig_bridge.default_cookie, + new_bridge.default_cookie) + + def test_request_int_br(self): + agent_extension_api = ovs_ext_agt.OVSAgentExtensionAPI(self.br_int, + self.br_tun) + new_int_br = agent_extension_api.request_int_br() + self._test_bridge(self.br_int, new_int_br) + + def test_request_tun_br(self): + agent_extension_api = ovs_ext_agt.OVSAgentExtensionAPI(self.br_int, + self.br_tun) + new_tun_br = agent_extension_api.request_tun_br() + self._test_bridge(self.br_tun, new_tun_br) + + def test_request_tun_br_tunneling_disabled(self): + agent_extension_api = ovs_ext_agt.OVSAgentExtensionAPI(self.br_int, + None) + self.assertIsNone(agent_extension_api.request_tun_br()) + + +class TestOVSCookieBridge(base.DietTestCase): + + def setUp(self): + super(TestOVSCookieBridge, self).setUp() + self.bridge = ovs_bridge.OVSAgentBridge("br-foo") + self.bridge.do_action_flows = mock.Mock() + self.tested_bridge = ovs_ext_agt.OVSCookieBridge(self.bridge) + + def test_reserved(self): + self.assertIn(self.tested_bridge.default_cookie, + self.bridge.reserved_cookies) + + def test_add_flow_without_cookie(self): + self.tested_bridge.add_flow(in_port=1, actions="output:2") + self.bridge.do_action_flows.assert_called_once_with( + 'add', + [{"in_port": 1, + "actions": "output:2", + "cookie": self.tested_bridge.default_cookie}] + ) + + def test_mod_flow_without_cookie(self): + self.tested_bridge.mod_flow(in_port=1, actions="output:2") + self.bridge.do_action_flows.assert_called_once_with( + 'mod', + [{"in_port": 1, + "actions": "output:2", + "cookie": str(self.tested_bridge.default_cookie) + '/-1'}] + ) + + def test_del_flows_without_cookie(self): + self.tested_bridge.delete_flows(in_port=1) + self.bridge.do_action_flows.assert_called_once_with( + 'del', + [{"in_port": 1, + "cookie": str(self.tested_bridge.default_cookie) + '/-1'}] + ) + + def test_add_flow_with_cookie(self): + self.tested_bridge.add_flow(cookie=1234, + in_port=1, actions="output:2") + self.bridge.do_action_flows.assert_called_once_with( + 'add', + [{"in_port": 1, + "actions": "output:2", + "cookie": 1234}] + ) + + def test_mod_flow_with_cookie(self): + self.tested_bridge.mod_flow(cookie='1234', + in_port=1, actions="output:2") + self.bridge.do_action_flows.assert_called_once_with( + 'mod', + [{"in_port": 1, + "actions": "output:2", + "cookie": str(1234) + '/-1'}] + ) + + def test_del_flows_with_cookie(self): + self.tested_bridge.delete_flows(cookie=1234, in_port=1) + self.bridge.do_action_flows.assert_called_once_with( + 'del', + [{"in_port": 1, + "cookie": str(1234) + '/-1'}] + ) + + def test_mod_flow_with_mask(self): + self.tested_bridge.mod_flow(cookie='1234/3', + in_port=1, actions="output:2") + self.bridge.do_action_flows.assert_called_once_with( + 'mod', + [{"in_port": 1, + "actions": "output:2", + "cookie": str(1234) + '/3'}] + ) + + def test_del_flows_with_mask(self): + self.tested_bridge.delete_flows(cookie='1234/7', in_port=1) + self.bridge.do_action_flows.assert_called_once_with( + 'del', + [{"in_port": 1, + "cookie": str(1234) + '/7'}] + ) + + +class TestOVSDeferredCookieBridge(base.DietTestCase): + + def setUp(self): + super(TestOVSDeferredCookieBridge, self).setUp() + self.bridge = ovs_bridge.OVSAgentBridge("br-foo") + self.bridge.do_action_flows = mock.Mock() + self.cookie_bridge = ovs_ext_agt.OVSCookieBridge(self.bridge) + self.tested_bridge = self.cookie_bridge.deferred() + + def test_add_flow(self): + self.tested_bridge.add_flow(in_port=1, actions="output:2") + self.tested_bridge.apply_flows() + self.bridge.do_action_flows.assert_called_once_with( + 'add', + [{"in_port": 1, + "actions": "output:2", + "cookie": self.cookie_bridge.default_cookie}] + ) + + def test_mod_flow(self): + self.tested_bridge.mod_flow(in_port=1, actions="output:2") + self.tested_bridge.apply_flows() + self.bridge.do_action_flows.assert_called_once_with( + 'mod', + [{"in_port": 1, + "actions": "output:2", + "cookie": str(self.cookie_bridge.default_cookie) + '/-1'}] + ) + + def test_del_flows(self): + self.tested_bridge.delete_flows(in_port=1) + self.tested_bridge.apply_flows() + self.bridge.do_action_flows.assert_called_once_with( + 'del', + [{"in_port": 1, + "cookie": str(self.cookie_bridge.default_cookie) + '/-1'}] + ) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index 50fe9ea6685..a94dd5a8f00 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -1850,12 +1850,11 @@ class TestOvsNeutronAgent(object): class TestOvsNeutronAgentOFCtl(TestOvsNeutronAgent, ovs_test_base.OVSOFCtlTestBase): def test_cleanup_stale_flows(self): - with mock.patch.object(self.agent.int_br, 'agent_uuid_stamp', - new=1234),\ - mock.patch.object(self.agent.int_br, + with mock.patch.object(self.agent.int_br, 'dump_flows_all_tables') as dump_flows,\ mock.patch.object(self.agent.int_br, 'delete_flows') as del_flow: + self.agent.int_br.set_agent_uuid_stamp(1234) dump_flows.return_value = [ 'cookie=0x4d2, duration=50.156s, table=0,actions=drop', 'cookie=0x4321, duration=54.143s, table=2, priority=0', @@ -1875,12 +1874,11 @@ class TestOvsNeutronAgentRyu(TestOvsNeutronAgent, ovs_test_base.OVSRyuTestBase): def test_cleanup_stale_flows(self): uint64_max = (1 << 64) - 1 - with mock.patch.object(self.agent.int_br, 'agent_uuid_stamp', - new=1234),\ - mock.patch.object(self.agent.int_br, + with mock.patch.object(self.agent.int_br, 'dump_flows') as dump_flows,\ mock.patch.object(self.agent.int_br, 'delete_flows') as del_flow: + self.agent.int_br.set_agent_uuid_stamp(1234) dump_flows.return_value = [ # mock ryu.ofproto.ofproto_v1_3_parser.OFPFlowStats mock.Mock(cookie=1234, table_id=0), diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py index 4065902c8f8..1c344020b9c 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py @@ -179,7 +179,6 @@ class TunnelTest(object): self.mock_int_bridge = self.ovs_bridges[self.INT_BRIDGE] self.mock_int_bridge_expected = [ - mock.call.set_agent_uuid_stamp(mock.ANY), mock.call.create(), mock.call.set_secure_mode(), mock.call.setup_controllers(mock.ANY), @@ -214,7 +213,6 @@ class TunnelTest(object): ] self.mock_tun_bridge_expected = [ - mock.call.set_agent_uuid_stamp(mock.ANY), mock.call.create(secure_mode=True), mock.call.setup_controllers(mock.ANY), mock.call.port_exists('patch-int'), @@ -627,7 +625,6 @@ class TunnelTestUseVethInterco(TunnelTest): ] self.mock_int_bridge_expected = [ - mock.call.set_agent_uuid_stamp(mock.ANY), mock.call.create(), mock.call.set_secure_mode(), mock.call.setup_controllers(mock.ANY), @@ -655,7 +652,6 @@ class TunnelTestUseVethInterco(TunnelTest): ] self.mock_tun_bridge_expected = [ - mock.call.set_agent_uuid_stamp(mock.ANY), mock.call.create(secure_mode=True), mock.call.setup_controllers(mock.ANY), mock.call.port_exists('patch-int'),