Added agent specific API support to L2 extensions

- Introduces an API to allow l2-agents to access resources within
  the Open vSwitch Agent, specifically the integration and tunnel bridges.
- adds consume_api method to the AgentCoreResourceExtension class.
- modifies the AgentExtensionManager class to accept the AgentExtensionAPI
  class as an optional argument.
- adds the OVSAgentExtensionAPI class.
- modifies ovs_lib and ofswitch to include a list of uuid stamps
  to exempt from flow deletion.
- adds the OVSBridgeCookieMixin class that manages the distribution of
  cookies and maintains the list of reserved cookies.
- modifies OVSNeutronAgent to initialize OVSAgentExtensionAPI and pass
  into the AgentExtensionManager.

Partial-Bug: #1517903
Co-Authored-By: Nate Johnston <nate_johnston@cable.comcast.com>
Co-Authored-By: Thomas Morin <thomas.morin@orange.com>
Implements: blueprint l2-api-extensions

Change-Id: I7cb61f30689dff2d7895d444060dedc1532a63ec
This commit is contained in:
David Shaughnessy 2016-01-13 13:26:57 +00:00
parent 3fb153b15b
commit ea8d60f561
22 changed files with 537 additions and 98 deletions

View File

@ -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

View File

@ -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
"""

View File

@ -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):

View File

@ -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)

View File

@ -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),

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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),

View File

@ -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),
],

View File

@ -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),

View File

@ -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),

View File

@ -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[],'

View File

@ -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)

View File

@ -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'}]
)

View File

@ -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),

View File

@ -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'),