Setup br-tun in secure fail mode to avoid broadcast storms
When not creating br-tun in secure fail mode, there are chances to get a broadcast storm from br-tun. For example, this occurs when at least three nodes have the br-tun OpenFlow rules reset in and a broadcast/multicast packet enters br-tun. This can happen if: * openvswitch is restarted, until the agent reloads the Openflow rules. * during neutron-openvswitch-agent restart, br-tun is reset, and there is a few seconds timeframe where tunnel endpoints are plugged and OF rules are reset. Secure fail mode doesn't forward traffic by default if no rule is hit. Change-Id: Iba5ded14179156decb16dcd4b898c026660f9653 Closes-bug: #1421232
This commit is contained in:
parent
86dbb886be
commit
740ddc5043
|
@ -37,6 +37,9 @@ DEFAULT_OVS_VSCTL_TIMEOUT = 10
|
||||||
INVALID_OFPORT = -1
|
INVALID_OFPORT = -1
|
||||||
UNASSIGNED_OFPORT = []
|
UNASSIGNED_OFPORT = []
|
||||||
|
|
||||||
|
# OVS bridge fail modes
|
||||||
|
FAILMODE_SECURE = 'secure'
|
||||||
|
|
||||||
OPTS = [
|
OPTS = [
|
||||||
cfg.IntOpt('ovs_vsctl_timeout',
|
cfg.IntOpt('ovs_vsctl_timeout',
|
||||||
default=DEFAULT_OVS_VSCTL_TIMEOUT,
|
default=DEFAULT_OVS_VSCTL_TIMEOUT,
|
||||||
|
@ -151,7 +154,7 @@ class OVSBridge(BaseOVS):
|
||||||
check_error=True)
|
check_error=True)
|
||||||
|
|
||||||
def set_secure_mode(self):
|
def set_secure_mode(self):
|
||||||
self.ovsdb.set_fail_mode(self.br_name, 'secure').execute(
|
self.ovsdb.set_fail_mode(self.br_name, FAILMODE_SECURE).execute(
|
||||||
check_error=True)
|
check_error=True)
|
||||||
|
|
||||||
def set_protocols(self, protocols):
|
def set_protocols(self, protocols):
|
||||||
|
@ -164,10 +167,13 @@ class OVSBridge(BaseOVS):
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
self.delete_bridge(self.br_name)
|
self.delete_bridge(self.br_name)
|
||||||
|
|
||||||
def reset_bridge(self):
|
def reset_bridge(self, secure_mode=False):
|
||||||
with self.ovsdb.transaction() as txn:
|
with self.ovsdb.transaction() as txn:
|
||||||
txn.add(self.ovsdb.del_br(self.br_name))
|
txn.add(self.ovsdb.del_br(self.br_name))
|
||||||
txn.add(self.ovsdb.add_br(self.br_name))
|
txn.add(self.ovsdb.add_br(self.br_name))
|
||||||
|
if secure_mode:
|
||||||
|
txn.add(self.ovsdb.set_fail_mode(self.br_name,
|
||||||
|
FAILMODE_SECURE))
|
||||||
|
|
||||||
def add_port(self, port_name, *interface_attr_tuples):
|
def add_port(self, port_name, *interface_attr_tuples):
|
||||||
with self.ovsdb.transaction() as txn:
|
with self.ovsdb.transaction() as txn:
|
||||||
|
|
|
@ -770,7 +770,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin,
|
||||||
if not self.tun_br:
|
if not self.tun_br:
|
||||||
self.tun_br = ovs_lib.OVSBridge(tun_br_name, self.root_helper)
|
self.tun_br = ovs_lib.OVSBridge(tun_br_name, self.root_helper)
|
||||||
|
|
||||||
self.tun_br.reset_bridge()
|
self.tun_br.reset_bridge(secure_mode=True)
|
||||||
self.patch_tun_ofport = self.int_br.add_patch_port(
|
self.patch_tun_ofport = self.int_br.add_patch_port(
|
||||||
cfg.CONF.OVS.int_peer_patch_port, cfg.CONF.OVS.tun_peer_patch_port)
|
cfg.CONF.OVS.int_peer_patch_port, cfg.CONF.OVS.tun_peer_patch_port)
|
||||||
self.patch_int_ofport = self.tun_br.add_patch_port(
|
self.patch_int_ofport = self.tun_br.add_patch_port(
|
||||||
|
|
|
@ -93,9 +93,12 @@ class OVSBridgeTestCase(base.BaseOVSLinuxTestCase):
|
||||||
|
|
||||||
def test_set_fail_mode(self):
|
def test_set_fail_mode(self):
|
||||||
self.br.set_secure_mode()
|
self.br.set_secure_mode()
|
||||||
|
self._assert_br_fail_mode(ovs_lib.FAILMODE_SECURE)
|
||||||
|
|
||||||
|
def _assert_br_fail_mode(self, fail_mode):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.br.db_get_val('Bridge', self.br.br_name, 'fail_mode'),
|
self.br.db_get_val('Bridge', self.br.br_name, 'fail_mode'),
|
||||||
'secure')
|
fail_mode)
|
||||||
|
|
||||||
def test_set_protocols(self):
|
def test_set_protocols(self):
|
||||||
self.br.set_protocols('OpenFlow10')
|
self.br.set_protocols('OpenFlow10')
|
||||||
|
@ -190,6 +193,16 @@ class OVSBridgeTestCase(base.BaseOVSLinuxTestCase):
|
||||||
self.br.delete_ports(all_ports=True)
|
self.br.delete_ports(all_ports=True)
|
||||||
self.assertEqual(len(self.br.get_port_name_list()), 0)
|
self.assertEqual(len(self.br.get_port_name_list()), 0)
|
||||||
|
|
||||||
|
def test_reset_bridge(self):
|
||||||
|
self.create_ovs_port()
|
||||||
|
self.br.reset_bridge()
|
||||||
|
self.assertEqual(len(self.br.get_port_name_list()), 0)
|
||||||
|
self._assert_br_fail_mode([])
|
||||||
|
|
||||||
|
def test_reset_bridge_secure_mode(self):
|
||||||
|
self.br.reset_bridge(secure_mode=True)
|
||||||
|
self._assert_br_fail_mode(ovs_lib.FAILMODE_SECURE)
|
||||||
|
|
||||||
|
|
||||||
class OVSLibTestCase(base.BaseOVSLinuxTestCase):
|
class OVSLibTestCase(base.BaseOVSLinuxTestCase):
|
||||||
def test_bridge_lifecycle_baseovs(self):
|
def test_bridge_lifecycle_baseovs(self):
|
||||||
|
|
|
@ -186,7 +186,7 @@ class TunnelTest(base.BaseTestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
self.mock_tun_bridge_expected = [
|
self.mock_tun_bridge_expected = [
|
||||||
mock.call.reset_bridge(),
|
mock.call.reset_bridge(secure_mode=True),
|
||||||
mock.call.add_patch_port('patch-int', 'patch-tun'),
|
mock.call.add_patch_port('patch-int', 'patch-tun'),
|
||||||
]
|
]
|
||||||
self.mock_int_bridge_expected += [
|
self.mock_int_bridge_expected += [
|
||||||
|
@ -602,7 +602,7 @@ class TunnelTestUseVethInterco(TunnelTest):
|
||||||
]
|
]
|
||||||
|
|
||||||
self.mock_tun_bridge_expected = [
|
self.mock_tun_bridge_expected = [
|
||||||
mock.call.reset_bridge(),
|
mock.call.reset_bridge(secure_mode=True),
|
||||||
mock.call.add_patch_port('patch-int', 'patch-tun'),
|
mock.call.add_patch_port('patch-int', 'patch-tun'),
|
||||||
]
|
]
|
||||||
self.mock_int_bridge_expected += [
|
self.mock_int_bridge_expected += [
|
||||||
|
|
Loading…
Reference in New Issue