From a5ffff50ea6d2e7acc078eb42a7b32ad50869cae Mon Sep 17 00:00:00 2001 From: Abhishek Raut Date: Fri, 21 Mar 2014 02:26:10 -0700 Subject: [PATCH] Segregate the VSM calls from database calls in N1kv plugin Rearrange the code in such a way that the calls to the VSM are outside the database session. This avoids DB locks on n1kv tables. Change-Id: Ic0f0d816cca06a3b03fdd9b58ee7599ddf65473e Closes-Bug: 1290646 --- .../plugins/cisco/n1kv/n1kv_neutron_plugin.py | 203 ++++++++++-------- 1 file changed, 113 insertions(+), 90 deletions(-) diff --git a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py index cad7378423..62fa75349e 100644 --- a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py +++ b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py @@ -846,45 +846,34 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, n1kvclient.update_network_segment(subnet['network_id'], body=body) n1kvclient.delete_ip_pool(subnet['id']) - def _send_create_port_request(self, context, port): + def _send_create_port_request(self, + context, + port, + port_count, + policy_profile, + vm_network_name): """ Send create port request to VSM. Create a VM network for a network and policy profile combination. If the VM network already exists, bind this port to the existing - VM network and increment its port count. + VM network on the VSM. :param context: neutron api request context :param port: port dictionary + :param port_count: integer representing the number of ports in one + VM Network + :param policy_profile: object of type policy profile + :param vm_network_name: string representing the name of the VM + network """ LOG.debug(_('_send_create_port_request: %s'), port) - try: - vm_network = n1kv_db_v2.get_vm_network( - context.session, - port[n1kv.PROFILE_ID], - port['network_id']) - except cisco_exceptions.VMNetworkNotFound: - policy_profile = n1kv_db_v2.get_policy_profile( - context.session, port[n1kv.PROFILE_ID]) - vm_network_name = (c_const.VM_NETWORK_NAME_PREFIX + - str(port[n1kv.PROFILE_ID]) + - "_" + str(port['network_id'])) - port_count = 1 - n1kv_db_v2.add_vm_network(context.session, - vm_network_name, - port[n1kv.PROFILE_ID], - port['network_id'], - port_count) - n1kvclient = n1kv_client.Client() + n1kvclient = n1kv_client.Client() + if port_count == 1: n1kvclient.create_vm_network(port, vm_network_name, policy_profile) else: - vm_network_name = vm_network['name'] - n1kvclient = n1kv_client.Client() n1kvclient.create_n1kv_port(port, vm_network_name) - vm_network['port_count'] += 1 - n1kv_db_v2.update_vm_network_port_count( - context.session, vm_network_name, vm_network['port_count']) def _send_update_port_request(self, port_id, mac_address, vm_network_name): """ @@ -900,29 +889,20 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, n1kvclient = n1kv_client.Client() n1kvclient.update_n1kv_port(vm_network_name, port_id, body) - def _send_delete_port_request(self, context, id): + def _send_delete_port_request(self, context, port, vm_network): """ Send delete port request to VSM. - Decrement the port count of the VM network after deleting the port. - If the port count reaches zero, delete the VM network. + Delete the port on the VSM. If it is the last port on the VM Network, + delete the VM Network. :param context: neutron api request context - :param id: UUID of the port to be deleted + :param port: port object which is to be deleted + :param vm_network: VM network object with which the port is associated """ - LOG.debug(_('_send_delete_port_request: %s'), id) - port = self.get_port(context, id) - vm_network = n1kv_db_v2.get_vm_network(context.session, - port[n1kv.PROFILE_ID], - port['network_id']) - vm_network['port_count'] -= 1 - n1kv_db_v2.update_vm_network_port_count( - context.session, vm_network['name'], vm_network['port_count']) + LOG.debug(_('_send_delete_port_request: %s'), port['id']) n1kvclient = n1kv_client.Client() - n1kvclient.delete_n1kv_port(vm_network['name'], id) + n1kvclient.delete_n1kv_port(vm_network['name'], port['id']) if vm_network['port_count'] == 0: - n1kv_db_v2.delete_vm_network(context.session, - port[n1kv.PROFILE_ID], - port['network_id']) n1kvclient.delete_vm_network(vm_network['name']) def _get_segmentation_id(self, context, id): @@ -1010,19 +990,16 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, self._process_l3_create(context, net, network['network']) self._extend_network_dict_provider(context, net) self._extend_network_dict_profile(context, net) - try: if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: self._send_add_multi_segment_request(context, net['id'], segment_pairs) else: self._send_create_network_request(context, net, segment_pairs) - # note - exception will rollback entire transaction except(cisco_exceptions.VSMError, cisco_exceptions.VSMConnectionFailed): super(N1kvNeutronPluginV2, self).delete_network(context, net['id']) else: - # note - exception will rollback entire transaction LOG.debug(_("Created network: %s"), net['id']) return net @@ -1108,13 +1085,12 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, elif binding.network_type == c_const.NETWORK_TYPE_VLAN: n1kv_db_v2.release_vlan(session, binding.physical_network, binding.segmentation_id) - # the network_binding record is deleted via cascade from - # the network record, so explicit removal is not necessary - self._send_delete_network_request(context, network) - self._process_l3_delete(context, id) super(N1kvNeutronPluginV2, self).delete_network(context, id) - LOG.debug(_("Deleted network: %s"), id) + # the network_binding record is deleted via cascade from + # the network record, so explicit removal is not necessary + self._send_delete_network_request(context, network) + LOG.debug(_("Deleted network: %s"), id) def get_network(self, context, id, fields=None): """ @@ -1167,6 +1143,12 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, :param port: port dictionary :returns: port object """ + p_profile = None + port_count = None + vm_network_name = None + profile_id_set = False + + # Set the network policy profile id for auto generated L3/DHCP ports if ('device_id' in port['port'] and port['port']['device_owner'] in [constants.DEVICE_OWNER_DHCP, constants.DEVICE_OWNER_ROUTER_INTF, constants.DEVICE_OWNER_ROUTER_GW, @@ -1176,11 +1158,11 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, if p_profile: port['port']['n1kv:profile_id'] = p_profile['id'] - profile_id_set = False if n1kv.PROFILE_ID in port['port']: profile_id = port['port'].get(n1kv.PROFILE_ID) profile_id_set = attributes.is_attr_set(profile_id) + # Set the default policy profile id for ports if no id is set if not profile_id_set: p_profile_name = c_conf.CISCO_N1K.default_policy_profile p_profile = self._get_policy_profile_by_name(p_profile_name) @@ -1188,27 +1170,56 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, port['port']['n1kv:profile_id'] = p_profile['id'] profile_id_set = True - if profile_id_set: - profile_id = self._process_policy_profile(context, - port['port']) - LOG.debug(_('Create port: profile_id=%s'), profile_id) - session = context.session - with session.begin(subtransactions=True): - pt = super(N1kvNeutronPluginV2, self).create_port(context, - port) - n1kv_db_v2.add_port_binding(session, pt['id'], profile_id) - self._extend_port_dict_profile(context, pt) - self._process_portbindings_create_and_update(context, - port['port'], - pt) + profile_id = self._process_policy_profile(context, + port['port']) + LOG.debug(_('Create port: profile_id=%s'), profile_id) + session = context.session + with session.begin(subtransactions=True): + pt = super(N1kvNeutronPluginV2, self).create_port(context, + port) + n1kv_db_v2.add_port_binding(session, pt['id'], profile_id) + self._extend_port_dict_profile(context, pt) try: - self._send_create_port_request(context, pt) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - super(N1kvNeutronPluginV2, self).delete_port(context, pt['id']) + vm_network = n1kv_db_v2.get_vm_network( + context.session, + profile_id, + pt['network_id']) + except cisco_exceptions.VMNetworkNotFound: + # Create a VM Network if no VM network exists. + vm_network_name = "%s%s_%s" % (c_const.VM_NETWORK_NAME_PREFIX, + profile_id, + pt['network_id']) + port_count = 1 + n1kv_db_v2.add_vm_network(context.session, + vm_network_name, + profile_id, + pt['network_id'], + port_count) else: - LOG.debug(_("Created port: %s"), pt) - return pt + # Update port count of the VM network. + vm_network_name = vm_network['name'] + port_count = vm_network['port_count'] + 1 + n1kv_db_v2.update_vm_network_port_count(context.session, + vm_network_name, + port_count) + self._process_portbindings_create_and_update(context, + port['port'], + pt) + # Extract policy profile for VM network create in VSM. + if not p_profile: + p_profile = n1kv_db_v2.get_policy_profile(session, profile_id) + try: + self._send_create_port_request(context, + pt, + port_count, + p_profile, + vm_network_name) + except(cisco_exceptions.VSMError, + cisco_exceptions.VSMConnectionFailed): + super(N1kvNeutronPluginV2, self).delete_port(context, pt['id']) + else: + LOG.debug(_("Created port: %s"), pt) + return pt def update_port(self, context, id, port): """ @@ -1240,9 +1251,21 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, if l3_port_check: self.prevent_l3_port_deletion(context, id) with context.session.begin(subtransactions=True): + port = self.get_port(context, id) + vm_network = n1kv_db_v2.get_vm_network(context.session, + port[n1kv.PROFILE_ID], + port['network_id']) + vm_network['port_count'] -= 1 + n1kv_db_v2.update_vm_network_port_count(context.session, + vm_network['name'], + vm_network['port_count']) + if vm_network['port_count'] == 0: + n1kv_db_v2.delete_vm_network(context.session, + port[n1kv.PROFILE_ID], + port['network_id']) self.disassociate_floatingips(context, id) - self._send_delete_port_request(context, id) super(N1kvNeutronPluginV2, self).delete_port(context, id) + self._send_delete_port_request(context, port, vm_network) def get_port(self, context, id, fields=None): """ @@ -1381,22 +1404,22 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, net_p = super(N1kvNeutronPluginV2, self).create_network_profile(context, network_profile) - try: - self._send_create_logical_network_request(net_p, - context.tenant_id) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - n1kv_db_v2.delete_profile_binding(context.session, - context.tenant_id, - net_p['id']) - try: - self._send_create_network_profile_request(context, net_p) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - n1kv_db_v2.delete_profile_binding(context.session, - context.tenant_id, - net_p['id']) - self._send_delete_logical_network_request(net_p) + try: + self._send_create_logical_network_request(net_p, + context.tenant_id) + except(cisco_exceptions.VSMError, + cisco_exceptions.VSMConnectionFailed): + n1kv_db_v2.delete_profile_binding(context.session, + context.tenant_id, + net_p['id']) + try: + self._send_create_network_profile_request(context, net_p) + except(cisco_exceptions.VSMError, + cisco_exceptions.VSMConnectionFailed): + n1kv_db_v2.delete_profile_binding(context.session, + context.tenant_id, + net_p['id']) + self._send_delete_logical_network_request(net_p) return net_p def delete_network_profile(self, context, id): @@ -1410,8 +1433,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, with context.session.begin(subtransactions=True): net_p = super(N1kvNeutronPluginV2, self).delete_network_profile(context, id) - self._send_delete_network_profile_request(net_p) - self._send_delete_logical_network_request(net_p) + self._send_delete_network_profile_request(net_p) + self._send_delete_logical_network_request(net_p) def update_network_profile(self, context, net_profile_id, network_profile): """ @@ -1427,8 +1450,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, update_network_profile(context, net_profile_id, network_profile)) - self._send_update_network_profile_request(net_p) - return net_p + self._send_update_network_profile_request(net_p) + return net_p def create_router(self, context, router): """