NSX|V3+P: subnet_create performance improvements

1. Improve _validate_external_subnet to get the result directly
from DB instead of a get_networks api call
2. Skip configuration validation in _is_overlay_network as the type
of TZ is validated at plugin init anyway
3. Some nit changes in create_subnet
4. Improve is_ddi_supported to get the network if it was
already retrived
5. Improve _get_net_tz to skip backend access when possible

Change-Id: I24aed399a478e2d391ab7b45fe38e53b77116abb
(cherry picked from commit 253273ca5f)
This commit is contained in:
Adit Sarfaty 2019-07-31 15:41:05 +03:00
parent caacf33807
commit bf45936f14
4 changed files with 54 additions and 45 deletions

View File

@ -368,9 +368,7 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
net_db[az_def.AZ_HINTS]) net_db[az_def.AZ_HINTS])
def _validate_external_subnet(self, context, network_id): def _validate_external_subnet(self, context, network_id):
filters = {'id': [network_id], 'router:external': [True]} if self._network_is_external(context, network_id):
nets = self.get_networks(context, filters=filters)
if len(nets) > 0:
err_msg = _("Can not enable DHCP on external network") err_msg = _("Can not enable DHCP on external network")
raise n_exc.InvalidInput(error_message=err_msg) raise n_exc.InvalidInput(error_message=err_msg)

View File

@ -811,14 +811,18 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
network[qos_consts.QOS_POLICY_ID] = (qos_com_utils. network[qos_consts.QOS_POLICY_ID] = (qos_com_utils.
get_network_policy_id(context, network['id'])) get_network_policy_id(context, network['id']))
def _translate_net_db_2_dict(self, context, net_db):
net_dict = self._make_network_dict(net_db, context=context)
self._extend_get_network_dict_provider(context, net_dict)
return net_dict
def get_network(self, context, id, fields=None): def get_network(self, context, id, fields=None):
with db_api.CONTEXT_READER.using(context): with db_api.CONTEXT_READER.using(context):
# Get network from Neutron database # Get network from Neutron database
network = self._get_network(context, id) network = self._get_network(context, id)
# Don't do field selection here otherwise we won't be able to add # Don't do field selection here otherwise we won't be able to add
# provider networks fields # provider networks fields
net = self._make_network_dict(network, context=context) net = self._translate_net_db_2_dict(context, network)
self._extend_get_network_dict_provider(context, net)
return db_utils.resource_fields(net, fields) return db_utils.resource_fields(net, fields)
def get_networks(self, context, filters=None, fields=None, def get_networks(self, context, filters=None, fields=None,
@ -2018,19 +2022,18 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self._validate_host_routes_input(subnet) self._validate_host_routes_input(subnet)
self._validate_subnet_ip_version(subnet['subnet']) self._validate_subnet_ip_version(subnet['subnet'])
network = self._get_network( net_id = subnet['subnet']['network_id']
context, subnet['subnet']['network_id']) network = self._get_network(context, net_id)
self._validate_single_ipv6_subnet(context, network, subnet['subnet']) self._validate_single_ipv6_subnet(context, network, subnet['subnet'])
# TODO(berlin): public external subnet announcement # TODO(berlin): public external subnet announcement
if self._subnet_with_native_dhcp(subnet['subnet']): if self._subnet_with_native_dhcp(subnet['subnet']):
self._validate_external_subnet(context, self._validate_external_subnet(context, net_id)
subnet['subnet']['network_id'])
self._ensure_native_dhcp() self._ensure_native_dhcp()
lock = 'nsxv3_network_' + subnet['subnet']['network_id'] lock = 'nsxv3_network_' + net_id
ddi_support, ddi_type = self._is_ddi_supported_on_net_with_type( ddi_support, ddi_type = self._is_ddi_supported_on_net_with_type(
context, subnet['subnet']['network_id']) context, net_id, network=network)
with locking.LockManager.get_lock(lock): with locking.LockManager.get_lock(lock):
# Check if it is on an overlay network and is the first # Check if it is on an overlay network and is the first
# DHCP-enabled subnet to create. # DHCP-enabled subnet to create.
@ -2052,8 +2055,7 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
context, created_subnet['id']) context, created_subnet['id'])
self._extension_manager.process_create_subnet(context, self._extension_manager.process_create_subnet(context,
subnet['subnet'], created_subnet) subnet['subnet'], created_subnet)
dhcp_relay = self._get_net_dhcp_relay( dhcp_relay = self._get_net_dhcp_relay(context, net_id)
context, subnet['subnet']['network_id'])
if not dhcp_relay: if not dhcp_relay:
if self.nsxlib: if self.nsxlib:
try: try:
@ -2072,13 +2074,11 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
msg = None msg = None
else: else:
msg = (_("Can not create more than one DHCP-enabled " msg = (_("Can not create more than one DHCP-enabled "
"subnet in network %s") % "subnet in network %s") % net_id)
subnet['subnet']['network_id'])
else: else:
msg = _("Native DHCP is not supported for %(type)s " msg = _("Native DHCP is not supported for %(type)s "
"network %(id)s") % { "network %(id)s") % {'id': net_id,
'id': subnet['subnet']['network_id'], 'type': ddi_type}
'type': ddi_type}
if msg: if msg:
LOG.error(msg) LOG.error(msg)
raise n_exc.InvalidInput(error_message=msg) raise n_exc.InvalidInput(error_message=msg)
@ -2278,7 +2278,8 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
if enable_dhcp: if enable_dhcp:
(ddi_support, (ddi_support,
ddi_type) = self._is_ddi_supported_on_net_with_type( ddi_type) = self._is_ddi_supported_on_net_with_type(
context, orig_subnet['network_id']) context, orig_subnet['network_id'],
network=network)
if ddi_support: if ddi_support:
if self._has_no_dhcp_enabled_subnet( if self._has_no_dhcp_enabled_subnet(
context, network): context, network):
@ -2521,13 +2522,20 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
def _is_vlan_router_interface_supported(self): def _is_vlan_router_interface_supported(self):
"""Should be implemented by each plugin""" """Should be implemented by each plugin"""
def _is_ddi_supported_on_network(self, context, network_id): def _is_ddi_supported_on_network(self, context, network_id, network=None):
result, _ = self._is_ddi_supported_on_net_with_type( result, _ = self._is_ddi_supported_on_net_with_type(
context, network_id) context, network_id, network=network)
return result return result
def _is_ddi_supported_on_net_with_type(self, context, network_id): def _is_ddi_supported_on_net_with_type(self, context, network_id,
net = self.get_network(context, network_id) network=None):
# Get the network dictionary from the inputs
if network:
net = (network if isinstance(network, dict)
else self._translate_net_db_2_dict(context, network))
else:
net = self.get_network(context, network_id)
# NSX current does not support transparent VLAN ports for # NSX current does not support transparent VLAN ports for
# DHCP and metadata # DHCP and metadata
if cfg.CONF.vlan_transparent: if cfg.CONF.vlan_transparent:
@ -2645,7 +2653,7 @@ class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
not self._has_native_dhcp_metadata()): not self._has_native_dhcp_metadata()):
return return
is_ddi_network = self._is_ddi_supported_on_network( is_ddi_network = self._is_ddi_supported_on_network(
context, network['id']) context, network['id'], network=network)
if is_ddi_network: if is_ddi_network:
# Enable native metadata proxy for this network. # Enable native metadata proxy for this network.
tags = self.nsxlib.build_v3_tags_payload( tags = self.nsxlib.build_v3_tags_payload(

View File

@ -2879,7 +2879,7 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
bindings = nsx_db.get_network_bindings(context.session, network_id) bindings = nsx_db.get_network_bindings(context.session, network_id)
# With NSX plugin, "normal" overlay networks will have no binding # With NSX plugin, "normal" overlay networks will have no binding
if not bindings: if not bindings:
# using the default /AZ overlay_tz # using the default/AZ overlay_tz
return True return True
binding = bindings[0] binding = bindings[0]
@ -2890,11 +2890,13 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
segment = self.nsxpolicy.segment.get(binding.phy_uuid) segment = self.nsxpolicy.segment.get(binding.phy_uuid)
tz = self._get_nsx_net_tz_id(segment) tz = self._get_nsx_net_tz_id(segment)
if tz: if tz:
# This call is cached on the nsxlib side
type = self.nsxpolicy.transport_zone.get_transport_type( type = self.nsxpolicy.transport_zone.get_transport_type(
tz) tz)
return type == nsxlib_consts.TRANSPORT_TYPE_OVERLAY return type == nsxlib_consts.TRANSPORT_TYPE_OVERLAY
def _is_ens_tz(self, tz_id): def _is_ens_tz(self, tz_id):
# This call is cached on the nsxlib side
mode = self.nsxpolicy.transport_zone.get_host_switch_mode(tz_id) mode = self.nsxpolicy.transport_zone.get_host_switch_mode(tz_id)
return mode == nsxlib_consts.HOST_SWITCH_MODE_ENS return mode == nsxlib_consts.HOST_SWITCH_MODE_ENS

View File

@ -895,20 +895,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
bindings = nsx_db.get_network_bindings(context.session, network_id) bindings = nsx_db.get_network_bindings(context.session, network_id)
# With NSX plugin, "normal" overlay networks will have no binding # With NSX plugin, "normal" overlay networks will have no binding
if not bindings: if not bindings:
# check the backend transport zone # using the default/AZ overlay_tz
az = self.get_network_az_by_net_id(context, network_id)
tz = az._default_overlay_tz_uuid
if tz:
backend_type = self.nsxlib.transport_zone.get_transport_type(
tz)
if (backend_type !=
self.nsxlib.transport_zone.TRANSPORT_TYPE_OVERLAY):
# This is a misconfiguration
LOG.warning("Availability zone %(az)s default overlay TZ "
"%(tz)s is of type %(type)s",
{'az': az.name, 'tz': tz,
'type': backend_type})
return False
return True return True
binding = bindings[0] binding = bindings[0]
if binding.binding_type == utils.NsxV3NetworkTypes.GENEVE: if binding.binding_type == utils.NsxV3NetworkTypes.GENEVE:
@ -919,6 +906,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
ls = self.nsxlib.logical_switch.get(binding.phy_uuid) ls = self.nsxlib.logical_switch.get(binding.phy_uuid)
tz = ls.get('transport_zone_id') tz = ls.get('transport_zone_id')
if tz: if tz:
# This call is cached on the nsxlib side
backend_type = self.nsxlib.transport_zone.get_transport_type( backend_type = self.nsxlib.transport_zone.get_transport_type(
tz) tz)
return (backend_type == return (backend_type ==
@ -1460,14 +1448,27 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
return result return result
def _get_net_tz(self, context, net_id): def _get_net_tz(self, context, net_id):
mappings = nsx_db.get_nsx_switch_ids(context.session, net_id) bindings = nsx_db.get_network_bindings(context.session, net_id)
if mappings: if bindings:
nsx_net_id = mappings[0] bind_type = bindings[0].binding_type
if nsx_net_id: if bind_type == utils.NsxV3NetworkTypes.NSX_NETWORK:
nsx_net = self.nsxlib.logical_switch.get(nsx_net_id) # If it is NSX network, return the TZ of the backend LS
return nsx_net.get('transport_zone_id') mappings = nsx_db.get_nsx_switch_ids(context.session, net_id)
if mappings and mappings[0]:
nsx_net = self.nsxlib.logical_switch.get(mappings[0])
return nsx_net.get('transport_zone_id')
elif bind_type == utils.NetworkTypes.L3_EXT:
# External network has tier0 as phy_uuid
return
else:
return bindings[0].phy_uuid
else:
# Get the default one for the network AZ
az = self.get_network_az_by_net_id(context, net_id)
return az._default_overlay_tz_uuid
def _is_ens_tz(self, tz_id): def _is_ens_tz(self, tz_id):
# This call is cached on the nsxlib side
mode = self.nsxlib.transport_zone.get_host_switch_mode(tz_id) mode = self.nsxlib.transport_zone.get_host_switch_mode(tz_id)
return mode == self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS return mode == self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS