From 11cf9f4ae5516d8679cbfa6085cff1566ec4e674 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Tue, 26 Jan 2021 11:22:39 +0100 Subject: [PATCH] Don't configure dnsmasq entries for "network" ports Ports with device_owner like: * floating_ip, * DHCP, * some types of router ports, like: HA interface interface, don't need to be configured in the dnsmasq file. So there is no need to reload dnsmasq every time when such port is added/updated to the network. This patch adds skip in such case which should improve load on the Neutron DHCP agent. Conflicts: neutron/agent/linux/dhcp.py neutron/agent/dhcp/agent.py Closes-Bug: #1913269 Change-Id: I63221507713b941c261cdf88781133149da8ab8d (cherry picked from commit e4bbeee2060058d079885339e99ef7e6e366de16) --- neutron/agent/dhcp/agent.py | 6 ++++++ neutron/agent/linux/dhcp.py | 19 +++++++++++++++++++ neutron/tests/unit/agent/linux/test_dhcp.py | 14 ++++++++++++++ ...r-all-types-of-ports-39c03b3782d2753e.yaml | 6 ++++++ 4 files changed, 45 insertions(+) create mode 100644 releasenotes/notes/do-not-create-dhcp-entries-for-all-types-of-ports-39c03b3782d2753e.yaml diff --git a/neutron/agent/dhcp/agent.py b/neutron/agent/dhcp/agent.py index 41de11542a6..44d5d36428f 100644 --- a/neutron/agent/dhcp/agent.py +++ b/neutron/agent/dhcp/agent.py @@ -535,6 +535,8 @@ class DhcpAgent(manager.Manager): def port_update_end(self, context, payload): """Handle the port.update.end notification event.""" updated_port = dhcp.DictModel(payload['port']) + if not dhcp.port_requires_dhcp_configuration(updated_port): + return if self.cache.is_port_message_stale(updated_port): LOG.debug("Discarding stale port update: %s", updated_port) return @@ -560,6 +562,8 @@ class DhcpAgent(manager.Manager): def reload_allocations(self, port, network, prio=False): LOG.info("Trigger reload_allocations for port %s on network %s", port, network) + if not dhcp.port_requires_dhcp_configuration(port): + return driver_action = 'reload_allocations' if self._is_port_on_this_agent(port): orig = self.cache.get_port_by_id(port['id']) @@ -598,6 +602,8 @@ class DhcpAgent(manager.Manager): def port_create_end(self, context, payload): """Handle the port.create.end notification event.""" created_port = dhcp.DictModel(payload['port']) + if not dhcp.port_requires_dhcp_configuration(created_port): + return update = queue.ResourceUpdate(created_port.network_id, payload.get('priority', DEFAULT_PRIORITY), diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index 7a771a9f1e8..1be761043ee 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -64,6 +64,22 @@ DHCP_RELEASE_TRIES_SLEEP = 0.3 DHCP_OPT_CLIENT_ID_NUM = 61 +def port_requires_dhcp_configuration(port): + if not getattr(port, 'device_owner', None): + # We can't check if port needs dhcp entry, so it will be better + # to create one + return True + # TODO(slaweq): define this list as a constant in neutron_lib.constants + # NOTE(slaweq): Not all port types which belongs e.g. to the routers can be + # excluded from that list. For some of them, like router interfaces used to + # plug subnet to the router should be configured in dnsmasq to provide DNS + # naming resolution. Otherwise it may slowdown e.g. traceroutes from the VM + return port.device_owner not in [ + constants.DEVICE_OWNER_ROUTER_HA_INTF, + constants.DEVICE_OWNER_FLOATINGIP, + constants.DEVICE_OWNER_DHCP] + + class DictModel(dict): """Convert dict into an object that provides attribute access to values.""" @@ -589,6 +605,9 @@ class Dnsmasq(DhcpLocalProcess): if subnet.ip_version == 6) for port in self.network.ports: + if not port_requires_dhcp_configuration(port): + continue + fixed_ips = self._sort_fixed_ips_for_dnsmasq(port.fixed_ips, v6_nets) # Confirm whether Neutron server supports dns_name attribute in the diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index 8f72a5a450e..963e95525c2 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -285,6 +285,19 @@ class FakeRouterPort(object): for ip in self.fixed_ips] +class FakeRouterHAPort(object): + def __init__(self): + self.id = 'hahahaha-haha-haha-haha-hahahahahaha' + self.admin_state_up = True + self.device_owner = constants.DEVICE_OWNER_ROUTER_HA_INTF + self.mac_address = '00:00:0f:aa:aa:aa' + self.device_id = 'fake_router_ha_port' + self.dns_assignment = [] + self.extra_dhcp_opts = [] + self.fixed_ips = [FakeIPAllocation( + '169.254.169.20', 'dddddddd-dddd-dddd-dddd-dddddddddddd')] + + class FakeRouterPortNoDHCP(object): def __init__(self, dev_owner=constants.DEVICE_OWNER_ROUTER_INTF, ip_address='192.168.0.1', domain='openstacklocal'): @@ -671,6 +684,7 @@ class FakeDualNetwork(object): self.namespace = 'qdhcp-ns' self.ports = [FakePort1(domain=domain), FakeV6Port(domain=domain), FakeDualPort(domain=domain), + FakeRouterHAPort(), FakeRouterPort(domain=domain)] diff --git a/releasenotes/notes/do-not-create-dhcp-entries-for-all-types-of-ports-39c03b3782d2753e.yaml b/releasenotes/notes/do-not-create-dhcp-entries-for-all-types-of-ports-39c03b3782d2753e.yaml new file mode 100644 index 00000000000..f921b780c88 --- /dev/null +++ b/releasenotes/notes/do-not-create-dhcp-entries-for-all-types-of-ports-39c03b3782d2753e.yaml @@ -0,0 +1,6 @@ +--- +other: + - | + To improve performance of the DHCP agent, it will no longer configure the DHCP server + for every port type created in Neutron. For example, for floating IP or router HA + interfaces there is no need since a client will not make a DHCP request for them