[OVN] Correctly set dns_server in dhcpv4/v6 options

When ovn/dns_servers consist of IPv6 dns nameservers,
it was getting added to IPv4 dhcp options also, and due to
this an invalid nameserver(last 4 octets of an IPv6 address)
is set in the instances.

This patch filters IPv4/IPv6 dns nameservers and set
dhcpv4/dhcpv6 options accordingly.

Also when dns_nameservers are not set for IPv6 subnets,
get those from ovn/dns_servers config or system nameservers
just like it's done with the IPv4 subnets. Updated
get_system_dns_resolvers to pick both IPv4/IPv6 valid
ips, this also requires bump of oslo.utils minimum version
to 4.8.0 to use strict option for IPv4[1].

Additionally fix some unit tests which were setting IPv4 dns
nameservers on the IPv6 subnets, this is not allowed with api.

[1] https://github.com/openstack/oslo.utils/commit/3288539

Closes-Bug: #1951816
Change-Id: I9f914e721201072e43a8c6c266ed97ca85fcc13d
This commit is contained in:
yatinkarel 2021-12-23 21:22:35 +05:30
parent 7aba1bddab
commit 4a06685098
6 changed files with 95 additions and 19 deletions

View File

@ -74,7 +74,7 @@ oslo.rootwrap==5.15.0
oslo.serialization==2.25.0
oslo.service==1.31.0
oslo.upgradecheck==1.3.0
oslo.utils==4.5.0
oslo.utils==4.8.0
oslo.versionedobjects==1.35.1
oslotest==3.2.0
osprofiler==2.3.0

View File

@ -410,9 +410,11 @@ def get_system_dns_resolvers(resolver_file=DNS_RESOLVER_FILE):
continue
line = line.split('nameserver')[1].strip()
ipv4 = re.search(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)
if ipv4:
resolvers.append(ipv4.group(0))
valid_ip = (netutils.is_valid_ipv4(line, strict=True) or
netutils.is_valid_ipv6(line))
if valid_ip:
resolvers.append(line)
return resolvers
@ -423,12 +425,13 @@ def get_dhcp_dns_servers(subnet, ip_version=const.IP_VERSION_4):
configured DNS server is "0.0.0.0" (IPv4) or "::" (IPv6).
https://docs.openstack.org/neutron/latest/admin/config-dns-res.html
"""
if ip_version == const.IP_VERSION_4:
dns_servers = (subnet.get('dns_nameservers') or
ovn_conf.get_dns_servers() or
get_system_dns_resolvers())
else:
dns_servers = subnet['dns_nameservers']
def filter_ips(ips, ip_version=const.IP_VERSION_4):
return [ip for ip in ips
if netaddr.IPAddress(ip).version == ip_version]
dns_servers = (subnet.get('dns_nameservers') or
filter_ips(ovn_conf.get_dns_servers(), ip_version) or
filter_ips(get_system_dns_resolvers(), ip_version))
if common_utils.is_dns_servers_any_address(dns_servers, ip_version):
return []

View File

@ -36,7 +36,9 @@ nameserver foo 10.0.0.4
nameserver aef0::4
foo 10.0.0.5
"""
RESOLV_DNS_SERVERS = ['10.0.0.1', '10.0.0.3']
RESOLV_DNS_SERVERS = ['10.0.0.1', '10.0.0.3', 'aef0::4']
RESOLV_DNS_SERVERS_V4 = ['10.0.0.1', '10.0.0.3']
RESOLV_DNS_SERVERS_V6 = ['aef0::4']
class TestUtils(base.BaseTestCase):
@ -405,7 +407,7 @@ class TestGetDhcpDnsServers(base.BaseTestCase):
mock.mock_open(read_data=RESOLV_CONF_TEMPLATE)), \
mock.patch.object(path, 'exists', return_value=True):
dns_servers = utils.get_dhcp_dns_servers({})
self.assertEqual(RESOLV_DNS_SERVERS, dns_servers)
self.assertEqual(RESOLV_DNS_SERVERS_V4, dns_servers)
# No DNS servers if only '0.0.0.0' configured.
dns_servers = utils.get_dhcp_dns_servers(
@ -424,6 +426,14 @@ class TestGetDhcpDnsServers(base.BaseTestCase):
self.assertEqual(['2001:4860:4860::8888',
'2001:4860:4860::8844'], dns_servers)
# DNS servers from local DNS resolver.
cfg.CONF.set_override('dns_servers', '', group='ovn')
with mock.patch('builtins.open',
mock.mock_open(read_data=RESOLV_CONF_TEMPLATE)), \
mock.patch.object(path, 'exists', return_value=True):
dns_servers = utils.get_dhcp_dns_servers({}, ip_version=6)
self.assertEqual(RESOLV_DNS_SERVERS_V6, dns_servers)
# No DNS servers if only '::' configured.
dns_servers = utils.get_dhcp_dns_servers(
{'dns_nameservers': ['2001:4860:4860::8888', '::']},

View File

@ -2725,6 +2725,58 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
self._test_get_ovn_dhcp_options_helper(subnet, network,
expected_dhcp_options)
def test_get_ovn_dhcpv4_options_ovn_conf_ip4_ip6_dns(self):
ovn_conf.cfg.CONF.set_override('dns_servers',
'8.8.8.8,2001:db8::8888',
group='ovn')
subnet = {'id': 'foo-subnet', 'network_id': 'network-id',
'cidr': '10.0.0.0/24',
'ip_version': 4,
'enable_dhcp': True,
'host_routes': [],
'gateway_ip': '10.0.0.1'}
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcpv4_options = {'cidr': subnet['cidr'],
'external_ids': {
'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}}
expected_dhcpv4_options['options'] = {
'server_id': subnet['gateway_ip'],
'server_mac': '01:02:03:04:05:06',
'lease_time': str(12 * 60 * 60),
'mtu': str(network['mtu']),
'router': subnet['gateway_ip'],
'dns_server': '{8.8.8.8}'
}
self._test_get_ovn_dhcp_options_helper(subnet, network,
expected_dhcpv4_options)
def test_get_ovn_dhcpv6_options_ovn_conf_ip4_ip6_dns(self):
ovn_conf.cfg.CONF.set_override('dns_servers',
'8.8.8.8,2001:db8::8888',
group='ovn')
subnet = {'id': 'foo-subnet', 'network_id': 'network-id',
'cidr': '2001:db8::/64',
'ip_version': 6,
'enable_dhcp': True,
'host_routes': [],
'gateway_ip': '2001:db8::1'}
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcpv6_options = {'cidr': subnet['cidr'],
'external_ids': {
'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}}
expected_dhcpv6_options['options'] = {
'server_id': '01:02:03:04:05:06',
'dns_server': '{2001:db8::8888}'
}
self._test_get_ovn_dhcp_options_helper(subnet, network,
expected_dhcpv6_options)
def test_get_ovn_dhcp_options_with_global_options(self):
ovn_conf.cfg.CONF.set_override('ovn_dhcp4_global_options',
'ntp_server:8.8.8.8,'
@ -2776,7 +2828,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
'cidr': 'ae70::/24',
'ip_version': 6,
'enable_dhcp': True,
'dns_nameservers': ['7.7.7.7', '8.8.8.8']}
'dns_nameservers': ['2001:db8::4444', '2001:db8::8888']}
network = {'id': 'network-id', 'mtu': 1400}
ext_ids = {'subnet_id': 'foo-subnet',
@ -2785,7 +2837,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
'cidr': 'ae70::/24', 'external_ids': ext_ids,
'options': {'server_id': '01:02:03:04:05:06',
'ntp_server': '8.8.8.8',
'dns_server': '{7.7.7.7, 8.8.8.8}'}}
'dns_server': '{2001:db8::4444, 2001:db8::8888}'}}
self._test_get_ovn_dhcp_options_helper(subnet, network,
expected_dhcp_options)
@ -2799,7 +2851,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
'cidr': 'ae70::/24',
'ip_version': 6,
'enable_dhcp': True,
'dns_nameservers': ['7.7.7.7', '8.8.8.8']}
'dns_nameservers': ['2001:db8::4444', '2001:db8::8888']}
network = {'id': 'network-id', 'mtu': 1400}
ext_ids = {'subnet_id': 'foo-subnet',
@ -2807,7 +2859,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
expected_dhcp_options = {
'cidr': 'ae70::/24', 'external_ids': ext_ids,
'options': {'server_id': '01:02:03:04:05:06',
'dns_server': '{7.7.7.7, 8.8.8.8}'}}
'dns_server': '{2001:db8::4444, 2001:db8::8888}'}}
self._test_get_ovn_dhcp_options_helper(subnet, network,
expected_dhcp_options)
@ -2821,7 +2873,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
'cidr': 'ae70::/24',
'ip_version': 6,
'enable_dhcp': True,
'dns_nameservers': ['7.7.7.7', '8.8.8.8'],
'dns_nameservers': ['2001:db8::4444', '2001:db8::8888'],
'ipv6_address_mode': const.DHCPV6_STATELESS}
network = {'id': 'network-id', 'mtu': 1400}
@ -2830,7 +2882,7 @@ class TestOVNMechanismDriverDHCPOptions(OVNMechanismDriverTestCase):
expected_dhcp_options = {
'cidr': 'ae70::/24', 'external_ids': ext_ids,
'options': {'server_id': '01:02:03:04:05:06',
'dns_server': '{7.7.7.7, 8.8.8.8}',
'dns_server': '{2001:db8::4444, 2001:db8::8888}',
'dhcpv6_stateless': 'true'}}
self._test_get_ovn_dhcp_options_helper(subnet, network,

View File

@ -0,0 +1,11 @@
---
fixes:
- |
For IPv4 subnets when dns_nameservers is not set in the subnet,
servers defined in 'ovn/dns_servers' config option or system's
resolv.conf are used, but for IPv6 subnets these are
not used. The same will now be used for IPv6 subnets too.
Additionally dns servers added in 'ovn/dns_servers' config
option or system's resolv.conf will be filtered as per
the subnet's IP version. For more info see the bug report
`1951816 <https://bugs.launchpad.net/neutron/+bug/1951816>`_.

View File

@ -40,7 +40,7 @@ oslo.rootwrap>=5.15.0 # Apache-2.0
oslo.serialization>=2.25.0 # Apache-2.0
oslo.service>=1.31.0 # Apache-2.0
oslo.upgradecheck>=1.3.0 # Apache-2.0
oslo.utils>=4.5.0 # Apache-2.0
oslo.utils>=4.8.0 # Apache-2.0
oslo.versionedobjects>=1.35.1 # Apache-2.0
osprofiler>=2.3.0 # Apache-2.0
os-ken>=2.2.0 # Apache-2.0