Add IPv6 Prefix Delegation support for DVR
Unlike Legacy routers, DVR Edge Routers have their gateway interfaces in the SNAT namespace as opposed to the router namespace. Added a new method to the router_info class, get_gw_ns_name(), so callers can determine which namespace the gateway device lives in. This can then be over-ridden in the DVR Edge router class. The Prefix Delegation code will also now listen on the update_router event from the l3-agent and reset the namespace name if it changes. Closes-Bug: #1541406 Change-Id: If6ada5027d0483fac7fc3ff935fee1edfc6e2759
This commit is contained in:
parent
eeeee06bf0
commit
7b5f01c2e5
@ -33,6 +33,9 @@ class DvrEdgeRouter(dvr_local_router.DvrLocalRouter):
|
||||
self.router_id, self.agent_conf, self.driver, self.use_ipv6)
|
||||
self.snat_iptables_manager = None
|
||||
|
||||
def get_gw_ns_name(self):
|
||||
return self.snat_namespace.name
|
||||
|
||||
def external_gateway_added(self, ex_gw_port, interface_name):
|
||||
super(DvrEdgeRouter, self).external_gateway_added(
|
||||
ex_gw_port, interface_name)
|
||||
|
@ -122,6 +122,9 @@ class RouterInfo(object):
|
||||
def get_external_device_interface_name(self, ex_gw_port):
|
||||
return self.get_external_device_name(ex_gw_port['id'])
|
||||
|
||||
def get_gw_ns_name(self):
|
||||
return self.ns_name
|
||||
|
||||
def _update_routing_table(self, operation, route, namespace):
|
||||
cmd = ['ip', 'route', operation, 'to', route['destination'],
|
||||
'via', route['nexthop']]
|
||||
|
@ -24,7 +24,7 @@ from oslo_utils import netutils
|
||||
import six
|
||||
from stevedore import driver
|
||||
|
||||
from neutron._i18n import _
|
||||
from neutron._i18n import _, _LE
|
||||
from neutron.callbacks import events
|
||||
from neutron.callbacks import registry
|
||||
from neutron.callbacks import resources
|
||||
@ -57,6 +57,9 @@ class PrefixDelegation(object):
|
||||
registry.subscribe(add_router,
|
||||
resources.ROUTER,
|
||||
events.BEFORE_CREATE)
|
||||
registry.subscribe(update_router,
|
||||
resources.ROUTER,
|
||||
events.AFTER_UPDATE)
|
||||
registry.subscribe(remove_router,
|
||||
resources.ROUTER,
|
||||
events.AFTER_DELETE)
|
||||
@ -329,12 +332,24 @@ def get_router_entry(ns_name):
|
||||
def add_router(resource, event, l3_agent, **kwargs):
|
||||
added_router = kwargs['router']
|
||||
router = l3_agent.pd.routers.get(added_router.router_id)
|
||||
gw_ns_name = added_router.get_gw_ns_name()
|
||||
if not router:
|
||||
l3_agent.pd.routers[added_router.router_id] = (
|
||||
get_router_entry(added_router.ns_name))
|
||||
get_router_entry(gw_ns_name))
|
||||
else:
|
||||
# This will happen during l3 agent restart
|
||||
router['ns_name'] = added_router.ns_name
|
||||
router['ns_name'] = gw_ns_name
|
||||
|
||||
|
||||
@utils.synchronized("l3-agent-pd")
|
||||
def update_router(resource, event, l3_agent, **kwargs):
|
||||
updated_router = kwargs['router']
|
||||
router = l3_agent.pd.routers.get(updated_router.router_id)
|
||||
if not router:
|
||||
LOG.exception(_LE("Router to be updated is not in internal routers "
|
||||
"list: %s"), updated_router.router_id)
|
||||
else:
|
||||
router['ns_name'] = updated_router.get_gw_ns_name()
|
||||
|
||||
|
||||
class PDInfo(object):
|
||||
|
@ -670,8 +670,10 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
|
||||
self._set_ri_kwargs(mock.Mock(), router['id'], router)
|
||||
ri = dvr_router.DvrEdgeRouter(HOSTNAME, **self.ri_kwargs)
|
||||
# Make sure that ri.snat_namespace object is created when the
|
||||
# router is initialized
|
||||
# router is initialized, and that it's name matches the gw
|
||||
# namespace name
|
||||
self.assertIsNotNone(ri.snat_namespace)
|
||||
self.assertEqual(ri.snat_namespace.name, ri.get_gw_ns_name())
|
||||
|
||||
def test_ext_gw_updated_calling_snat_ns_delete_if_gw_port_host_none(
|
||||
self):
|
||||
|
@ -164,6 +164,10 @@ class TestDvrRouterOperations(base.BaseTestCase):
|
||||
self.ri_kwargs['router_id'] = router_id
|
||||
self.ri_kwargs['router'] = router
|
||||
|
||||
def test_gw_ns_name(self):
|
||||
ri = self._create_router()
|
||||
self.assertEqual(ri.ns_name, ri.get_gw_ns_name())
|
||||
|
||||
def test_create_dvr_fip_interfaces_update(self):
|
||||
ri = self._create_router()
|
||||
fip_agent_port = {'subnets': []}
|
||||
|
@ -12,6 +12,9 @@
|
||||
|
||||
import mock
|
||||
|
||||
from neutron.agent.l3 import dvr_edge_router
|
||||
from neutron.agent.l3 import dvr_local_router
|
||||
from neutron.agent.l3 import legacy_router
|
||||
from neutron.agent.linux import pd
|
||||
from neutron.tests import base as tests_base
|
||||
|
||||
@ -24,8 +27,68 @@ class FakeRouter(object):
|
||||
class TestPrefixDelegation(tests_base.DietTestCase):
|
||||
def test_remove_router(self):
|
||||
l3_agent = mock.Mock()
|
||||
router_id = 1
|
||||
router_id = '1'
|
||||
l3_agent.pd.routers = {router_id: pd.get_router_entry(None)}
|
||||
pd.remove_router(None, None, l3_agent, router=FakeRouter(router_id))
|
||||
self.assertTrue(l3_agent.pd.delete_router_pd.called)
|
||||
self.assertEqual({}, l3_agent.pd.routers)
|
||||
|
||||
def _test_add_update_pd(self, l3_agent, router, ns_name):
|
||||
# add entry
|
||||
pd.add_router(None, None, l3_agent, router=router)
|
||||
pd_router = l3_agent.pd.routers.get(router.router_id)
|
||||
self.assertEqual(ns_name, pd_router.get('ns_name'))
|
||||
|
||||
# clear namespace name, update entry
|
||||
pd_router['ns_name'] = None
|
||||
pd.update_router(None, None, l3_agent, router=router)
|
||||
pd_router = l3_agent.pd.routers.get(router.router_id)
|
||||
self.assertEqual(ns_name, pd_router.get('ns_name'))
|
||||
|
||||
def test_add_update_dvr_edge_router(self):
|
||||
l3_agent = mock.Mock()
|
||||
l3_agent.pd.routers = {}
|
||||
router_id = '1'
|
||||
ri = dvr_edge_router.DvrEdgeRouter(l3_agent,
|
||||
'host',
|
||||
router_id,
|
||||
mock.Mock(),
|
||||
mock.Mock(),
|
||||
mock.Mock())
|
||||
ns_name = ri.snat_namespace.name
|
||||
self._test_add_update_pd(l3_agent, ri, ns_name)
|
||||
|
||||
def test_add_update_dvr_local_router(self):
|
||||
l3_agent = mock.Mock()
|
||||
l3_agent.pd.routers = {}
|
||||
router_id = '1'
|
||||
ri = dvr_local_router.DvrLocalRouter(l3_agent,
|
||||
'host',
|
||||
router_id,
|
||||
mock.Mock(),
|
||||
mock.Mock(),
|
||||
mock.Mock())
|
||||
ns_name = ri.ns_name
|
||||
self._test_add_update_pd(l3_agent, ri, ns_name)
|
||||
|
||||
def test_add_update_legacy_router(self):
|
||||
l3_agent = mock.Mock()
|
||||
l3_agent.pd.routers = {}
|
||||
router_id = '1'
|
||||
ri = legacy_router.LegacyRouter(l3_agent,
|
||||
router_id,
|
||||
mock.Mock(),
|
||||
mock.Mock(),
|
||||
mock.Mock())
|
||||
ns_name = ri.ns_name
|
||||
self._test_add_update_pd(l3_agent, ri, ns_name)
|
||||
|
||||
def test_update_no_router_exception(self):
|
||||
l3_agent = mock.Mock()
|
||||
l3_agent.pd.routers = {}
|
||||
router = mock.Mock()
|
||||
router.router_id = '1'
|
||||
|
||||
with mock.patch.object(pd.LOG, 'exception') as log:
|
||||
pd.update_router(None, None, l3_agent, router=router)
|
||||
self.assertTrue(log.called)
|
||||
|
Loading…
Reference in New Issue
Block a user