diff --git a/neutron/db/l3_db.py b/neutron/db/l3_db.py index 69357afce4b..ee024c20578 100644 --- a/neutron/db/l3_db.py +++ b/neutron/db/l3_db.py @@ -169,10 +169,8 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): return self._make_router_dict(router_db) def _update_router_db(self, context, router_id, data, gw_info): - """Update the DB object and related gw info, if available.""" + """Update the DB object.""" with context.session.begin(subtransactions=True): - if gw_info != attributes.ATTR_NOT_SPECIFIED: - self._update_router_gw_info(context, router_id, gw_info) router_db = self._get_router(context, router_id) if data: router_db.update(data) @@ -188,6 +186,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): if gw_info != attributes.ATTR_NOT_SPECIFIED: candidates = self._check_router_needs_rescheduling( context, id, gw_info) + # Update the gateway outside of the DB update since it involves L2 + # calls that don't make sense to rollback and may cause deadlocks + # in a transaction. + self._update_router_gw_info(context, id, gw_info) else: candidates = None router_db = self._update_router_db(context, id, r, gw_info) @@ -316,10 +318,10 @@ class L3_NAT_dbonly_mixin(l3.RouterPluginBase): router.gw_port = None context.session.add(router) context.session.expire(gw_port) - vpnservice = manager.NeutronManager.get_service_plugins().get( - constants.VPN) - if vpnservice: - vpnservice.check_router_in_use(context, router_id) + vpnservice = manager.NeutronManager.get_service_plugins().get( + constants.VPN) + if vpnservice: + vpnservice.check_router_in_use(context, router_id) self._core_plugin.delete_port( admin_ctx, gw_port['id'], l3_port_check=False)