of_interface: Implement bundled() method

Change-Id: Ie0de8309cdbed02fa88887e7fe25e8b3a2c0afe1
Related-blueprint: ovs-ofctl-to-python
This commit is contained in:
IWAMOTO Toshihiro 2017-03-29 15:47:26 +09:00
parent 9f10a9304f
commit 2180bd902c
8 changed files with 345 additions and 66 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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