~niedbalski/ubuntu/vivid/neutron/fixes-1447803

« back to all changes in this revision

Viewing changes to neutron/plugins/ml2/plugin.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-10-03 18:45:23 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20141003184523-4mt6dy1q3j8n30c9
Tags: 1:2014.2~rc1-0ubuntu1
* New upstream release candidate:
  - d/p/*: Refreshed.
  - d/control: Add python-requests-mock to BD's.
  - d/control: Align versioned requirements with upstream.
* Transition linuxbridge and openvswitch plugin users to modular
  layer 2 plugin (LP: #1323729):
  - d/control: Mark removed plugin packages as transitional, depend
    on neutron-plugin-ml2, mark oldlibs/extra.
  - d/neutron-plugin-{linuxbridge,openvswitch}.install: Drop.
  - d/control: Depend on neutron-plugin-ml2 for linuxbridge
    agent package.
  - d/neutron-plugin-linuxbridge-agent.upstart: Use ml2 plugin
    configuration files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
72
72
# providernet.py?
73
73
TYPE_MULTI_SEGMENT = 'multi-segment'
74
74
 
75
 
TAP_DEVICE_PREFIX = 'tap'
76
 
TAP_DEVICE_PREFIX_LENGTH = 3
77
 
 
78
75
 
79
76
class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
80
77
                dvr_mac_db.DVRDbMixin,
159
156
        # TODO(rkukura): Implement filtering.
160
157
        return nets
161
158
 
162
 
    def _process_port_binding(self, mech_context, context, attrs):
 
159
    def _notify_l3_agent_new_port(self, context, port):
 
160
        if not port:
 
161
            return
 
162
 
 
163
        # Whenever a DVR serviceable port comes up on a
 
164
        # node, it has to be communicated to the L3 Plugin
 
165
        # and agent for creating the respective namespaces.
 
166
        if (utils.is_dvr_serviced(port['device_owner'])):
 
167
            l3plugin = manager.NeutronManager.get_service_plugins().get(
 
168
                service_constants.L3_ROUTER_NAT)
 
169
            if (utils.is_extension_supported(
 
170
                l3plugin, const.L3_DISTRIBUTED_EXT_ALIAS)):
 
171
                l3plugin.dvr_update_router_addvm(context, port)
 
172
 
 
173
    def _get_host_port_if_changed(self, mech_context, attrs):
 
174
        binding = mech_context._binding
 
175
        host = attrs and attrs.get(portbindings.HOST_ID)
 
176
        if (attributes.is_attr_set(host) and binding.host != host):
 
177
            return mech_context.current
 
178
 
 
179
    def _process_port_binding(self, mech_context, attrs):
163
180
        binding = mech_context._binding
164
181
        port = mech_context.current
165
182
        changes = False
169
186
            binding.host != host):
170
187
            binding.host = host
171
188
            changes = True
172
 
            # Whenever a DVR serviceable port comes up on a
173
 
            # node, it has to be communicated to the L3 Plugin
174
 
            # and agent for creating the respective namespaces.
175
 
            if (utils.is_dvr_serviced(port['device_owner'])):
176
 
                l3plugin = manager.NeutronManager.get_service_plugins().get(
177
 
                    service_constants.L3_ROUTER_NAT)
178
 
                if (utils.is_extension_supported(
179
 
                    l3plugin, const.L3_DISTRIBUTED_EXT_ALIAS)):
180
 
                    l3plugin.dvr_update_router_addvm(context, port)
181
189
 
182
190
        vnic_type = attrs and attrs.get(portbindings.VNIC_TYPE)
183
191
        if (attributes.is_attr_set(vnic_type) and
350
358
                cur_binding.driver = new_binding.driver
351
359
                cur_binding.segment = new_binding.segment
352
360
 
353
 
                # REVISIT(rkukura): The binding:profile attribute is
354
 
                # supposed to be input-only, but the Mellanox driver
355
 
                # currently modifies it while binding. Remove this
356
 
                # code when the Mellanox driver has been updated to
357
 
                # use binding:vif_details instead.
358
 
                if cur_binding.profile != new_binding.profile:
359
 
                    cur_binding.profile = new_binding.profile
360
 
 
361
361
                # Update PortContext's port dictionary to reflect the
362
362
                # updated binding state.
363
363
                self._update_port_dict_binding(port, cur_binding)
580
580
                # to prevent deadlock waiting to acquire a DB lock
581
581
                # held by another thread in the same process, leading
582
582
                # to 'lock wait timeout' errors.
 
583
                #
 
584
                # Process L3 first, since, depending on the L3 plugin, it may
 
585
                # involve locking the db-access semaphore, sending RPC
 
586
                # notifications, and/or calling delete_port on this plugin.
 
587
                # Additionally, a rollback may not be enough to undo the
 
588
                # deletion of a floating IP with certain L3 backends.
 
589
                self._process_l3_delete(context, id)
583
590
                with contextlib.nested(lockutils.lock('db-access'),
584
591
                                       session.begin(subtransactions=True)):
585
 
                    self._process_l3_delete(context, id)
586
592
                    # Get ports to auto-delete.
587
593
                    ports = (session.query(models_v2.Port).
588
594
                             enable_eagerloads(False).
708
714
            # wait timeout' errors.
709
715
            with contextlib.nested(lockutils.lock('db-access'),
710
716
                                   session.begin(subtransactions=True)):
711
 
                subnet = self.get_subnet(context, id)
 
717
                record = self._get_subnet(context, id)
 
718
                subnet = self._make_subnet_dict(record, None)
712
719
                # Get ports to auto-deallocate
713
720
                allocated = (session.query(models_v2.IPAllocation).
714
721
                             filter_by(subnet_id=id).
731
738
                        mech_context)
732
739
 
733
740
                    LOG.debug(_("Deleting subnet record"))
734
 
                    record = self._get_subnet(context, id)
735
741
                    session.delete(record)
736
742
 
737
743
                    LOG.debug(_("Committing transaction"))
778
784
            binding = db.add_port_binding(session, result['id'])
779
785
            mech_context = driver_context.PortContext(self, context, result,
780
786
                                                      network, binding)
781
 
            self._process_port_binding(mech_context, context, attrs)
 
787
            new_host_port = self._get_host_port_if_changed(mech_context, attrs)
 
788
            self._process_port_binding(mech_context, attrs)
782
789
 
783
790
            result[addr_pair.ADDRESS_PAIRS] = (
784
791
                self._process_create_allowed_address_pairs(
788
795
                                                      dhcp_opts)
789
796
            self.mechanism_manager.create_port_precommit(mech_context)
790
797
 
 
798
        # Notification must be sent after the above transaction is complete
 
799
        self._notify_l3_agent_new_port(context, new_host_port)
 
800
 
791
801
        try:
792
802
            self.mechanism_manager.create_port_postcommit(mech_context)
793
803
        except ml2_exc.MechanismDriverError:
842
852
            mech_context = driver_context.PortContext(
843
853
                self, context, updated_port, network, binding,
844
854
                original_port=original_port)
 
855
            new_host_port = self._get_host_port_if_changed(mech_context, attrs)
845
856
            need_port_update_notify |= self._process_port_binding(
846
 
                mech_context, context, attrs)
 
857
                mech_context, attrs)
847
858
            self.mechanism_manager.update_port_precommit(mech_context)
848
859
 
 
860
        # Notification must be sent after the above transaction is complete
 
861
        self._notify_l3_agent_new_port(context, new_host_port)
 
862
 
849
863
        # TODO(apech) - handle errors raised by update_port, potentially
850
864
        # by re-calling update_port with the previous attributes. For
851
865
        # now the error is propogated to the caller, which is expected to
877
891
 
878
892
        self._update_port_dict_binding(port, binding)
879
893
        binding.host = attrs and attrs.get(portbindings.HOST_ID)
 
894
        binding.router_id = attrs and attrs.get('device_id')
880
895
 
881
896
    def update_dvr_port_binding(self, context, id, port):
882
897
        attrs = port['port']
890
905
 
891
906
        session = context.session
892
907
        binding = db.get_dvr_port_binding_by_host(session, id, host)
893
 
        if (not binding or
894
 
            binding.vif_type == portbindings.VIF_TYPE_BINDING_FAILED):
 
908
        device_id = attrs and attrs.get('device_id')
 
909
        router_id = binding and binding.get('router_id')
 
910
        update_required = (not binding or
 
911
            binding.vif_type == portbindings.VIF_TYPE_BINDING_FAILED or
 
912
            router_id != device_id)
 
913
        if update_required:
895
914
            with session.begin(subtransactions=True):
 
915
                try:
 
916
                    orig_port = super(Ml2Plugin, self).get_port(context, id)
 
917
                except exc.PortNotFound:
 
918
                    LOG.debug("DVR Port %s has been deleted concurrently", id)
 
919
                    return
896
920
                if not binding:
897
921
                    binding = db.ensure_dvr_port_binding(
898
 
                        session, id, host, router_id=attrs['device_id'])
899
 
                orig_port = super(Ml2Plugin, self).get_port(context, id)
 
922
                        session, id, host, router_id=device_id)
900
923
                network = self.get_network(context, orig_port['network_id'])
901
924
                mech_context = driver_context.DvrPortContext(self,
902
925
                    context, orig_port, network,
939
962
                cur_binding.vif_details = new_binding.vif_details
940
963
                cur_binding.driver = new_binding.driver
941
964
                cur_binding.segment = new_binding.segment
942
 
                if cur_binding.profile != new_binding.profile:
943
 
                    cur_binding.profile = new_binding.profile
944
965
 
945
966
    def delete_port(self, context, id, l3_port_check=True):
946
967
        LOG.debug(_("Deleting port %s"), id)
969
990
 
970
991
            network = self.get_network(context, port['network_id'])
971
992
            mech_context = None
972
 
            if port['device_owner'] == const.DEVICE_OWNER_DVR_INTERFACE:
 
993
            device_owner = port['device_owner']
 
994
            if device_owner == const.DEVICE_OWNER_DVR_INTERFACE:
973
995
                bindings = db.get_dvr_port_bindings(context.session, id)
974
996
                for bind in bindings:
975
997
                    mech_context = driver_context.DvrPortContext(
978
1000
            else:
979
1001
                mech_context = driver_context.PortContext(self, context, port,
980
1002
                                                          network, binding)
981
 
                if "compute:" in port['device_owner'] and is_dvr_enabled:
982
 
                    router_info = l3plugin.dvr_deletens_if_no_vm(context, id)
 
1003
                if is_dvr_enabled and utils.is_dvr_serviced(device_owner):
 
1004
                    router_info = l3plugin.dvr_deletens_if_no_port(context, id)
983
1005
                    removed_routers += router_info
984
1006
                self.mechanism_manager.delete_port_precommit(mech_context)
985
1007
                self._delete_port_security_group_bindings(context, id)
990
1012
                    l3plugin.dvr_vmarp_table_update(context, id, "del")
991
1013
 
992
1014
            LOG.debug("Calling delete_port for %(port_id)s owned by %(owner)s"
993
 
                      % {"port_id": id, "owner": port['device_owner']})
 
1015
                      % {"port_id": id, "owner": device_owner})
994
1016
            super(Ml2Plugin, self).delete_port(context, id)
995
1017
 
996
1018
        # now that we've left db transaction, we are safe to notify
1139
1161
        # REVISIT(rkukura): Consider calling into MechanismDrivers to
1140
1162
        # process device names, or having MechanismDrivers supply list
1141
1163
        # of device prefixes to strip.
1142
 
        if device.startswith(TAP_DEVICE_PREFIX):
1143
 
            return device[TAP_DEVICE_PREFIX_LENGTH:]
 
1164
        if device.startswith(const.TAP_DEVICE_PREFIX):
 
1165
            return device[len(const.TAP_DEVICE_PREFIX):]
1144
1166
        else:
1145
1167
            # REVISIT(irenab): Consider calling into bound MD to
1146
1168
            # handle the get_device_details RPC, then remove the 'else' clause