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: I7cb61f30689dff2d7895d444060dedc1532a63ecchanges/91/267591/30
parent
3fb153b15b
commit
ea8d60f561
|
@ -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
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
],
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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[],'
|
||||
|
|
|
@ -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)
|
|
@ -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):
|
||||