Ensure gateway is set for prefix delegated subnets

With [1] gateway is no longer set for subnet created
with prefix delegation, but when adding the subnet
to the router it fails as it expects gateway to be
set.

This patch ensures gateway is set temporary to the first IP
of the subnet as it used to be just like the temporary CIDR.
Also need to ensure dhcp configuration is skipped to avoid the
original issue[2].

[1] https://review.opendev.org/c/openstack/neutron/+/699465
[2] https://bugs.launchpad.net/neutron/+bug/1856675

Closes-Bug: #1962306
Related-Bug: #1856675
Change-Id: I512f7d98ac99bb0ef06fd2acba09482e3436d18d
This commit is contained in:
yatinkarel 2022-02-28 18:54:26 +05:30
parent 0763d9284a
commit 820b2e2665
9 changed files with 25 additions and 8 deletions

View File

@ -1437,7 +1437,8 @@ class DeviceManager(object):
skip_subnet = (
subnet.ip_version != ip_version or
not subnet.enable_dhcp or
subnet.gateway_ip is None)
subnet.gateway_ip is None or
subnet.subnetpool_id == constants.IPV6_PD_POOL_ID)
if skip_subnet:
continue

View File

@ -160,7 +160,7 @@ class DbBasePluginCommon(object):
'standard_attr_id': standard_attr_id,
}
res['gateway_ip'] = str(
subnet['gateway_ip']) if subnet['gateway_ip'] else None
subnet['gateway_ip']) if subnet['gateway_ip'] is not None else None
# TODO(korzen) this method can get subnet as DB object or Subnet OVO,
# so temporary workaround will be to fill in the fields in separate
# ways. After converting all code pieces to use Subnet OVO, the latter

View File

@ -58,9 +58,6 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon):
if subnet.get('gateway_ip') is const.ATTR_NOT_SPECIFIED:
if subnet.get('ip_version') == const.IP_VERSION_6:
gateway_ip = netaddr.IPNetwork(cidr_net).network
pd_net = netaddr.IPNetwork(const.PROVISIONAL_IPV6_PD_PREFIX)
if gateway_ip == pd_net.network:
return
else:
gateway_ip = netaddr.IPNetwork(cidr_net).network + 1
return str(gateway_ip)

View File

@ -88,7 +88,12 @@ class TestSubnet(base.BaseFullStackTestCase):
ipv6_ra_mode='slaac',
subnetpool_id='prefix_delegation')
subnet = self._show_subnet(subnet['id'])
self.assertIsNone(subnet['subnet']['gateway_ip'])
cidr = subnet['subnet']['cidr']
self.assertEqual(subnet['subnet']['gateway_ip'],
str(netaddr.IPNetwork(cidr).network))
router = self.safe_client.create_router(self._project_id)
self.safe_client.add_router_interface(
router['id'], subnet['subnet']['id'])
def test_create_subnet_ipv4_with_subnetpool(self):
subnetpool_cidr = self.useFixture(

View File

@ -16,6 +16,7 @@ from unittest import mock
from neutron_lib import constants
from oslo_config import cfg
from oslo_utils import uuidutils
from neutron.agent.linux import dhcp
from neutron.agent.linux import ip_lib
@ -47,6 +48,7 @@ class TestDhcp(functional_base.BaseSudoTestCase):
def test_cleanup_stale_devices(self):
plugin = mock.MagicMock()
dev_mgr = dhcp.DeviceManager(self.conf, plugin)
spool_id = uuidutils.generate_uuid()
network = {
'id': 'foo_id',
'project_id': 'foo_project',
@ -57,6 +59,7 @@ class TestDhcp(functional_base.BaseSudoTestCase):
'ipv6_address_mode': None,
'ipv6_ra_mode': None,
'cidr': '10.0.0.0/24',
'subnetpool_id': spool_id,
'ip_version':
constants.IP_VERSION_4,
'gateway_ip': '10.0.0.1'})]}

View File

@ -108,6 +108,7 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
ip_version=lib_const.IP_VERSION_4,
prefix_override=None):
cidr = self._IP_ADDRS[ip_version]['cidr']
spool_id = uuidutils.generate_uuid()
if prefix_override is not None:
cidr = '/'.join((cidr.split('/')[0], str(prefix_override)))
sn_dict = dhcp.DictModel(
@ -115,6 +116,7 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
network_id=net_id,
ip_version=ip_version,
cidr=cidr,
subnetpool_id=spool_id,
gateway_ip=self._IP_ADDRS[ip_version]['gateway'],
enable_dhcp=dhcp_enabled,
dns_nameservers=[],

View File

@ -53,6 +53,8 @@ FAKE_NETWORK_UUID = '12345678-1234-5678-1234567890ab'
FAKE_NETWORK_DHCP_NS = "qdhcp-%s" % FAKE_NETWORK_UUID
FAKE_PROJECT_ID = 'aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa'
FAKE_PRIORITY = 6
FAKE_V4_SUBNETPOOL_ID = 'kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk'
FAKE_V6_SUBNETPOOL_ID = 'jjjjjjjj-jjjj-jjjj-jjjj-jjjjjjjjjjjj'
fake_subnet1_allocation_pools = dhcp.DictModel(id='', start='172.9.9.2',
@ -64,6 +66,7 @@ fake_subnet1 = dhcp.DictModel(id='bbbbbbbb-bbbb-bbbb-bbbbbbbbbbbb',
gateway_ip='172.9.9.1', host_routes=[],
dns_nameservers=[],
ip_version=const.IP_VERSION_4,
subnetpool_id=FAKE_V4_SUBNETPOOL_ID,
ipv6_ra_mode=None, ipv6_address_mode=None,
allocation_pools=fake_subnet1_allocation_pools)
@ -1785,6 +1788,7 @@ class FakeV4Subnet(object):
self.cidr = '192.168.0.0/24'
self.gateway_ip = '192.168.0.1'
self.enable_dhcp = True
self.subnetpool_id = FAKE_V4_SUBNETPOOL_ID
class FakeV6Subnet(object):
@ -1794,6 +1798,7 @@ class FakeV6Subnet(object):
self.cidr = '2001:db8:0:1::/64'
self.gateway_ip = '2001:db8:0:1::1'
self.enable_dhcp = True
self.subnetpool_id = FAKE_V6_SUBNETPOOL_ID
class FakeV4SubnetOutsideGateway(FakeV4Subnet):

View File

@ -436,6 +436,7 @@ class FakeV4Subnet(Dictable):
self.enable_dhcp = True
self.host_routes = [FakeV4HostRoute()]
self.dns_nameservers = ['8.8.8.8']
self.subnetpool_id = 'kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk'
class FakeV4Subnet2(FakeV4Subnet):
@ -563,6 +564,7 @@ class FakeV6Subnet(object):
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
self.ipv6_ra_mode = None
self.ipv6_address_mode = None
self.subnetpool_id = 'jjjjjjjj-jjjj-jjjj-jjjj-jjjjjjjjjjjj'
class FakeV4SubnetNoDHCP(object):
@ -587,6 +589,7 @@ class FakeV6SubnetDHCPStateful(Dictable):
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
self.ipv6_ra_mode = None
self.ipv6_address_mode = constants.DHCPV6_STATEFUL
self.subnetpool_id = 'mmmmmmmm-mmmm-mmmm-mmmm-mmmmmmmmmmmm'
class FakeV6SubnetSlaac(object):

View File

@ -4041,8 +4041,9 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
ipv6_ra_mode=constants.DHCPV6_STATELESS,
ipv6_address_mode=constants.DHCPV6_STATELESS)
# If gateway_ip is not specified and the subnet is using prefix
# delegation, until the CIDR is assigned, this value should be "None"
expected = {'gateway_ip': None,
# delegation, until the CIDR is assigned, this value should be first
# IP from the subnet
expected = {'gateway_ip': str(netaddr.IPNetwork(cidr).network),
'cidr': cidr}
self._test_create_subnet(expected=expected,
cidr=cidr, ip_version=constants.IP_VERSION_6,