Merge "NSX|V: prevent deadlock with subnet creation and deletion"

This commit is contained in:
Jenkins 2017-06-08 10:41:16 +00:00 committed by Gerrit Code Review
commit 2082495477
3 changed files with 35 additions and 46 deletions

View File

@ -494,11 +494,7 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
with locking.LockManager.get_lock(network_id): with locking.LockManager.get_lock(network_id):
dhcp_id = self.edge_manager.create_dhcp_edge_service( dhcp_id = self.edge_manager.create_dhcp_edge_service(
context, network_id, subnet) context, network_id, subnet)
self.plugin._update_dhcp_adddress(context, network_id)
address_groups = self.plugin._create_network_dhcp_address_group(
context, network_id)
self.edge_manager.update_dhcp_edge_service(
context, network_id, address_groups=address_groups)
if dhcp_id: if dhcp_id:
edge_id, az_name = self.plugin._get_edge_id_and_az_by_rtr_id( edge_id, az_name = self.plugin._get_edge_id_and_az_by_rtr_id(
context, dhcp_id) context, dhcp_id)

View File

@ -1893,6 +1893,13 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
return self._update_port(context, id, port, original_port, return self._update_port(context, id, port, original_port,
is_compute_port, device_id) is_compute_port, device_id)
def _update_dhcp_adddress(self, context, network_id):
with locking.LockManager.get_lock('dhcp-update-%s' % network_id):
address_groups = self._create_network_dhcp_address_group(
context, network_id)
self._update_dhcp_edge_service(context, network_id,
address_groups)
def _update_port(self, context, id, port, original_port, is_compute_port, def _update_port(self, context, id, port, original_port, is_compute_port,
device_id): device_id):
attrs = port[port_def.RESOURCE_NAME] attrs = port[port_def.RESOURCE_NAME]
@ -2039,11 +2046,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self._create_dhcp_static_binding(context, ret_port) self._create_dhcp_static_binding(context, ret_port)
elif owner == constants.DEVICE_OWNER_DHCP: elif owner == constants.DEVICE_OWNER_DHCP:
# Update the ip of the dhcp port # Update the ip of the dhcp port
with locking.LockManager.get_lock(ret_port['network_id']): self._update_dhcp_adddress(context,
address_groups = self._create_network_dhcp_address_group( ret_port['network_id'])
context, ret_port['network_id'])
self._update_dhcp_edge_service(
context, ret_port['network_id'], address_groups)
elif (owner == constants.DEVICE_OWNER_ROUTER_GW or elif (owner == constants.DEVICE_OWNER_ROUTER_GW or
owner == constants.DEVICE_OWNER_ROUTER_INTF): owner == constants.DEVICE_OWNER_ROUTER_INTF):
# This is a router port - update the edge appliance # This is a router port - update the edge appliance
@ -2278,34 +2282,33 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# and send update dhcp interface rest call before deleting subnet's # and send update dhcp interface rest call before deleting subnet's
# corresponding dhcp interface rest call and lead to overlap response # corresponding dhcp interface rest call and lead to overlap response
# from backend. # from backend.
with locking.LockManager.get_lock('nsx-edge-pool'): network_id = subnet['network_id']
with db_api.context_manager.writer.using(context): with locking.LockManager.get_lock(network_id):
super(NsxVPluginV2, self).delete_subnet(context, id) with locking.LockManager.get_lock('nsx-edge-pool'):
with db_api.context_manager.writer.using(context):
super(NsxVPluginV2, self).delete_subnet(context, id)
if subnet['enable_dhcp']: if subnet['enable_dhcp']:
# There is only DHCP port available # There is only DHCP port available
if len(ports) == 1: if len(ports) == 1:
port = ports.pop() port = ports.pop()
# This is done out of the transaction as it invokes
# update_port which interfaces with the NSX
self.ipam.delete_port(context, port['id']) self.ipam.delete_port(context, port['id'])
if subnet['enable_dhcp']: # Delete the DHCP edge service
# Delete the DHCP edge service filters = {'network_id': [network_id]}
network_id = subnet['network_id'] remaining_subnets = self.get_subnets(context,
filters = {'network_id': [network_id]} filters=filters)
remaining_subnets = self.get_subnets(context, if len(remaining_subnets) == 0:
filters=filters) self._cleanup_dhcp_edge_before_deletion(
if len(remaining_subnets) == 0:
self._cleanup_dhcp_edge_before_deletion(
context, network_id)
LOG.debug("Delete the DHCP service for network %s",
network_id)
self._delete_dhcp_edge_service(context, network_id)
else:
# Update address group and delete the DHCP port only
with locking.LockManager.get_lock(network_id):
addr_groups = self._create_network_dhcp_address_group(
context, network_id) context, network_id)
self._update_dhcp_edge_service(context, network_id, LOG.debug("Delete the DHCP service for network %s",
addr_groups) network_id)
self._delete_dhcp_edge_service(context, network_id)
else:
# Update address group and delete the DHCP port only
self._update_dhcp_adddress(context, network_id)
def _is_overlapping_reserved_subnets(self, subnet): def _is_overlapping_reserved_subnets(self, subnet):
"""Return True if the subnet overlaps with reserved subnets. """Return True if the subnet overlaps with reserved subnets.
@ -2428,7 +2431,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self._update_dhcp_service_with_subnet(context, s) self._update_dhcp_service_with_subnet(context, s)
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
self.delete_subnet(context, s['id']) super(NsxVPluginV2, self).delete_subnet(context,
s['id'])
return s return s
def _process_subnet_ext_attr_create(self, session, subnet_db, def _process_subnet_ext_attr_create(self, session, subnet_db,
@ -2630,11 +2634,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
network_id) network_id)
self._delete_dhcp_edge_service(context, network_id) self._delete_dhcp_edge_service(context, network_id)
return return
with locking.LockManager.get_lock(network_id): self._update_dhcp_adddress(context, network_id)
address_groups = self._create_network_dhcp_address_group(
context, network_id)
self._update_dhcp_edge_service(context, network_id,
address_groups)
def _get_conflict_network_ids_by_overlapping(self, context, subnets): def _get_conflict_network_ids_by_overlapping(self, context, subnets):
with locking.LockManager.get_lock('nsx-networking'): with locking.LockManager.get_lock('nsx-networking'):
@ -2732,10 +2732,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self.edge_manager.create_dhcp_edge_service(context, network_id, self.edge_manager.create_dhcp_edge_service(context, network_id,
subnet) subnet)
# Create all dhcp ports within the network # Create all dhcp ports within the network
address_groups = self._create_network_dhcp_address_group( self._update_dhcp_adddress(context, network_id)
context, network_id)
self.edge_manager.update_dhcp_edge_service(
context, network_id, address_groups=address_groups)
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():

View File

@ -1541,11 +1541,7 @@ class EdgeManager(object):
LOG.error('Database conflict could not be recovered ' LOG.error('Database conflict could not be recovered '
'for VDR %(vdr)s DHCP edge %(dhcp)s', 'for VDR %(vdr)s DHCP edge %(dhcp)s',
{'vdr': vdr_router_id, 'dhcp': dhcp_edge_id}) {'vdr': vdr_router_id, 'dhcp': dhcp_edge_id})
with locking.LockManager.get_lock(network_id): self.plugin._update_dhcp_adddress(context, network_id)
address_groups = self.plugin._create_network_dhcp_address_group(
context, network_id)
self.update_dhcp_edge_service(
context, network_id, address_groups=address_groups)
self.set_sysctl_rp_filter_for_vdr_dhcp( self.set_sysctl_rp_filter_for_vdr_dhcp(
context, dhcp_edge_id, network_id) context, dhcp_edge_id, network_id)