of_interface: Implement bundled() method
Change-Id: Ie0de8309cdbed02fa88887e7fe25e8b3a2c0afe1 Related-blueprint: ovs-ofctl-to-python
This commit is contained in:
parent
9f10a9304f
commit
2180bd902c
|
@ -14,8 +14,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import functools
|
||||
import random
|
||||
|
||||
import eventlet
|
||||
import netaddr
|
||||
from neutron_lib import exceptions
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
@ -31,9 +35,14 @@ from neutron.agent.common import ovs_lib
|
|||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
BUNDLE_ID_WIDTH = 1 << 32
|
||||
COOKIE_DEFAULT = object()
|
||||
|
||||
|
||||
class ActiveBundleRunning(exceptions.NeutronException):
|
||||
message = _("Another active bundle 0x%(bundle_id)x is running")
|
||||
|
||||
|
||||
class OpenFlowSwitchMixin(object):
|
||||
"""Mixin to provide common convenient routines for an openflow switch.
|
||||
|
||||
|
@ -50,6 +59,7 @@ class OpenFlowSwitchMixin(object):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._app = kwargs.pop('ryu_app')
|
||||
self.active_bundles = set()
|
||||
super(OpenFlowSwitchMixin, self).__init__(*args, **kwargs)
|
||||
|
||||
def _get_dp_by_dpid(self, dpid_int):
|
||||
|
@ -70,9 +80,14 @@ class OpenFlowSwitchMixin(object):
|
|||
eventlet.sleep(1)
|
||||
return dp
|
||||
|
||||
def _send_msg(self, msg, reply_cls=None, reply_multi=False):
|
||||
def _send_msg(self, msg, reply_cls=None, reply_multi=False,
|
||||
active_bundle=None):
|
||||
timeout_sec = cfg.CONF.OVS.of_request_timeout
|
||||
timeout = eventlet.Timeout(seconds=timeout_sec)
|
||||
if active_bundle is not None:
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
msg = ofpp.ONFBundleAddMsg(dp, active_bundle['id'],
|
||||
active_bundle['bundle_flags'], msg, [])
|
||||
try:
|
||||
result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi)
|
||||
except ryu_exc.RyuException as e:
|
||||
|
@ -107,7 +122,7 @@ class OpenFlowSwitchMixin(object):
|
|||
|
||||
def uninstall_flows(self, table_id=None, strict=False, priority=0,
|
||||
cookie=COOKIE_DEFAULT, cookie_mask=0,
|
||||
match=None, **match_kwargs):
|
||||
match=None, active_bundle=None, **match_kwargs):
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
if table_id is None:
|
||||
table_id = ofp.OFPTT_ALL
|
||||
|
@ -135,7 +150,7 @@ class OpenFlowSwitchMixin(object):
|
|||
priority=priority,
|
||||
out_group=ofp.OFPG_ANY,
|
||||
out_port=ofp.OFPP_ANY)
|
||||
self._send_msg(msg)
|
||||
self._send_msg(msg, active_bundle=active_bundle)
|
||||
|
||||
def dump_flows(self, table_id=None):
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
|
@ -160,8 +175,9 @@ class OpenFlowSwitchMixin(object):
|
|||
{'cookie': c})
|
||||
self.uninstall_flows(cookie=c, cookie_mask=ovs_lib.UINT64_BITMASK)
|
||||
|
||||
def install_goto_next(self, table_id):
|
||||
self.install_goto(table_id=table_id, dest_table_id=table_id + 1)
|
||||
def install_goto_next(self, table_id, active_bundle=None):
|
||||
self.install_goto(table_id=table_id, dest_table_id=table_id + 1,
|
||||
active_bundle=active_bundle)
|
||||
|
||||
def install_output(self, port, table_id=0, priority=0,
|
||||
match=None, **match_kwargs):
|
||||
|
@ -194,7 +210,7 @@ class OpenFlowSwitchMixin(object):
|
|||
|
||||
def install_instructions(self, instructions,
|
||||
table_id=0, priority=0,
|
||||
match=None, **match_kwargs):
|
||||
match=None, active_bundle=None, **match_kwargs):
|
||||
(dp, ofp, ofpp) = self._get_dp()
|
||||
match = self._match(ofp, ofpp, match, **match_kwargs)
|
||||
if isinstance(instructions, six.string_types):
|
||||
|
@ -211,7 +227,7 @@ class OpenFlowSwitchMixin(object):
|
|||
match=match,
|
||||
priority=priority,
|
||||
instructions=instructions)
|
||||
self._send_msg(msg)
|
||||
self._send_msg(msg, active_bundle=active_bundle)
|
||||
|
||||
def install_apply_actions(self, actions,
|
||||
table_id=0, priority=0,
|
||||
|
@ -225,3 +241,81 @@ class OpenFlowSwitchMixin(object):
|
|||
match=match,
|
||||
instructions=instructions,
|
||||
**match_kwargs)
|
||||
|
||||
def bundled(self, atomic=False, ordered=False):
|
||||
return BundledOpenFlowBridge(self, atomic, ordered)
|
||||
|
||||
|
||||
class BundledOpenFlowBridge(object):
|
||||
def __init__(self, br, atomic, ordered):
|
||||
self.br = br
|
||||
self.active_bundle = None
|
||||
self.bundle_flags = 0
|
||||
if not atomic and not ordered:
|
||||
return
|
||||
(dp, ofp, ofpp) = self.br._get_dp()
|
||||
if atomic:
|
||||
self.bundle_flags |= ofp.ONF_BF_ATOMIC
|
||||
if ordered:
|
||||
self.bundle_flags |= ofp.ONF_BF_ORDERED
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('install') or name.startswith('uninstall'):
|
||||
under = getattr(self.br, name)
|
||||
if self.active_bundle is None:
|
||||
return under
|
||||
return functools.partial(under, active_bundle=dict(
|
||||
id=self.active_bundle, bundle_flags=self.bundle_flags))
|
||||
raise AttributeError("Only install_* or uninstall_* methods "
|
||||
"can be used")
|
||||
|
||||
def __enter__(self):
|
||||
if self.active_bundle is not None:
|
||||
raise ActiveBundleRunning(bundle_id=self.active_bundle)
|
||||
while True:
|
||||
self.active_bundle = random.randrange(BUNDLE_ID_WIDTH)
|
||||
if self.active_bundle not in self.br.active_bundles:
|
||||
self.br.active_bundles.add(self.active_bundle)
|
||||
break
|
||||
try:
|
||||
(dp, ofp, ofpp) = self.br._get_dp()
|
||||
msg = ofpp.ONFBundleCtrlMsg(dp, self.active_bundle,
|
||||
ofp.ONF_BCT_OPEN_REQUEST,
|
||||
self.bundle_flags, [])
|
||||
reply = self.br._send_msg(msg, reply_cls=ofpp.ONFBundleCtrlMsg)
|
||||
if reply.type != ofp.ONF_BCT_OPEN_REPLY:
|
||||
raise RuntimeError(
|
||||
"Unexpected reply type %d != ONF_BCT_OPEN_REPLY" %
|
||||
reply.type)
|
||||
return self
|
||||
except Exception:
|
||||
self.br.active_bundles.remove(self.active_bundle)
|
||||
self.active_bundle = None
|
||||
raise
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
(dp, ofp, ofpp) = self.br._get_dp()
|
||||
if type is None:
|
||||
ctrl_type = ofp.ONF_BCT_COMMIT_REQUEST
|
||||
expected_reply = ofp.ONF_BCT_COMMIT_REPLY
|
||||
else:
|
||||
ctrl_type = ofp.ONF_BCT_DISCARD_REQUEST
|
||||
expected_reply = ofp.ONF_BCT_DISCARD_REPLY
|
||||
LOG.warning(
|
||||
"Discarding bundle with ID 0x%(id)x due to an exception",
|
||||
{'id': self.active_bundle})
|
||||
|
||||
try:
|
||||
msg = ofpp.ONFBundleCtrlMsg(dp, self.active_bundle,
|
||||
ctrl_type,
|
||||
self.bundle_flags, [])
|
||||
reply = self.br._send_msg(msg, reply_cls=ofpp.ONFBundleCtrlMsg)
|
||||
if reply.type != expected_reply:
|
||||
# The bundle ID may be in a bad state. Let's leave it
|
||||
# in active_bundles so that we will never use it again.
|
||||
raise RuntimeError("Unexpected reply type %d" % reply.type)
|
||||
self.br.active_bundles.remove(self.active_bundle)
|
||||
finally:
|
||||
# It is possible the bundle is kept open, but this must be
|
||||
# cleared or all subsequent __enter__ will fail.
|
||||
self.active_bundle = None
|
||||
|
|
|
@ -466,3 +466,23 @@ class OVSFlowTestCase(OVSAgentTestBase):
|
|||
"icmp_type=8,icmp_code=0,vlan_tci=%(vlan_tci)d"
|
||||
% kwargs)
|
||||
self.assertIn("pop_vlan,", trace["Datapath actions"])
|
||||
|
||||
def test_bundled_install(self):
|
||||
if 'ovs_ofctl' in self.main_module:
|
||||
self.skip("ovs-ofctl of_interface doesn't have bundled()")
|
||||
|
||||
kwargs = {'in_port': 345, 'vlan_tci': 0x1321}
|
||||
dst_p = self.useFixture(
|
||||
net_helpers.OVSPortFixture(self.br_tun, self.namespace)).port
|
||||
dst_ofp = self.br_tun.get_port_ofport(dst_p.name)
|
||||
with self.br_tun.bundled() as br:
|
||||
br.install_instructions("pop_vlan,output:%d" % dst_ofp,
|
||||
priority=10, **kwargs)
|
||||
trace = self._run_trace(self.br_tun.br_name,
|
||||
"in_port=%(in_port)d,dl_src=12:34:56:78:aa:bb,"
|
||||
"dl_dst=24:12:56:78:aa:bb,dl_type=0x0800,"
|
||||
"nw_src=192.168.0.1,nw_dst=192.168.0.2,"
|
||||
"nw_proto=1,nw_tos=0,nw_ttl=128,"
|
||||
"icmp_type=8,icmp_code=0,vlan_tci=%(vlan_tci)d"
|
||||
% kwargs)
|
||||
self.assertIn("pop_vlan,", trace["Datapath actions"])
|
||||
|
|
|
@ -65,7 +65,8 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase):
|
|||
instructions=[],
|
||||
match=ofpp.OFPMatch(in_port=in_port),
|
||||
priority=2,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -85,7 +86,8 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase):
|
|||
],
|
||||
match=ofpp.OFPMatch(in_port=in_port),
|
||||
priority=priority,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -101,7 +103,8 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase):
|
|||
instructions=[],
|
||||
match=ofpp.OFPMatch(in_port=in_port),
|
||||
priority=priority,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -121,7 +124,8 @@ class OVSBridgeTestBase(ovs_test_base.OVSRyuTestBase):
|
|||
],
|
||||
match=ofpp.OFPMatch(in_port=in_port),
|
||||
priority=priority,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -162,7 +166,8 @@ class OVSDVRProcessTestMixin(object):
|
|||
arp_tpa=gateway_ip,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=3,
|
||||
table_id=self.dvr_process_table_id)),
|
||||
table_id=self.dvr_process_table_id),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -198,7 +203,8 @@ class OVSDVRProcessTestMixin(object):
|
|||
ip_proto=self.in_proto.IPPROTO_ICMPV6,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=3,
|
||||
table_id=self.dvr_process_table_id)),
|
||||
table_id=self.dvr_process_table_id),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -235,7 +241,8 @@ class OVSDVRProcessTestMixin(object):
|
|||
eth_dst=vif_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=2,
|
||||
table_id=self.dvr_process_table_id)),
|
||||
table_id=self.dvr_process_table_id),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -249,7 +256,8 @@ class OVSDVRProcessTestMixin(object):
|
|||
eth_src=vif_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=1,
|
||||
table_id=self.dvr_process_table_id)),
|
||||
table_id=self.dvr_process_table_id),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=23)),
|
||||
table_id=23),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -46,7 +47,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -57,13 +59,15 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=3,
|
||||
table_id=60)),
|
||||
table_id=60),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=24)),
|
||||
table_id=24),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -88,7 +92,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=port,
|
||||
vlan_vid=segmentation_id | ofp.OFPVID_PRESENT),
|
||||
priority=3,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -114,7 +119,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=port,
|
||||
vlan_vid=ofp.OFPVID_NONE),
|
||||
priority=3,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -169,7 +175,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_dst=dst_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=1)),
|
||||
table_id=1),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -182,7 +189,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_dst=dst_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=60)),
|
||||
table_id=60),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -237,7 +245,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_dst=dst_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=2)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -250,7 +259,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_dst=dst_mac,
|
||||
vlan_vid=vlan_tag | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=60)),
|
||||
table_id=60),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -295,7 +305,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_src=mac,
|
||||
in_port=port),
|
||||
priority=4,
|
||||
table_id=0))
|
||||
table_id=0),
|
||||
active_bundle=None)
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -323,7 +334,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
eth_src=mac,
|
||||
in_port=port),
|
||||
priority=2,
|
||||
table_id=0))
|
||||
table_id=0),
|
||||
active_bundle=None)
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -355,7 +367,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888,
|
||||
),
|
||||
priority=2,
|
||||
table_id=24)),
|
||||
table_id=24),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -369,7 +382,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888,
|
||||
),
|
||||
priority=2,
|
||||
table_id=24)),
|
||||
table_id=24),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -382,7 +396,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888,
|
||||
),
|
||||
priority=10,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -403,7 +418,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888,
|
||||
),
|
||||
priority=2,
|
||||
table_id=24)),
|
||||
table_id=24),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -415,7 +431,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888
|
||||
),
|
||||
priority=2,
|
||||
table_id=24)),
|
||||
table_id=24),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -426,7 +443,8 @@ class OVSIntegrationBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
in_port=8888,
|
||||
),
|
||||
priority=10,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -79,7 +80,8 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
in_port=port,
|
||||
vlan_vid=lvid | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -105,7 +107,8 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
in_port=port,
|
||||
vlan_vid=lvid | ofp.OFPVID_PRESENT),
|
||||
priority=4,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -137,7 +140,8 @@ class OVSPhysicalBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(eth_src=mac),
|
||||
priority=2,
|
||||
table_id=3)),
|
||||
table_id=3),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
|
|
@ -59,41 +59,48 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=2)],
|
||||
match=ofpp.OFPMatch(in_port=patch_int_ofport),
|
||||
priority=1, table_id=0)),
|
||||
priority=1, table_id=0),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=0)),
|
||||
priority=0, table_id=0),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
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)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
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)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=3)),
|
||||
priority=0, table_id=3),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=4)),
|
||||
priority=0, table_id=4),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=6)),
|
||||
priority=0, table_id=6),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -130,19 +137,22 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=1,
|
||||
table_id=10)),
|
||||
table_id=10),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=22)],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=20)),
|
||||
table_id=20),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=22))
|
||||
table_id=22),
|
||||
active_bundle=None)
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -157,12 +167,14 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=2)],
|
||||
match=ofpp.OFPMatch(in_port=patch_int_ofport),
|
||||
priority=1, table_id=0)),
|
||||
priority=1, table_id=0),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=0)),
|
||||
priority=0, table_id=0),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=21)],
|
||||
|
@ -170,36 +182,42 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
eth_dst='ff:ff:ff:ff:ff:ff',
|
||||
eth_type=self.ether_types.ETH_TYPE_ARP),
|
||||
priority=1,
|
||||
table_id=2)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
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)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
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)),
|
||||
table_id=2),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=3)),
|
||||
priority=0, table_id=3),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=4)),
|
||||
priority=0, table_id=4),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0, table_id=6)),
|
||||
priority=0, table_id=6),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[
|
||||
|
@ -236,25 +254,29 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=1,
|
||||
table_id=10)),
|
||||
table_id=10),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=22)],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=20)),
|
||||
table_id=20),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[ofpp.OFPInstructionGotoTable(table_id=22)],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=21)),
|
||||
table_id=21),
|
||||
active_bundle=None),
|
||||
call._send_msg(ofpp.OFPFlowMod(dp,
|
||||
cookie=self.stamp,
|
||||
instructions=[],
|
||||
match=ofpp.OFPMatch(),
|
||||
priority=0,
|
||||
table_id=22))
|
||||
table_id=22),
|
||||
active_bundle=None)
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -280,7 +302,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(tunnel_id=segmentation_id),
|
||||
priority=1,
|
||||
table_id=4)),
|
||||
table_id=4),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -316,7 +339,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(vlan_vid=vlan | ofp.OFPVID_PRESENT),
|
||||
priority=1,
|
||||
table_id=22)),
|
||||
table_id=22),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -353,7 +377,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
match=ofpp.OFPMatch(
|
||||
eth_dst=mac, vlan_vid=vlan | ofp.OFPVID_PRESENT),
|
||||
priority=2,
|
||||
table_id=20)),
|
||||
table_id=20),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -414,7 +439,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
arp_tpa=ip,
|
||||
vlan_vid=vlan | ofp.OFPVID_PRESENT),
|
||||
priority=1,
|
||||
table_id=21)),
|
||||
table_id=21),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -460,7 +486,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(in_port=port),
|
||||
priority=1,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
@ -488,7 +515,8 @@ class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
|
|||
],
|
||||
match=ofpp.OFPMatch(eth_src=mac),
|
||||
priority=1,
|
||||
table_id=9)),
|
||||
table_id=9),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
# 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 ryu.ofproto import ofproto_v1_3
|
||||
from ryu.ofproto import ofproto_v1_3_parser
|
||||
|
||||
from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
|
||||
import ofswitch
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
class FakeReply(object):
|
||||
def __init__(self, type):
|
||||
self.type = type
|
||||
|
||||
|
||||
class TestBundledOpenFlowBridge(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestBundledOpenFlowBridge, self).setUp()
|
||||
br = mock.Mock(spec=['install_instructions', 'foo'])
|
||||
br._get_dp = lambda: (mock.Mock(), ofproto_v1_3, ofproto_v1_3_parser)
|
||||
br.active_bundles = set()
|
||||
self.br = ofswitch.BundledOpenFlowBridge(br, False, False)
|
||||
|
||||
def test_method_calls(self):
|
||||
self.br.install_instructions(dummy_arg=1)
|
||||
self.br.br.install_instructions.assert_called_once_with(dummy_arg=1)
|
||||
|
||||
def test_illegal_method_calls(self):
|
||||
# With python3, this can be written as "with assertRaises..."
|
||||
try:
|
||||
self.br.uninstall_foo()
|
||||
self.fail("Expected an exception")
|
||||
except Exception as e:
|
||||
self.assertIsInstance(e, AttributeError)
|
||||
try:
|
||||
self.br.foo()
|
||||
self.fail("Expected an exception")
|
||||
except Exception as e:
|
||||
self.assertIsInstance(e, AttributeError)
|
||||
|
||||
def test_normal_bundle_context(self):
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
self.br.br._send_msg = mock.Mock(side_effect=[
|
||||
FakeReply(ofproto_v1_3.ONF_BCT_OPEN_REPLY),
|
||||
FakeReply(ofproto_v1_3.ONF_BCT_COMMIT_REPLY)])
|
||||
with self.br:
|
||||
self.assertIsNotNone(self.br.active_bundle)
|
||||
# Do nothing
|
||||
# Assert that the active bundle is gone
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
|
||||
def test_aborted_bundle_context(self):
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
self.br.br._send_msg = mock.Mock(side_effect=[
|
||||
FakeReply(ofproto_v1_3.ONF_BCT_OPEN_REPLY),
|
||||
FakeReply(ofproto_v1_3.ONF_BCT_DISCARD_REPLY)])
|
||||
try:
|
||||
with self.br:
|
||||
self.assertIsNotNone(self.br.active_bundle)
|
||||
raise Exception()
|
||||
except Exception:
|
||||
pass
|
||||
# Assert that the active bundle is gone
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
self.assertEqual(2, len(self.br.br._send_msg.mock_calls))
|
||||
args, kwargs = self.br.br._send_msg.call_args_list[0]
|
||||
self.assertEqual(ofproto_v1_3.ONF_BCT_OPEN_REQUEST,
|
||||
args[0].type)
|
||||
args, kwargs = self.br.br._send_msg.call_args_list[1]
|
||||
self.assertEqual(ofproto_v1_3.ONF_BCT_DISCARD_REQUEST,
|
||||
args[0].type)
|
||||
|
||||
def test_bundle_context_with_error(self):
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
self.br.br._send_msg = mock.Mock(side_effect=[
|
||||
FakeReply(ofproto_v1_3.ONF_BCT_OPEN_REPLY),
|
||||
RuntimeError])
|
||||
try:
|
||||
with self.br:
|
||||
saved_bundle_id = self.br.active_bundle
|
||||
self.assertIsNotNone(self.br.active_bundle)
|
||||
self.fail("Expected an exception")
|
||||
except RuntimeError:
|
||||
pass
|
||||
# Assert that the active bundle is gone
|
||||
self.assertIsNone(self.br.active_bundle)
|
||||
self.assertIn(saved_bundle_id, self.br.br.active_bundles)
|
||||
|
||||
self.assertEqual(2, len(self.br.br._send_msg.mock_calls))
|
||||
args, kwargs = self.br.br._send_msg.call_args_list[0]
|
||||
self.assertEqual(ofproto_v1_3.ONF_BCT_OPEN_REQUEST,
|
||||
args[0].type)
|
||||
args, kwargs = self.br.br._send_msg.call_args_list[1]
|
||||
self.assertEqual(ofproto_v1_3.ONF_BCT_COMMIT_REQUEST,
|
||||
args[0].type)
|
|
@ -204,6 +204,7 @@ class TestOVSCookieBridgeRyu(native_ovs_bridge_test_base.OVSBridgeTestBase):
|
|||
instructions=[],
|
||||
match=ofpp.OFPMatch(in_port=in_port),
|
||||
priority=priority,
|
||||
table_id=0)),
|
||||
table_id=0),
|
||||
active_bundle=None),
|
||||
]
|
||||
self.assertEqual(expected, self.mock.mock_calls)
|
||||
|
|
Loading…
Reference in New Issue