From 740ddc5043e39f3babb57896652d11c223f1f385 Mon Sep 17 00:00:00 2001 From: Miguel Angel Ajo Date: Thu, 12 Feb 2015 14:32:58 +0000 Subject: [PATCH] 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 --- neutron/agent/linux/ovs_lib.py | 10 ++++++++-- .../openvswitch/agent/ovs_neutron_agent.py | 2 +- neutron/tests/functional/agent/test_ovs_lib.py | 15 ++++++++++++++- neutron/tests/unit/openvswitch/test_ovs_tunnel.py | 4 ++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/neutron/agent/linux/ovs_lib.py b/neutron/agent/linux/ovs_lib.py index 6895d565f..1c05c2220 100644 --- a/neutron/agent/linux/ovs_lib.py +++ b/neutron/agent/linux/ovs_lib.py @@ -37,6 +37,9 @@ DEFAULT_OVS_VSCTL_TIMEOUT = 10 INVALID_OFPORT = -1 UNASSIGNED_OFPORT = [] +# OVS bridge fail modes +FAILMODE_SECURE = 'secure' + OPTS = [ cfg.IntOpt('ovs_vsctl_timeout', default=DEFAULT_OVS_VSCTL_TIMEOUT, @@ -151,7 +154,7 @@ class OVSBridge(BaseOVS): check_error=True) 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) def set_protocols(self, protocols): @@ -164,10 +167,13 @@ class OVSBridge(BaseOVS): def destroy(self): self.delete_bridge(self.br_name) - def reset_bridge(self): + def reset_bridge(self, secure_mode=False): with self.ovsdb.transaction() as txn: txn.add(self.ovsdb.del_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): with self.ovsdb.transaction() as txn: diff --git a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py index b1a3565bb..333e14c90 100644 --- a/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/openvswitch/agent/ovs_neutron_agent.py @@ -770,7 +770,7 @@ class OVSNeutronAgent(sg_rpc.SecurityGroupAgentRpcCallbackMixin, if not self.tun_br: 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( cfg.CONF.OVS.int_peer_patch_port, cfg.CONF.OVS.tun_peer_patch_port) self.patch_int_ofport = self.tun_br.add_patch_port( diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py index 89192e52f..4f6f2e622 100644 --- a/neutron/tests/functional/agent/test_ovs_lib.py +++ b/neutron/tests/functional/agent/test_ovs_lib.py @@ -93,9 +93,12 @@ class OVSBridgeTestCase(base.BaseOVSLinuxTestCase): def test_set_fail_mode(self): 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.br.db_get_val('Bridge', self.br.br_name, 'fail_mode'), - 'secure') + fail_mode) def test_set_protocols(self): self.br.set_protocols('OpenFlow10') @@ -190,6 +193,16 @@ class OVSBridgeTestCase(base.BaseOVSLinuxTestCase): self.br.delete_ports(all_ports=True) 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): def test_bridge_lifecycle_baseovs(self): diff --git a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py index 53595cbd6..4ab73e1db 100644 --- a/neutron/tests/unit/openvswitch/test_ovs_tunnel.py +++ b/neutron/tests/unit/openvswitch/test_ovs_tunnel.py @@ -186,7 +186,7 @@ class TunnelTest(base.BaseTestCase): ] 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'), ] self.mock_int_bridge_expected += [ @@ -602,7 +602,7 @@ class TunnelTestUseVethInterco(TunnelTest): ] 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'), ] self.mock_int_bridge_expected += [ -- 2.45.2