DVR: Ignore DHCP port during DVR host query

For large scale deployment, the dvr router will be installed to
the scheduled DHCP host. This will definitely increase the l3
agent service pressure, especially in large number of concurrent
updates, creation, or agent restart.

This patch adds a config ``host_dvr_for_dhcp`` for the DHCP port
device_owner filter during DVR host query. Then if we set
``host_dvr_for_dhcp = False``, L3-agent will not host the DVR router
namespace in its connected networks' DHCP agent hosts.

Closes-Bug: #1609217
Change-Id: I53e20be9b306bf9d3b34ec6a31e3afabd5a0fd6f
(cherry picked from commit 8f057fb49a)
This commit is contained in:
LIU Yulong 2016-08-19 10:16:44 +08:00 committed by norman shen
parent ec395e44e6
commit 50fdc6505f
6 changed files with 40 additions and 9 deletions

View File

@ -75,6 +75,15 @@ Controller node
[DEFAULT]
router_distributed = True
.. note::
For a large scale cloud, if your deployment is running DVR with DHCP,
we recommend you set ``host_dvr_for_dhcp=False`` to achieve higher
L3 agent router processing performance. When this is set to False,
DNS functionality will not be available via the DHCP namespace (dnsmasq)
however, a different nameserver will have to be configured, for
example, by specifying a value in ``dns_nameservers`` for subnets.
#. Restart the following services:
* Server

View File

@ -162,16 +162,18 @@ class exception_logger(object):
return call
def get_other_dvr_serviced_device_owners():
def get_other_dvr_serviced_device_owners(host_dvr_for_dhcp=True):
"""Return device_owner names for ports that should be serviced by DVR
This doesn't return DEVICE_OWNER_COMPUTE_PREFIX since it is a
prefix, not a complete device_owner name, so should be handled
separately (see is_dvr_serviced() below)
"""
return [n_const.DEVICE_OWNER_LOADBALANCER,
n_const.DEVICE_OWNER_LOADBALANCERV2,
n_const.DEVICE_OWNER_DHCP]
device_owners = [n_const.DEVICE_OWNER_LOADBALANCER,
n_const.DEVICE_OWNER_LOADBALANCERV2]
if host_dvr_for_dhcp:
device_owners.append(n_const.DEVICE_OWNER_DHCP)
return device_owners
def get_dvr_allowed_address_pair_device_owners():

View File

@ -25,6 +25,12 @@ ROUTER_DISTRIBUTED_OPTS = [
default=True,
help=_("Determine if setup is configured for DVR. If False, "
"DVR API extension will be disabled.")),
cfg.BoolOpt('host_dvr_for_dhcp',
default=True,
help=_("Flag to determine if hosting a DVR local router to "
"the DHCP agent is desired. If False, any L3 function "
"supported by the DHCP agent instance will not be "
"possible, for instance: DNS.")),
]

View File

@ -33,6 +33,7 @@ from sqlalchemy import or_
from neutron.common import utils
from neutron.conf.db import dvr_mac_db
from neutron.conf.db import l3_dvr_db
from neutron.db import models_v2
from neutron.extensions import dvr as ext_dvr
from neutron.objects import router
@ -42,6 +43,7 @@ LOG = logging.getLogger(__name__)
dvr_mac_db.register_db_dvr_mac_opts()
l3_dvr_db.register_db_l3_dvr_opts()
@registry.has_registry_receivers
@ -151,6 +153,7 @@ class DVRDbMixin(ext_dvr.DVRMacAddressPluginBase):
:param subnet: subnet id to match and extract ports of interest
:returns: list -- Ports on the given subnet in the input host
"""
host_dvr_for_dhcp = cfg.CONF.host_dvr_for_dhcp
filters = {'fixed_ips': {'subnet_id': [subnet]},
portbindings.HOST_ID: [host]}
ports_query = self.plugin._get_ports_query(context, filters=filters)
@ -158,7 +161,7 @@ class DVRDbMixin(ext_dvr.DVRMacAddressPluginBase):
models_v2.Port.device_owner.startswith(
constants.DEVICE_OWNER_COMPUTE_PREFIX),
models_v2.Port.device_owner.in_(
utils.get_other_dvr_serviced_device_owners()))
utils.get_other_dvr_serviced_device_owners(host_dvr_for_dhcp)))
ports_query = ports_query.filter(owner_filter)
ports = [
self.plugin._make_port_dict(port, process_extensions=False)

View File

@ -22,11 +22,12 @@ from neutron_lib import constants as n_const
from neutron_lib.exceptions import l3 as l3_exc
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import log as logging
from sqlalchemy import or_
from neutron.common import utils as n_utils
from neutron.conf.db import l3_dvr_db as l3_dvr_db_conf
from neutron.db import agentschedulers_db
from neutron.db import l3_agentschedulers_db as l3agent_sch_db
from neutron.db import l3_dvr_db
@ -37,6 +38,7 @@ from neutron.plugins.ml2 import db as ml2_db
from neutron.plugins.ml2 import models as ml2_models
LOG = logging.getLogger(__name__)
l3_dvr_db_conf.register_db_l3_dvr_opts()
class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
@ -334,6 +336,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
def _get_dvr_hosts_for_subnets(self, context, subnet_ids):
"""Get a list of hosts with DVR servicable ports on subnet_ids."""
host_dvr_dhcp = cfg.CONF.host_dvr_for_dhcp
Binding = ml2_models.PortBinding
Port = models_v2.Port
IPAllocation = models_v2.IPAllocation
@ -345,12 +348,13 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
owner_filter = or_(
Port.device_owner.startswith(n_const.DEVICE_OWNER_COMPUTE_PREFIX),
Port.device_owner.in_(
n_utils.get_other_dvr_serviced_device_owners()))
n_utils.get_other_dvr_serviced_device_owners(host_dvr_dhcp)))
query = query.filter(owner_filter)
hosts = [item[0] for item in query if item[0] != '']
return hosts
def _get_dvr_subnet_ids_on_host_query(self, context, host):
host_dvr_dhcp = cfg.CONF.host_dvr_for_dhcp
query = context.session.query(
models_v2.IPAllocation.subnet_id).distinct()
query = query.join(models_v2.IPAllocation.port)
@ -360,7 +364,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
models_v2.Port.device_owner.startswith(
n_const.DEVICE_OWNER_COMPUTE_PREFIX),
models_v2.Port.device_owner.in_(
n_utils.get_other_dvr_serviced_device_owners()))
n_utils.get_other_dvr_serviced_device_owners(host_dvr_dhcp)))
query = query.filter(owner_filter)
return query
@ -458,6 +462,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
IPAllocation = models_v2.IPAllocation
Port = models_v2.Port
host_dvr_dhcp = cfg.CONF.host_dvr_for_dhcp
query = context.session.query(Binding)
query = query.join(Binding.port)
query = query.join(Port.fixed_ips)
@ -469,7 +474,7 @@ class L3_DVRsch_db_mixin(l3agent_sch_db.L3AgentSchedulerDbMixin):
models_v2.Port.device_owner.startswith(
n_const.DEVICE_OWNER_COMPUTE_PREFIX),
models_v2.Port.device_owner.in_(
n_utils.get_other_dvr_serviced_device_owners()))
n_utils.get_other_dvr_serviced_device_owners(host_dvr_dhcp)))
query = query.filter(device_filter)
host_filter = or_(
ml2_models.PortBinding.host == host,

View File

@ -0,0 +1,6 @@
---
other:
- |
A new config option, ``host_dvr_for_dhcp``, was added to neutron.conf
for DVR to determine whether to host the DVR local router to the
scheduled DHCP node(s).