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

Closes-Bug: #1913269
Change-Id: I63221507713b941c261cdf88781133149da8ab8d
(cherry picked from commit e4bbeee206)
This commit is contained in:
Slawek Kaplonski 2021-01-26 11:22:39 +01:00
parent 526bb04096
commit 3a880b8495
4 changed files with 45 additions and 0 deletions

View File

@ -564,6 +564,8 @@ class DhcpAgent(manager.Manager):
def port_update_end(self, context, payload): def port_update_end(self, context, payload):
"""Handle the port.update.end notification event.""" """Handle the port.update.end notification event."""
updated_port = dhcp.DictModel(payload['port']) 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): if self.cache.is_port_message_stale(updated_port):
LOG.debug("Discarding stale port update: %s", updated_port) LOG.debug("Discarding stale port update: %s", updated_port)
return return
@ -588,6 +590,8 @@ class DhcpAgent(manager.Manager):
def reload_allocations(self, port, network, prio=False): def reload_allocations(self, port, network, prio=False):
LOG.info("Trigger reload_allocations for port %s on network %s", LOG.info("Trigger reload_allocations for port %s on network %s",
port, network) port, network)
if not dhcp.port_requires_dhcp_configuration(port):
return
driver_action = 'reload_allocations' driver_action = 'reload_allocations'
if self._is_port_on_this_agent(port): if self._is_port_on_this_agent(port):
orig = self.cache.get_port_by_id(port['id']) orig = self.cache.get_port_by_id(port['id'])
@ -626,6 +630,8 @@ class DhcpAgent(manager.Manager):
def port_create_end(self, context, payload): def port_create_end(self, context, payload):
"""Handle the port.create.end notification event.""" """Handle the port.create.end notification event."""
created_port = dhcp.DictModel(payload['port']) created_port = dhcp.DictModel(payload['port'])
if not dhcp.port_requires_dhcp_configuration(created_port):
return
update = DHCPResourceUpdate(created_port.network_id, update = DHCPResourceUpdate(created_port.network_id,
payload.get('priority', DEFAULT_PRIORITY), payload.get('priority', DEFAULT_PRIORITY),
action='_port_create', action='_port_create',

View File

@ -65,6 +65,22 @@ HOST_DHCPV6_TAG = 'tag:dhcpv6,'
DHCP_OPT_CLIENT_ID_NUM = 61 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): class DictModel(dict):
"""Convert dict into an object that provides attribute access to values.""" """Convert dict into an object that provides attribute access to values."""
@ -681,6 +697,9 @@ class Dnsmasq(DhcpLocalProcess):
if subnet.ip_version == 6) if subnet.ip_version == 6)
for port in self.network.ports: 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, fixed_ips = self._sort_fixed_ips_for_dnsmasq(port.fixed_ips,
v6_nets) v6_nets)
# TODO(hjensas): Drop this conditional and option once distros # TODO(hjensas): Drop this conditional and option once distros

View File

@ -305,6 +305,19 @@ class FakeRouterPort(object):
for ip in self.fixed_ips] 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): class FakeRouterPortNoDHCP(object):
def __init__(self, dev_owner=constants.DEVICE_OWNER_ROUTER_INTF, def __init__(self, dev_owner=constants.DEVICE_OWNER_ROUTER_INTF,
ip_address='192.168.0.1', domain='openstacklocal'): ip_address='192.168.0.1', domain='openstacklocal'):
@ -691,6 +704,7 @@ class FakeDualNetwork(object):
self.namespace = 'qdhcp-ns' self.namespace = 'qdhcp-ns'
self.ports = [FakePort1(domain=domain), FakeV6Port(domain=domain), self.ports = [FakePort1(domain=domain), FakeV6Port(domain=domain),
FakeDualPort(domain=domain), FakeDualPort(domain=domain),
FakeRouterHAPort(),
FakeRouterPort(domain=domain)] FakeRouterPort(domain=domain)]

View File

@ -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