Fix IPv6 prefix delegation issue on agent restart

On l3-agent restart, prefix delegation subnets weren't always
inserted into the local router_info cache, leading to a missing
ip6tables rule.  Add it when the internal network is configured
if the prefix has already been assigned.

Change-Id: Ic045e2763ba2772bcaf037591821501e84e40878
Closes-bug: #1789403
(cherry picked from commit d19dcf1ef2)
This commit is contained in:
Brian Haley 2018-08-29 17:06:59 -04:00 committed by Brian Haley
parent 517918dc5e
commit b2cd92241f
3 changed files with 51 additions and 2 deletions

View File

@ -567,6 +567,9 @@ class RouterInfo(object):
self.agent.pd.enable_subnet(self.router_id, subnet['id'],
subnet['cidr'],
interface_name, p['mac_address'])
if (subnet['cidr'] !=
lib_constants.PROVISIONAL_IPV6_PD_PREFIX):
self.pd_subnets[subnet['id']] = subnet['cidr']
for p in old_ports:
self.internal_network_removed(p)

View File

@ -269,7 +269,9 @@ def router_append_subnet(router, count=1, ip_version=4,
router[lib_constants.INTERFACE_KEY] = interfaces
def router_append_pd_enabled_subnet(router, count=1):
def router_append_pd_enabled_subnet(router, count=1, prefix=None):
if not prefix:
prefix = lib_constants.PROVISIONAL_IPV6_PD_PREFIX
interfaces = router[lib_constants.INTERFACE_KEY]
current = sum(netaddr.IPNetwork(subnet['cidr']).version == 6
for p in interfaces for subnet in p['subnets'])
@ -288,7 +290,7 @@ def router_append_pd_enabled_subnet(router, count=1):
'subnet_id': subnet_id}],
'mac_address': str(mac_address),
'subnets': [{'id': subnet_id,
'cidr': lib_constants.PROVISIONAL_IPV6_PD_PREFIX,
'cidr': prefix,
'gateway_ip': '::1',
'ipv6_ra_mode': lib_constants.IPV6_SLAAC,
'subnetpool_id': lib_constants.IPV6_PD_POOL_ID}]}
@ -308,6 +310,17 @@ def get_unassigned_pd_interfaces(router):
return pd_intfs
def get_assigned_pd_interfaces(router):
pd_intfs = []
for intf in router[lib_constants.INTERFACE_KEY]:
for subnet in intf['subnets']:
if (ipv6_utils.is_ipv6_pd_enabled(subnet) and
subnet['cidr'] !=
lib_constants.PROVISIONAL_IPV6_PD_PREFIX):
pd_intfs.append(intf)
return pd_intfs
def assign_prefix_for_pd_interfaces(router):
pd_intfs = []
for ifno, intf in enumerate(router[lib_constants.INTERFACE_KEY]):

View File

@ -3143,6 +3143,36 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
gw_ifname = ri.get_external_device_name(ri.router['gw_port']['id'])
agent.pd.add_gw_interface(ri.router['id'], gw_ifname)
@mock.patch.object(pd.PrefixDelegation, 'update_subnet')
@mock.patch.object(dibbler.PDDibbler, 'get_prefix', autospec=True)
@mock.patch.object(dibbler.os, 'getpid', return_value=1234)
@mock.patch.object(pd.PrefixDelegation, '_is_lla_active',
return_value=True)
@mock.patch.object(dibbler.os, 'chmod')
@mock.patch.object(dibbler.shutil, 'rmtree')
@mock.patch.object(pd.PrefixDelegation, '_get_sync_data')
def test_pd_have_subnet(self, mock1, mock2, mock3, mock4,
mock_getpid, mock_get_prefix,
mock_pd_update_subnet):
'''Add one pd-enabled subnet that has already been assigned
'''
prefix = '2001:db8:10::/64'
# Initial setup
agent, router, ri = self._pd_setup_agent_router()
# Create one pd-enabled subnet and add router interface
l3_test_common.router_append_pd_enabled_subnet(router, prefix=prefix)
ri.process()
pd_intfs = l3_test_common.get_assigned_pd_interfaces(router)
subnet_id = pd_intfs[0]['subnets'][0]['id']
# Check that _process_pd_iptables_rules() is called correctly
self.assertEqual({subnet_id: prefix}, ri.pd_subnets)
ri._process_pd_iptables_rules.assert_called_once_with(prefix,
subnet_id)
@mock.patch.object(pd.PrefixDelegation, 'update_subnet')
@mock.patch.object(dibbler.PDDibbler, 'get_prefix', autospec=True)
@mock.patch.object(dibbler.os, 'getpid', return_value=1234)
@ -3164,6 +3194,9 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
l3_test_common.router_append_pd_enabled_subnet(router)
ri.process()
# Provisional PD prefix on startup, so nothing cached
self.assertEqual({}, ri.pd_subnets)
# No client should be started since there is no gateway port
self.assertFalse(self.external_process.call_count)
self.assertFalse(mock_get_prefix.call_count)