diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index 0f17aa4337e..8484ec1e91f 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -875,6 +875,11 @@ class Dnsmasq(DhcpLocalProcess): str(DHCP_OPT_CLIENT_ID_NUM)): return opt.opt_value + @staticmethod + def _parse_ip_addresses(ip_list): + ip_list = [ip.strip('[]') for ip in ip_list] + return [ip for ip in ip_list if netutils.is_valid_ip(ip)] + def _read_hosts_file_leases(self, filename): leases = set() try: @@ -886,11 +891,14 @@ class Dnsmasq(DhcpLocalProcess): if host[1].startswith('set:'): continue if host[1].startswith(self._ID): - ip = host[3].strip('[]') + ips = self._parse_ip_addresses(host[3:]) client_id = host[1][len(self._ID):] + elif host[1].startswith('tag:'): + ips = self._parse_ip_addresses(host[3:]) else: - ip = host[2].strip('[]') - leases.add((ip, mac, client_id)) + ips = self._parse_ip_addresses(host[2:]) + for ip in ips: + leases.add((ip, mac, client_id)) except (OSError, IOError): LOG.debug('Error while reading hosts file %s', filename) return leases diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index 52479c02189..ca1d8c23176 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -2572,51 +2572,57 @@ class TestDnsmasq(TestBase): def test_release_unused_leases_one_lease_mult_times_removed(self): self._test_release_unused_leases_one_lease_mult_times(True) - def test_read_hosts_file_leases(self): + def test__parse_ip_addresses(self): + ip_list = ['192.168.0.1', '[fdca:3ba5:a17a::1]', 'no_ip_address'] + self.assertEqual(['192.168.0.1', 'fdca:3ba5:a17a::1'], + dhcp.Dnsmasq._parse_ip_addresses(ip_list)) + + def _test_read_hosts_file_leases(self, lines, expected_result): filename = '/path/to/file' - lines = ["00:00:80:aa:bb:cc,inst-name,192.168.0.1", - "00:00:80:aa:bb:cc,inst-name,[fdca:3ba5:a17a::1]"] mock_open = self.useFixture( lib_fixtures.OpenFixture(filename, '\n'.join(lines))).mock_open dnsmasq = self._get_dnsmasq(FakeDualNetwork()) leases = dnsmasq._read_hosts_file_leases(filename) - - self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", None), - ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", - None)]), leases) + self.assertEqual(expected_result, leases) mock_open.assert_called_once_with(filename) + def test_read_hosts_file_leases(self): + lines = ["00:00:80:aa:bb:cc,inst-name,192.168.0.1", + "00:00:80:aa:bb:cc,inst-name,[fdca:3ba5:a17a::1]"] + result = {("192.168.0.1", "00:00:80:aa:bb:cc", None), + ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", None)} + self._test_read_hosts_file_leases(lines, result) + def test_read_hosts_file_leases_with_client_id(self): - filename = '/path/to/file' lines = ["00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1", "00:00:80:aa:bb:cc,id:client2,inst-name," "[fdca:3ba5:a17a::1]"] - mock_open = self.useFixture( - lib_fixtures.OpenFixture(filename, '\n'.join(lines))).mock_open - dnsmasq = self._get_dnsmasq(FakeDualNetwork()) - leases = dnsmasq._read_hosts_file_leases(filename) - - self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'), - ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", - 'client2')]), leases) - mock_open.assert_called_once_with(filename) + result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'), + ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", 'client2')} + self._test_read_hosts_file_leases(lines, result) def test_read_hosts_file_leases_with_stateless_IPv6_tag(self): - filename = self.get_temp_file_path('leases') - with open(filename, "w") as leasesfile: - lines = [ - "00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1\n", - "00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc\n", - "00:00:80:aa:bb:cc,id:client2,inst-name,[fdca:3ba5:a17a::1]\n"] - for line in lines: - leasesfile.write(line) + lines = [ + "00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1", + "00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc", + "00:00:80:aa:bb:cc,id:client2,inst-name,[fdca:3ba5:a17a::1]"] + result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'), + ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", 'client2')} + self._test_read_hosts_file_leases(lines, result) - dnsmasq = self._get_dnsmasq(FakeDualNetwork()) - leases = dnsmasq._read_hosts_file_leases(filename) - - self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'), - ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", - 'client2')]), leases) + def test_read_hosts_file_leases_with_IPv6_tag_and_multiple_ips(self): + lines = [ + "00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1", + "00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc", + "00:00:80:aa:bb:cc,tag:dhcpv6,inst-name,[fdca:3ba5:a17a::1]," + "[fdca:3ba5:a17a::2],[fdca:3ba5:a17a::3],[fdca:3ba5:a17a::4]," + "set:port-fe2baee9-aba9-4b67-be03-be4aeee40cca"] + result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'), + ("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", None), + ("fdca:3ba5:a17a::2", "00:00:80:aa:bb:cc", None), + ("fdca:3ba5:a17a::3", "00:00:80:aa:bb:cc", None), + ("fdca:3ba5:a17a::4", "00:00:80:aa:bb:cc", None)} + self._test_read_hosts_file_leases(lines, result) def _test_read_leases_file_leases(self, ip_version, add_bad_line=False): filename = '/path/to/file'