diff --git a/neutron/agent/common/config.py b/neutron/agent/common/config.py index b6913d58d61..499e27899f1 100644 --- a/neutron/agent/common/config.py +++ b/neutron/agent/common/config.py @@ -83,14 +83,14 @@ AVAILABILITY_ZONE_OPTS = [ ] EXT_NET_BRIDGE_OPTS = [ - cfg.StrOpt('external_network_bridge', default='br-ex', + cfg.StrOpt('external_network_bridge', default='', deprecated_for_removal=True, help=_("Name of bridge used for external network " - "traffic. This should be set to an empty value for the " - "Linux Bridge. When this parameter is set, each L3 " - "agent can be associated with no more than one external " - "network. This option is deprecated and will be removed " - "in the M release.")), + "traffic. When this parameter is set, the L3 agent will " + "plug an interface directly into an external bridge " + "which will not allow any wiring by the L2 agent. Using " + "this will result in incorrect port statuses. This " + "option is deprecated and will be removed in Ocata.")) ] diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 98b7eea4b99..9537afe3df9 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -332,7 +332,7 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase, ext_net_id = agent['configurations'].get( 'gateway_external_network_id') ext_bridge = agent['configurations'].get( - 'external_network_bridge', 'br-ex') + 'external_network_bridge', '') if (ext_net_id == network_id or (not ext_net_id and not ext_bridge)): return diff --git a/neutron/tests/functional/agent/l3/test_legacy_router.py b/neutron/tests/functional/agent/l3/test_legacy_router.py index 60306ae51f5..212aa2010a3 100644 --- a/neutron/tests/functional/agent/l3/test_legacy_router.py +++ b/neutron/tests/functional/agent/l3/test_legacy_router.py @@ -24,6 +24,7 @@ from neutron.agent.linux import ip_lib from neutron.callbacks import events from neutron.callbacks import registry from neutron.callbacks import resources +from neutron.tests import base as tests_base from neutron.tests.common import machine_fixtures from neutron.tests.common import net_helpers from neutron.tests.functional.agent.l3 import framework @@ -96,6 +97,39 @@ class L3AgentTestCase(framework.L3AgentTestFramework): self.assertIsNone(device.route.get_gateway()) + def _make_bridge(self): + bridge = framework.get_ovs_bridge(tests_base.get_rand_name()) + bridge.create() + self.addCleanup(bridge.destroy) + return bridge + + def test_external_network_bridge_change(self): + bridge1, bridge2 = self._make_bridge(), self._make_bridge() + self.agent.conf.set_override('external_network_bridge', + bridge1.br_name) + router_info = self.generate_router_info(False) + router = self.manage_router(self.agent, router_info) + gw_port = router.router['gw_port'] + gw_inf_name = router.get_external_device_name(gw_port['id']) + + self.assertIn(gw_inf_name, + [v.port_name for v in bridge1.get_vif_ports()]) + # changeing the external_network_bridge should have no impact since + # the interface exists. + self.agent.conf.set_override('external_network_bridge', + bridge2.br_name) + self.manage_router(self.agent, router_info) + self.assertIn(gw_inf_name, + [v.port_name for v in bridge1.get_vif_ports()]) + self.assertNotIn(gw_inf_name, + [v.port_name for v in bridge2.get_vif_ports()]) + namespaces.Namespace.delete(router.router_namespace) + self.manage_router(self.agent, router_info) + self.assertIn(gw_inf_name, + [v.port_name for v in bridge2.get_vif_ports()]) + self.assertNotIn(gw_inf_name, + [v.port_name for v in bridge1.get_vif_ports()]) + def test_legacy_router_ns_rebuild(self): router_info = self.generate_router_info(False) router = self.manage_router(self.agent, router_info) diff --git a/neutron/tests/unit/agent/l3/test_agent.py b/neutron/tests/unit/agent/l3/test_agent.py index 184cbbbd330..815091e96bb 100644 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@ -1813,7 +1813,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): self.mock_driver.unplug.assert_called_with( stale_devnames[0], - bridge="br-ex", + bridge="", namespace=ri.ns_name, prefix=l3_agent.EXTERNAL_DEV_PREFIX) @@ -1994,6 +1994,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): self._test_process_routers_update_router_deleted(True) def test_process_router_if_compatible_with_no_ext_net_in_conf(self): + self.conf.set_override('external_network_bridge', 'br-ex') agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) self.plugin_api.get_external_network_id.return_value = 'aaa' @@ -2022,6 +2023,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): self.assertFalse(self.plugin_api.get_external_network_id.called) def test_process_router_if_compatible_with_stale_cached_ext_net(self): + self.conf.set_override('external_network_bridge', 'br-ex') agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) self.plugin_api.get_external_network_id.return_value = 'aaa' agent.target_ex_net_id = 'bbb' @@ -2037,6 +2039,7 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): agent.context) def test_process_router_if_compatible_w_no_ext_net_and_2_net_plugin(self): + self.conf.set_override('external_network_bridge', 'br-ex') agent = l3_agent.L3NATAgent(HOSTNAME, self.conf) router = {'id': _uuid(), @@ -2078,7 +2081,6 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework): 'external_gateway_info': {'network_id': 'aaa'}} agent.router_info = {} - self.conf.set_override('external_network_bridge', '') agent._process_router_if_compatible(router) self.assertIn(router['id'], agent.router_info) diff --git a/neutron/tests/unit/debug/test_commands.py b/neutron/tests/unit/debug/test_commands.py index 60c6edea9c8..d564c0ffbe5 100644 --- a/neutron/tests/unit/debug/test_commands.py +++ b/neutron/tests/unit/debug/test_commands.py @@ -173,7 +173,7 @@ class TestDebugCommands(base.BaseTestCase): 'fake_port', 'tap12345678-12', 'aa:bb:cc:dd:ee:ffa', - bridge='br-ex', + bridge='', namespace=namespace), mock.call.init_l3('tap12345678-12', ['10.0.0.3/24'], @@ -223,7 +223,7 @@ class TestDebugCommands(base.BaseTestCase): self.driver.assert_has_calls([mock.call.get_device_name(mock.ANY), mock.call.unplug('tap12345678-12', namespace=namespace, - bridge='br-ex')]) + bridge='')]) def test_list_probe(self): cmd = commands.ListProbe(self.app, None) diff --git a/releasenotes/notes/change_external_network_bridge_default-5de3a0c19182eb70.yaml b/releasenotes/notes/change_external_network_bridge_default-5de3a0c19182eb70.yaml new file mode 100644 index 00000000000..e69331f22f4 --- /dev/null +++ b/releasenotes/notes/change_external_network_bridge_default-5de3a0c19182eb70.yaml @@ -0,0 +1,16 @@ +--- +prelude: > + The default value for 'external_network_bridge' in the L3 agent is now ''. +upgrade: + - The default value for 'external_network_bridge' has been changed to '' + since that is the preferred way to configure the L3 agent and will be the + only way in future releases. If you have not explicitly set this value + and you use the L3 agent, you will need to set this value to 'br-ex' to + match the old default. + If you are using 'br-ex', you should switch to '', ensure your external + network has a flat segment and ensure your L2 agent has a bridge_mapping + entry between the external network's flat segment physnet and 'br-ex' to + get the same connectivity. If the external network did not already have + the flat segment, you will need to detach all routers from the external + networks, delete the incorrect segment type, add the flat segment, and + re-attach the routers.