self._process_internal_ports(ri)
self._process_external(ri)
# Process static routes for router
- self.routes_updated(ri)
+ ri.routes_updated()
# Enable or disable keepalived for ha routers
self._process_ha_router(ri)
# When L3 agent is ready, we immediately do a full sync
self.periodic_sync_routers_task(self.context)
- def _update_routing_table(self, ri, operation, route):
- cmd = ['ip', 'route', operation, 'to', route['destination'],
- 'via', route['nexthop']]
- ip_wrapper = ip_lib.IPWrapper(self.root_helper,
- namespace=ri.ns_name)
- ip_wrapper.netns.execute(cmd, check_exit_code=False)
-
- def routes_updated(self, ri):
- new_routes = ri.router['routes']
- if ri.is_ha:
- ri._process_virtual_routes(new_routes)
- return
-
- old_routes = ri.routes
- adds, removes = common_utils.diff_list_of_dict(old_routes,
- new_routes)
- for route in adds:
- LOG.debug("Added route entry is '%s'", route)
- # remove replaced route from deleted route
- for del_route in removes:
- if route['destination'] == del_route['destination']:
- removes.remove(del_route)
- #replace success even if there is no existing route
- self._update_routing_table(ri, 'replace', route)
- for route in removes:
- LOG.debug("Removed route entry is '%s'", route)
- self._update_routing_table(ri, 'delete', route)
- ri.routes = new_routes
-
class L3NATAgentWithStateReport(L3NATAgent):
def _ha_external_gateway_removed(self, interface_name):
self._clear_vips(interface_name)
- def _process_virtual_routes(self, new_routes):
+ def routes_updated(self):
+ new_routes = self.router['routes']
+
instance = self._get_keepalived_instance()
# Filter out all of the old routes while keeping only the default route
route['destination'],
route['nexthop']))
+ self.routes = new_routes
+
def _add_default_gw_virtual_route(self, ex_gw_port, interface_name):
gw_ip = ex_gw_port['subnet']['gateway_ip']
if gw_ip:
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.agent.linux import ip_lib
from neutron.agent.linux import iptables_manager
+from neutron.common import utils as common_utils
+from neutron.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
class RouterInfo(object):
snat_callback(self, self._router.get('gw_port'),
*args, action=self._snat_action)
self._snat_action = None
+
+ def _update_routing_table(self, operation, route):
+ cmd = ['ip', 'route', operation, 'to', route['destination'],
+ 'via', route['nexthop']]
+ ip_wrapper = ip_lib.IPWrapper(self.root_helper,
+ namespace=self.ns_name)
+ ip_wrapper.netns.execute(cmd, check_exit_code=False)
+
+ def routes_updated(self):
+ new_routes = self.router['routes']
+
+ old_routes = self.routes
+ adds, removes = common_utils.diff_list_of_dict(old_routes,
+ new_routes)
+ for route in adds:
+ LOG.debug("Added route entry is '%s'", route)
+ # remove replaced route from deleted route
+ for del_route in removes:
+ if route['destination'] == del_route['destination']:
+ removes.remove(del_route)
+ #replace success even if there is no existing route
+ self._update_routing_table('replace', route)
+ for route in removes:
+ LOG.debug("Removed route entry is '%s'", route)
+ self._update_routing_table('delete', route)
+ self.routes = new_routes
--- /dev/null
+# 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 neutron.agent.common import config as agent_config
+from neutron.agent.l3 import router_info
+from neutron.openstack.common import uuidutils
+from neutron.tests import base
+
+
+_uuid = uuidutils.generate_uuid
+
+
+class TestRouterInfo(base.BaseTestCase):
+ def setUp(self):
+ super(TestRouterInfo, self).setUp()
+
+ conf = agent_config.setup_conf()
+ agent_config.register_root_helper(conf)
+ conf.root_helper = 'sudo'
+
+ self.ip_cls_p = mock.patch('neutron.agent.linux.ip_lib.IPWrapper')
+ ip_cls = self.ip_cls_p.start()
+ self.mock_ip = mock.MagicMock()
+ ip_cls.return_value = self.mock_ip
+ self.ri_kwargs = {'root_helper': conf.root_helper,
+ 'agent_conf': conf,
+ 'interface_driver': mock.sentinel.interface_driver}
+
+ def _check_agent_method_called(self, calls):
+ self.mock_ip.netns.execute.assert_has_calls(
+ [mock.call(call, check_exit_code=False) for call in calls],
+ any_order=True)
+
+ def test_routing_table_update(self):
+ ri = router_info.RouterInfo(_uuid(), {}, ns_name=_uuid(),
+ **self.ri_kwargs)
+ ri.router = {}
+
+ fake_route1 = {'destination': '135.207.0.0/16',
+ 'nexthop': '1.2.3.4'}
+ fake_route2 = {'destination': '135.207.111.111/32',
+ 'nexthop': '1.2.3.4'}
+
+ ri._update_routing_table('replace', fake_route1)
+ expected = [['ip', 'route', 'replace', 'to', '135.207.0.0/16',
+ 'via', '1.2.3.4']]
+ self._check_agent_method_called(expected)
+
+ ri._update_routing_table('delete', fake_route1)
+ expected = [['ip', 'route', 'delete', 'to', '135.207.0.0/16',
+ 'via', '1.2.3.4']]
+ self._check_agent_method_called(expected)
+
+ ri._update_routing_table('replace', fake_route2)
+ expected = [['ip', 'route', 'replace', 'to', '135.207.111.111/32',
+ 'via', '1.2.3.4']]
+ self._check_agent_method_called(expected)
+
+ ri._update_routing_table('delete', fake_route2)
+ expected = [['ip', 'route', 'delete', 'to', '135.207.111.111/32',
+ 'via', '1.2.3.4']]
+ self._check_agent_method_called(expected)
+
+ def test_routes_updated(self):
+ ri = router_info.RouterInfo(_uuid(), {}, ns_name=_uuid(),
+ **self.ri_kwargs)
+ ri.router = {}
+
+ fake_old_routes = []
+ fake_new_routes = [{'destination': "110.100.31.0/24",
+ 'nexthop': "10.100.10.30"},
+ {'destination': "110.100.30.0/24",
+ 'nexthop': "10.100.10.30"}]
+ ri.routes = fake_old_routes
+ ri.router['routes'] = fake_new_routes
+ ri.routes_updated()
+
+ expected = [['ip', 'route', 'replace', 'to', '110.100.30.0/24',
+ 'via', '10.100.10.30'],
+ ['ip', 'route', 'replace', 'to', '110.100.31.0/24',
+ 'via', '10.100.10.30']]
+
+ self._check_agent_method_called(expected)
+
+ fake_new_routes = [{'destination': "110.100.30.0/24",
+ 'nexthop': "10.100.10.30"}]
+ ri.router['routes'] = fake_new_routes
+ ri.routes_updated()
+ expected = [['ip', 'route', 'delete', 'to', '110.100.31.0/24',
+ 'via', '10.100.10.30']]
+
+ self._check_agent_method_called(expected)
+ fake_new_routes = []
+ ri.router['routes'] = fake_new_routes
+ ri.routes_updated()
+
+ expected = [['ip', 'route', 'delete', 'to', '110.100.30.0/24',
+ 'via', '10.100.10.30']]
+ self._check_agent_method_called(expected)
'priority': 1}
-class TestBasicRouterOperations(base.BaseTestCase):
+class BasicRouterOperationsFramework(base.BaseTestCase):
def setUp(self):
- super(TestBasicRouterOperations, self).setUp()
+ super(BasicRouterOperationsFramework, self).setUp()
self.conf = agent_config.setup_conf()
self.conf.register_opts(base_config.core_opts)
self.conf.register_cli_opts(log.common_cli_opts)
return agent, ri, port
+
+class TestBasicRouterOperations(BasicRouterOperationsFramework):
def test_periodic_sync_routers_task_raise_exception(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.plugin_api.get_routers.side_effect = ValueError()
router['gw_port_host'] = HOSTNAME
self._test_external_gateway_action('remove', router)
- def _check_agent_method_called(self, agent, calls, namespace):
- self.mock_ip.netns.execute.assert_has_calls(
- [mock.call(call, check_exit_code=False) for call in calls],
- any_order=True)
-
- def _test_routing_table_update(self, namespace):
- if not namespace:
- self.conf.set_override('use_namespaces', False)
-
- router_id = _uuid()
- ri = l3router.RouterInfo(router_id, {}, **self.ri_kwargs)
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
-
- fake_route1 = {'destination': '135.207.0.0/16',
- 'nexthop': '1.2.3.4'}
- fake_route2 = {'destination': '135.207.111.111/32',
- 'nexthop': '1.2.3.4'}
-
- agent._update_routing_table(ri, 'replace', fake_route1)
- expected = [['ip', 'route', 'replace', 'to', '135.207.0.0/16',
- 'via', '1.2.3.4']]
- self._check_agent_method_called(agent, expected, namespace)
-
- agent._update_routing_table(ri, 'delete', fake_route1)
- expected = [['ip', 'route', 'delete', 'to', '135.207.0.0/16',
- 'via', '1.2.3.4']]
- self._check_agent_method_called(agent, expected, namespace)
-
- agent._update_routing_table(ri, 'replace', fake_route2)
- expected = [['ip', 'route', 'replace', 'to', '135.207.111.111/32',
- 'via', '1.2.3.4']]
- self._check_agent_method_called(agent, expected, namespace)
-
- agent._update_routing_table(ri, 'delete', fake_route2)
- expected = [['ip', 'route', 'delete', 'to', '135.207.111.111/32',
- 'via', '1.2.3.4']]
- self._check_agent_method_called(agent, expected, namespace)
-
- def test_agent_routing_table_updated(self):
- self._test_routing_table_update(namespace=True)
-
- def test_agent_routing_table_updated_no_namespace(self):
- self._test_routing_table_update(namespace=False)
-
- def test_routes_updated(self):
- self._test_routes_updated(namespace=True)
-
- def test_routes_updated_no_namespace(self):
- self._test_routes_updated(namespace=False)
-
- def _test_routes_updated(self, namespace=True):
- if not namespace:
- self.conf.set_override('use_namespaces', False)
- agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
- router_id = _uuid()
-
- ri = l3router.RouterInfo(router_id, {}, **self.ri_kwargs)
- ri.router = {}
-
- fake_old_routes = []
- fake_new_routes = [{'destination': "110.100.31.0/24",
- 'nexthop': "10.100.10.30"},
- {'destination': "110.100.30.0/24",
- 'nexthop': "10.100.10.30"}]
- ri.routes = fake_old_routes
- ri.router['routes'] = fake_new_routes
- agent.routes_updated(ri)
-
- expected = [['ip', 'route', 'replace', 'to', '110.100.30.0/24',
- 'via', '10.100.10.30'],
- ['ip', 'route', 'replace', 'to', '110.100.31.0/24',
- 'via', '10.100.10.30']]
-
- self._check_agent_method_called(agent, expected, namespace)
-
- fake_new_routes = [{'destination': "110.100.30.0/24",
- 'nexthop': "10.100.10.30"}]
- ri.router['routes'] = fake_new_routes
- agent.routes_updated(ri)
- expected = [['ip', 'route', 'delete', 'to', '110.100.31.0/24',
- 'via', '10.100.10.30']]
-
- self._check_agent_method_called(agent, expected, namespace)
- fake_new_routes = []
- ri.router['routes'] = fake_new_routes
- agent.routes_updated(ri)
-
- expected = [['ip', 'route', 'delete', 'to', '110.100.30.0/24',
- 'via', '10.100.10.30']]
- self._check_agent_method_called(agent, expected, namespace)
-
def _verify_snat_rules(self, rules, router, negate=False):
interfaces = router[l3_constants.INTERFACE_KEY]
source_cidrs = []