diff --git a/doc/source/admin/deploy-ovs-ha-dvr.rst b/doc/source/admin/deploy-ovs-ha-dvr.rst index dc748456b78..39ae8ccbfe2 100644 --- a/doc/source/admin/deploy-ovs-ha-dvr.rst +++ b/doc/source/admin/deploy-ovs-ha-dvr.rst @@ -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 diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 00ab95e3e6f..5efe03eecd1 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -170,16 +170,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(): diff --git a/neutron/conf/db/l3_dvr_db.py b/neutron/conf/db/l3_dvr_db.py index 36ccd5d91d8..5b7f7027cc4 100644 --- a/neutron/conf/db/l3_dvr_db.py +++ b/neutron/conf/db/l3_dvr_db.py @@ -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.")), ] diff --git a/neutron/db/dvr_mac_db.py b/neutron/db/dvr_mac_db.py index 71c502700e7..412e28e4aae 100644 --- a/neutron/db/dvr_mac_db.py +++ b/neutron/db/dvr_mac_db.py @@ -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) diff --git a/neutron/db/l3_dvrscheduler_db.py b/neutron/db/l3_dvrscheduler_db.py index aa0d4d636ca..1376460e4b0 100644 --- a/neutron/db/l3_dvrscheduler_db.py +++ b/neutron/db/l3_dvrscheduler_db.py @@ -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): @@ -340,6 +342,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 @@ -351,12 +354,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) @@ -366,7 +370,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 @@ -464,6 +468,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) @@ -475,7 +480,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, diff --git a/releasenotes/notes/config-host_dvr_for_dhcp-f949aca5bd666e24.yaml b/releasenotes/notes/config-host_dvr_for_dhcp-f949aca5bd666e24.yaml new file mode 100644 index 00000000000..5ea144801e1 --- /dev/null +++ b/releasenotes/notes/config-host_dvr_for_dhcp-f949aca5bd666e24.yaml @@ -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).