[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

Conflicts:
  lower-constraints.txt
  requirements.txt

[Stable Only] Since Neutron stable policy do not allow bumping
of minimum version of a requirement in stable releases, so doing
a partial backport by not backporting requirements.txt changes and
updated get_system_dns_resolvers to work with older version of
oslo.utils.

Depends-On: https://review.opendev.org/c/openstack/neutron-tempest-plugin/+/826647
Closes-Bug: #1951816
Change-Id: I9f914e721201072e43a8c6c266ed97ca85fcc13d
(cherry picked from commit 4a06685098)
(cherry picked from commit 4b89ad6403)
This commit is contained in:
yatinkarel 2021-12-23 21:22:35 +05:30 committed by Rodolfo Alonso
parent ee1b021464
commit 6a5aa9b83c
4 changed files with 91 additions and 14 deletions

View File

@ -417,6 +417,9 @@ def get_system_dns_resolvers(resolver_file=DNS_RESOLVER_FILE):
ipv4 = re.search(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}', line)
if ipv4:
resolvers.append(ipv4.group(0))
elif netutils.is_valid_ipv6(line):
resolvers.append(line)
return resolvers
@ -427,12 +430,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

@ -35,7 +35,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):
@ -308,7 +310,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(
@ -327,6 +329,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

@ -2564,6 +2564,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,'
@ -2615,7 +2667,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',
@ -2624,7 +2676,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)
@ -2638,7 +2690,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',
@ -2646,7 +2698,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)
@ -2660,7 +2712,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}
@ -2669,7 +2721,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>`_.