diff --git a/neutron/agent/dhcp/agent.py b/neutron/agent/dhcp/agent.py index 5b2b5dd036f..38cb6717723 100644 --- a/neutron/agent/dhcp/agent.py +++ b/neutron/agent/dhcp/agent.py @@ -541,11 +541,14 @@ class DhcpAgent(manager.Manager): return new_ips = {i['ip_address'] for i in created_port['fixed_ips']} for port_cached in network.ports: - # if there are other ports cached with the same ip address in - # the same network this indicate that the cache is out of sync + # if in the same network there are ports cached with the same + # ip address but different MAC address and/or different id, + # this indicate that the cache is out of sync cached_ips = {i['ip_address'] for i in port_cached['fixed_ips']} - if new_ips.intersection(cached_ips): + if (new_ips.intersection(cached_ips) and + (created_port['id'] != port_cached['id'] or + created_port['mac_address'] != port_cached['mac_address'])): self.schedule_resync("Duplicate IP addresses found, " "DHCP cache is out of sync", created_port.network_id) diff --git a/neutron/tests/unit/agent/dhcp/test_agent.py b/neutron/tests/unit/agent/dhcp/test_agent.py index 3139a15a05a..62764f7a603 100644 --- a/neutron/tests/unit/agent/dhcp/test_agent.py +++ b/neutron/tests/unit/agent/dhcp/test_agent.py @@ -1137,6 +1137,21 @@ class TestDhcpAgentEventHandler(base.BaseTestCase): self.reload_allocations.assert_called_once_with(fake_port2, fake_network) + def test_port_create_end_no_resync_if_same_port_already_in_cache(self): + self.reload_allocations_p = mock.patch.object(self.dhcp, + 'reload_allocations') + self.reload_allocations = self.reload_allocations_p.start() + payload = dict(port=copy.deepcopy(fake_port2)) + cached_port = copy.deepcopy(fake_port2) + new_fake_network = copy.deepcopy(fake_network) + new_fake_network.ports = [cached_port] + self.cache.get_network_by_id.return_value = new_fake_network + self.dhcp.port_create_end(None, payload) + self.dhcp._process_resource_update() + self.reload_allocations.assert_called_once_with(fake_port2, + new_fake_network) + self.schedule_resync.assert_not_called() + def test_port_update_change_ip_on_port(self): payload = dict(port=fake_port1, priority=FAKE_PRIORITY) self.cache.get_network_by_id.return_value = fake_network