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
(cherry picked from commit 820b2e2665
)
This commit is contained in:
parent
ca458d9eb9
commit
6f01d45c4a
@ -1429,7 +1429,8 @@ class DeviceManager(object):
|
|||||||
skip_subnet = (
|
skip_subnet = (
|
||||||
subnet.ip_version != ip_version or
|
subnet.ip_version != ip_version or
|
||||||
not subnet.enable_dhcp 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:
|
if skip_subnet:
|
||||||
continue
|
continue
|
||||||
|
@ -160,7 +160,7 @@ class DbBasePluginCommon(object):
|
|||||||
'standard_attr_id': standard_attr_id,
|
'standard_attr_id': standard_attr_id,
|
||||||
}
|
}
|
||||||
res['gateway_ip'] = str(
|
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,
|
# 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
|
# so temporary workaround will be to fill in the fields in separate
|
||||||
# ways. After converting all code pieces to use Subnet OVO, the latter
|
# ways. After converting all code pieces to use Subnet OVO, the latter
|
||||||
|
@ -58,9 +58,6 @@ class IpamBackendMixin(db_base_plugin_common.DbBasePluginCommon):
|
|||||||
if subnet.get('gateway_ip') is const.ATTR_NOT_SPECIFIED:
|
if subnet.get('gateway_ip') is const.ATTR_NOT_SPECIFIED:
|
||||||
if subnet.get('ip_version') == const.IP_VERSION_6:
|
if subnet.get('ip_version') == const.IP_VERSION_6:
|
||||||
gateway_ip = netaddr.IPNetwork(cidr_net).network
|
gateway_ip = netaddr.IPNetwork(cidr_net).network
|
||||||
pd_net = netaddr.IPNetwork(const.PROVISIONAL_IPV6_PD_PREFIX)
|
|
||||||
if gateway_ip == pd_net.network:
|
|
||||||
return
|
|
||||||
else:
|
else:
|
||||||
gateway_ip = netaddr.IPNetwork(cidr_net).network + 1
|
gateway_ip = netaddr.IPNetwork(cidr_net).network + 1
|
||||||
return str(gateway_ip)
|
return str(gateway_ip)
|
||||||
|
@ -87,7 +87,12 @@ class TestSubnet(base.BaseFullStackTestCase):
|
|||||||
ipv6_ra_mode='slaac',
|
ipv6_ra_mode='slaac',
|
||||||
subnetpool_id='prefix_delegation')
|
subnetpool_id='prefix_delegation')
|
||||||
subnet = self._show_subnet(subnet['id'])
|
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):
|
def test_create_subnet_ipv4_with_subnetpool(self):
|
||||||
subnetpool_cidr = self.useFixture(
|
subnetpool_cidr = self.useFixture(
|
||||||
|
@ -16,6 +16,7 @@ from unittest import mock
|
|||||||
|
|
||||||
from neutron_lib import constants
|
from neutron_lib import constants
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from neutron.agent.linux import dhcp
|
from neutron.agent.linux import dhcp
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
@ -47,6 +48,7 @@ class TestDhcp(functional_base.BaseSudoTestCase):
|
|||||||
def test_cleanup_stale_devices(self):
|
def test_cleanup_stale_devices(self):
|
||||||
plugin = mock.MagicMock()
|
plugin = mock.MagicMock()
|
||||||
dev_mgr = dhcp.DeviceManager(self.conf, plugin)
|
dev_mgr = dhcp.DeviceManager(self.conf, plugin)
|
||||||
|
spool_id = uuidutils.generate_uuid()
|
||||||
network = {
|
network = {
|
||||||
'id': 'foo_id',
|
'id': 'foo_id',
|
||||||
'tenant_id': 'foo_tenant',
|
'tenant_id': 'foo_tenant',
|
||||||
@ -57,6 +59,7 @@ class TestDhcp(functional_base.BaseSudoTestCase):
|
|||||||
'ipv6_address_mode': None,
|
'ipv6_address_mode': None,
|
||||||
'ipv6_ra_mode': None,
|
'ipv6_ra_mode': None,
|
||||||
'cidr': '10.0.0.0/24',
|
'cidr': '10.0.0.0/24',
|
||||||
|
'subnetpool_id': spool_id,
|
||||||
'ip_version':
|
'ip_version':
|
||||||
constants.IP_VERSION_4,
|
constants.IP_VERSION_4,
|
||||||
'gateway_ip': '10.0.0.1'})]}
|
'gateway_ip': '10.0.0.1'})]}
|
||||||
|
@ -108,6 +108,7 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
|
|||||||
ip_version=lib_const.IP_VERSION_4,
|
ip_version=lib_const.IP_VERSION_4,
|
||||||
prefix_override=None):
|
prefix_override=None):
|
||||||
cidr = self._IP_ADDRS[ip_version]['cidr']
|
cidr = self._IP_ADDRS[ip_version]['cidr']
|
||||||
|
spool_id = uuidutils.generate_uuid()
|
||||||
if prefix_override is not None:
|
if prefix_override is not None:
|
||||||
cidr = '/'.join((cidr.split('/')[0], str(prefix_override)))
|
cidr = '/'.join((cidr.split('/')[0], str(prefix_override)))
|
||||||
sn_dict = dhcp.DictModel(
|
sn_dict = dhcp.DictModel(
|
||||||
@ -115,6 +116,7 @@ class DHCPAgentOVSTestFramework(base.BaseSudoTestCase):
|
|||||||
network_id=net_id,
|
network_id=net_id,
|
||||||
ip_version=ip_version,
|
ip_version=ip_version,
|
||||||
cidr=cidr,
|
cidr=cidr,
|
||||||
|
subnetpool_id=spool_id,
|
||||||
gateway_ip=self._IP_ADDRS[ip_version]['gateway'],
|
gateway_ip=self._IP_ADDRS[ip_version]['gateway'],
|
||||||
enable_dhcp=dhcp_enabled,
|
enable_dhcp=dhcp_enabled,
|
||||||
dns_nameservers=[],
|
dns_nameservers=[],
|
||||||
|
@ -53,6 +53,8 @@ FAKE_NETWORK_UUID = '12345678-1234-5678-1234567890ab'
|
|||||||
FAKE_NETWORK_DHCP_NS = "qdhcp-%s" % FAKE_NETWORK_UUID
|
FAKE_NETWORK_DHCP_NS = "qdhcp-%s" % FAKE_NETWORK_UUID
|
||||||
FAKE_TENANT_ID = 'aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
FAKE_TENANT_ID = 'aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa'
|
||||||
FAKE_PRIORITY = 6
|
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',
|
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=[],
|
gateway_ip='172.9.9.1', host_routes=[],
|
||||||
dns_nameservers=[],
|
dns_nameservers=[],
|
||||||
ip_version=const.IP_VERSION_4,
|
ip_version=const.IP_VERSION_4,
|
||||||
|
subnetpool_id=FAKE_V4_SUBNETPOOL_ID,
|
||||||
ipv6_ra_mode=None, ipv6_address_mode=None,
|
ipv6_ra_mode=None, ipv6_address_mode=None,
|
||||||
allocation_pools=fake_subnet1_allocation_pools)
|
allocation_pools=fake_subnet1_allocation_pools)
|
||||||
|
|
||||||
@ -1744,6 +1747,7 @@ class FakeV4Subnet(object):
|
|||||||
self.cidr = '192.168.0.0/24'
|
self.cidr = '192.168.0.0/24'
|
||||||
self.gateway_ip = '192.168.0.1'
|
self.gateway_ip = '192.168.0.1'
|
||||||
self.enable_dhcp = True
|
self.enable_dhcp = True
|
||||||
|
self.subnetpool_id = FAKE_V4_SUBNETPOOL_ID
|
||||||
|
|
||||||
|
|
||||||
class FakeV6Subnet(object):
|
class FakeV6Subnet(object):
|
||||||
@ -1753,6 +1757,7 @@ class FakeV6Subnet(object):
|
|||||||
self.cidr = '2001:db8:0:1::/64'
|
self.cidr = '2001:db8:0:1::/64'
|
||||||
self.gateway_ip = '2001:db8:0:1::1'
|
self.gateway_ip = '2001:db8:0:1::1'
|
||||||
self.enable_dhcp = True
|
self.enable_dhcp = True
|
||||||
|
self.subnetpool_id = FAKE_V6_SUBNETPOOL_ID
|
||||||
|
|
||||||
|
|
||||||
class FakeV4SubnetOutsideGateway(FakeV4Subnet):
|
class FakeV4SubnetOutsideGateway(FakeV4Subnet):
|
||||||
|
@ -436,6 +436,7 @@ class FakeV4Subnet(Dictable):
|
|||||||
self.enable_dhcp = True
|
self.enable_dhcp = True
|
||||||
self.host_routes = [FakeV4HostRoute()]
|
self.host_routes = [FakeV4HostRoute()]
|
||||||
self.dns_nameservers = ['8.8.8.8']
|
self.dns_nameservers = ['8.8.8.8']
|
||||||
|
self.subnetpool_id = 'kkkkkkkk-kkkk-kkkk-kkkk-kkkkkkkkkkkk'
|
||||||
|
|
||||||
|
|
||||||
class FakeV4Subnet2(FakeV4Subnet):
|
class FakeV4Subnet2(FakeV4Subnet):
|
||||||
@ -563,6 +564,7 @@ class FakeV6Subnet(object):
|
|||||||
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
|
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
|
||||||
self.ipv6_ra_mode = None
|
self.ipv6_ra_mode = None
|
||||||
self.ipv6_address_mode = None
|
self.ipv6_address_mode = None
|
||||||
|
self.subnetpool_id = 'jjjjjjjj-jjjj-jjjj-jjjj-jjjjjjjjjjjj'
|
||||||
|
|
||||||
|
|
||||||
class FakeV4SubnetNoDHCP(object):
|
class FakeV4SubnetNoDHCP(object):
|
||||||
@ -587,6 +589,7 @@ class FakeV6SubnetDHCPStateful(Dictable):
|
|||||||
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
|
self.dns_nameservers = ['2001:0200:feed:7ac0::1']
|
||||||
self.ipv6_ra_mode = None
|
self.ipv6_ra_mode = None
|
||||||
self.ipv6_address_mode = constants.DHCPV6_STATEFUL
|
self.ipv6_address_mode = constants.DHCPV6_STATEFUL
|
||||||
|
self.subnetpool_id = 'mmmmmmmm-mmmm-mmmm-mmmm-mmmmmmmmmmmm'
|
||||||
|
|
||||||
|
|
||||||
class FakeV6SubnetSlaac(object):
|
class FakeV6SubnetSlaac(object):
|
||||||
|
@ -3971,8 +3971,9 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
|
|||||||
ipv6_ra_mode=constants.DHCPV6_STATELESS,
|
ipv6_ra_mode=constants.DHCPV6_STATELESS,
|
||||||
ipv6_address_mode=constants.DHCPV6_STATELESS)
|
ipv6_address_mode=constants.DHCPV6_STATELESS)
|
||||||
# If gateway_ip is not specified and the subnet is using prefix
|
# If gateway_ip is not specified and the subnet is using prefix
|
||||||
# delegation, until the CIDR is assigned, this value should be "None"
|
# delegation, until the CIDR is assigned, this value should be first
|
||||||
expected = {'gateway_ip': None,
|
# IP from the subnet
|
||||||
|
expected = {'gateway_ip': str(netaddr.IPNetwork(cidr).network),
|
||||||
'cidr': cidr}
|
'cidr': cidr}
|
||||||
self._test_create_subnet(expected=expected,
|
self._test_create_subnet(expected=expected,
|
||||||
cidr=cidr, ip_version=constants.IP_VERSION_6,
|
cidr=cidr, ip_version=constants.IP_VERSION_6,
|
||||||
|
Loading…
Reference in New Issue
Block a user