diff --git a/lower-constraints.txt b/lower-constraints.txt index fced365ba80..4a9c97e6204 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -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 diff --git a/neutron/common/ovn/utils.py b/neutron/common/ovn/utils.py index aee875e9f57..835dce0bc47 100644 --- a/neutron/common/ovn/utils.py +++ b/neutron/common/ovn/utils.py @@ -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 [] diff --git a/neutron/tests/unit/common/ovn/test_utils.py b/neutron/tests/unit/common/ovn/test_utils.py index 85a9d098b11..d6b71dcd87b 100644 --- a/neutron/tests/unit/common/ovn/test_utils.py +++ b/neutron/tests/unit/common/ovn/test_utils.py @@ -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', '::']}, diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py index 996974b1bd1..0042ebbb16a 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py @@ -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, diff --git a/releasenotes/notes/ovn-default-dns-servers-ipv6-subnets-f2d525abc70b01b3.yaml b/releasenotes/notes/ovn-default-dns-servers-ipv6-subnets-f2d525abc70b01b3.yaml new file mode 100644 index 00000000000..db60b0d176c --- /dev/null +++ b/releasenotes/notes/ovn-default-dns-servers-ipv6-subnets-f2d525abc70b01b3.yaml @@ -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 `_. diff --git a/requirements.txt b/requirements.txt index 840b5a63173..117fbe45283 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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