¡@

Home 

OpenStack Study: hyperv_neutron_plugin.py

OpenStack Index

**** CubicPower OpenStack Study ****

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2013 Cloudbase Solutions SRL

# All Rights Reserved.

#

# Licensed under the Apache License, Version 2.0 (the "License"); you may

# not use this file except in compliance with the License. You may obtain

# a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT

# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the

# License for the specific language governing permissions and limitations

# under the License.

# @author: Alessandro Pilotti, Cloudbase Solutions Srl

from oslo.config import cfg

from neutron.api.v2 import attributes

from neutron.common import exceptions as n_exc

from neutron.common import topics

from neutron.db import agents_db

from neutron.db import db_base_plugin_v2

from neutron.db import external_net_db

from neutron.db import l3_gwmode_db

from neutron.db import portbindings_base

from neutron.db import quota_db # noqa

from neutron.extensions import portbindings

from neutron.extensions import providernet as provider

from neutron.openstack.common import log as logging

from neutron.openstack.common import rpc

from neutron.plugins.common import constants as svc_constants

from neutron.plugins.common import utils as plugin_utils

from neutron.plugins.hyperv import agent_notifier_api

from neutron.plugins.hyperv.common import constants

from neutron.plugins.hyperv import db as hyperv_db

from neutron.plugins.hyperv import rpc_callbacks

DEFAULT_VLAN_RANGES = []

hyperv_opts = [

cfg.StrOpt('tenant_network_type', default='local',

help=_("Network type for tenant networks "

"(local, flat, vlan or none)")),

cfg.ListOpt('network_vlan_ranges',

default=DEFAULT_VLAN_RANGES,

help=_("List of :: "

"or ")),

]

cfg.CONF.register_opts(hyperv_opts, "HYPERV")

LOG = logging.getLogger(__name__)

**** CubicPower OpenStack Study ****

class BaseNetworkProvider(object):

**** CubicPower OpenStack Study ****

    def __init__(self):

        self._db = hyperv_db.HyperVPluginDB()

**** CubicPower OpenStack Study ****

    def create_network(self, session, attrs):

        pass

**** CubicPower OpenStack Study ****

    def delete_network(self, session, binding):

        pass

**** CubicPower OpenStack Study ****

    def extend_network_dict(self, network, binding):

        pass

**** CubicPower OpenStack Study ****

class LocalNetworkProvider(BaseNetworkProvider):

**** CubicPower OpenStack Study ****

    def create_network(self, session, attrs):

        network_type = attrs.get(provider.NETWORK_TYPE)

        segmentation_id = attrs.get(provider.SEGMENTATION_ID)

        if attributes.is_attr_set(segmentation_id):

            msg = _("segmentation_id specified "

                    "for %s network") % network_type

            raise n_exc.InvalidInput(error_message=msg)

        attrs[provider.SEGMENTATION_ID] = None

        physical_network = attrs.get(provider.PHYSICAL_NETWORK)

        if attributes.is_attr_set(physical_network):

            msg = _("physical_network specified "

                    "for %s network") % network_type

            raise n_exc.InvalidInput(error_message=msg)

        attrs[provider.PHYSICAL_NETWORK] = None

**** CubicPower OpenStack Study ****

    def extend_network_dict(self, network, binding):

        network[provider.PHYSICAL_NETWORK] = None

        network[provider.SEGMENTATION_ID] = None

**** CubicPower OpenStack Study ****

class FlatNetworkProvider(BaseNetworkProvider):

**** CubicPower OpenStack Study ****

    def create_network(self, session, attrs):

        network_type = attrs.get(provider.NETWORK_TYPE)

        segmentation_id = attrs.get(provider.SEGMENTATION_ID)

        if attributes.is_attr_set(segmentation_id):

            msg = _("segmentation_id specified "

                    "for %s network") % network_type

            raise n_exc.InvalidInput(error_message=msg)

        segmentation_id = constants.FLAT_VLAN_ID

        attrs[provider.SEGMENTATION_ID] = segmentation_id

        physical_network = attrs.get(provider.PHYSICAL_NETWORK)

        if not attributes.is_attr_set(physical_network):

            physical_network = self._db.reserve_flat_net(session)

            attrs[provider.PHYSICAL_NETWORK] = physical_network

        else:

            self._db.reserve_specific_flat_net(session, physical_network)

**** CubicPower OpenStack Study ****

    def delete_network(self, session, binding):

        self._db.release_vlan(session, binding.physical_network,

                              constants.FLAT_VLAN_ID)

**** CubicPower OpenStack Study ****

    def extend_network_dict(self, network, binding):

        network[provider.PHYSICAL_NETWORK] = binding.physical_network

**** CubicPower OpenStack Study ****

class VlanNetworkProvider(BaseNetworkProvider):

**** CubicPower OpenStack Study ****

    def create_network(self, session, attrs):

        segmentation_id = attrs.get(provider.SEGMENTATION_ID)

        if attributes.is_attr_set(segmentation_id):

            physical_network = attrs.get(provider.PHYSICAL_NETWORK)

            if not attributes.is_attr_set(physical_network):

                msg = _("physical_network not provided")

                raise n_exc.InvalidInput(error_message=msg)

            self._db.reserve_specific_vlan(session, physical_network,

                                           segmentation_id)

        else:

            (physical_network,

             segmentation_id) = self._db.reserve_vlan(session)

            attrs[provider.SEGMENTATION_ID] = segmentation_id

            attrs[provider.PHYSICAL_NETWORK] = physical_network

**** CubicPower OpenStack Study ****

    def delete_network(self, session, binding):

        self._db.release_vlan(

            session, binding.physical_network,

            binding.segmentation_id)

**** CubicPower OpenStack Study ****

    def extend_network_dict(self, network, binding):

        network[provider.PHYSICAL_NETWORK] = binding.physical_network

        network[provider.SEGMENTATION_ID] = binding.segmentation_id

**** CubicPower OpenStack Study ****

class HyperVNeutronPlugin(agents_db.AgentDbMixin, db_base_plugin_v2.NeutronDbPluginV2, external_net_db.External_net_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, portbindings_base.PortBindingBaseMixin):

# This attribute specifies whether the plugin supports or not

# bulk operations. Name mangling is used in order to ensure it

# is qualified by class

__native_bulk_support = True

supported_extension_aliases = ["provider", "external-net", "router",

"agent", "ext-gw-mode", "binding", "quotas"]

**** CubicPower OpenStack Study ****

    def __init__(self, configfile=None):

        self._db = hyperv_db.HyperVPluginDB()

        self._db.initialize()

        self.base_binding_dict = {

            portbindings.VIF_TYPE: portbindings.VIF_TYPE_HYPERV}

        portbindings_base.register_port_dict_function()

        self._set_tenant_network_type()

        self._parse_network_vlan_ranges()

        self._create_network_providers_map()

        self._db.sync_vlan_allocations(self._network_vlan_ranges)

        self._setup_rpc()

**** CubicPower OpenStack Study ****

    def _set_tenant_network_type(self):

        tenant_network_type = cfg.CONF.HYPERV.tenant_network_type

        if tenant_network_type not in [svc_constants.TYPE_LOCAL,

                                       svc_constants.TYPE_FLAT,

                                       svc_constants.TYPE_VLAN,

                                       svc_constants.TYPE_NONE]:

            msg = _(

                "Invalid tenant_network_type: %s. "

                "Agent terminated!") % tenant_network_type

            raise n_exc.InvalidInput(error_message=msg)

        self._tenant_network_type = tenant_network_type

**** CubicPower OpenStack Study ****

    def _setup_rpc(self):

        # RPC support

        self.service_topics = {svc_constants.CORE: topics.PLUGIN,

                               svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}

        self.conn = rpc.create_connection(new=True)

        self.notifier = agent_notifier_api.AgentNotifierApi(

            topics.AGENT)

        self.callbacks = rpc_callbacks.HyperVRpcCallbacks(self.notifier)

        self.dispatcher = self.callbacks.create_rpc_dispatcher()

        for svc_topic in self.service_topics.values():

            self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)

        # Consume from all consumers in a thread

        self.conn.consume_in_thread()

**** CubicPower OpenStack Study ****

    def _parse_network_vlan_ranges(self):

        self._network_vlan_ranges = plugin_utils.parse_network_vlan_ranges(

            cfg.CONF.HYPERV.network_vlan_ranges)

        LOG.info(_("Network VLAN ranges: %s"), self._network_vlan_ranges)

**** CubicPower OpenStack Study ****

    def _check_vlan_id_in_range(self, physical_network, vlan_id):

        for r in self._network_vlan_ranges[physical_network]:

            if vlan_id >= r[0] and vlan_id <= r[1]:

                return True

        return False

**** CubicPower OpenStack Study ****

    def _create_network_providers_map(self):

        self._network_providers_map = {

            svc_constants.TYPE_LOCAL: LocalNetworkProvider(),

            svc_constants.TYPE_FLAT: FlatNetworkProvider(),

            svc_constants.TYPE_VLAN: VlanNetworkProvider()

        }

**** CubicPower OpenStack Study ****

    def _process_provider_create(self, context, session, attrs):

        network_type = attrs.get(provider.NETWORK_TYPE)

        network_type_set = attributes.is_attr_set(network_type)

        if not network_type_set:

            if self._tenant_network_type == svc_constants.TYPE_NONE:

                raise n_exc.TenantNetworksDisabled()

            network_type = self._tenant_network_type

            attrs[provider.NETWORK_TYPE] = network_type

        if network_type not in self._network_providers_map:

            msg = _("Network type %s not supported") % network_type

            raise n_exc.InvalidInput(error_message=msg)

        p = self._network_providers_map[network_type]

        # Provider specific network creation

        p.create_network(session, attrs)

**** CubicPower OpenStack Study ****

    def create_network(self, context, network):

        session = context.session

        with session.begin(subtransactions=True):

            network_attrs = network['network']

            self._process_provider_create(context, session, network_attrs)

            net = super(HyperVNeutronPlugin, self).create_network(

                context, network)

            network_type = network_attrs[provider.NETWORK_TYPE]

            physical_network = network_attrs[provider.PHYSICAL_NETWORK]

            segmentation_id = network_attrs[provider.SEGMENTATION_ID]

            self._db.add_network_binding(

                session, net['id'], network_type,

                physical_network, segmentation_id)

            self._process_l3_create(context, net, network['network'])

            self._extend_network_dict_provider(context, net)

            LOG.debug(_("Created network: %s"), net['id'])

            return net

**** CubicPower OpenStack Study ****

    def _extend_network_dict_provider(self, context, network):

        binding = self._db.get_network_binding(

            context.session, network['id'])

        network[provider.NETWORK_TYPE] = binding.network_type

        p = self._network_providers_map[binding.network_type]

        p.extend_network_dict(network, binding)

**** CubicPower OpenStack Study ****

    def update_network(self, context, id, network):

        provider._raise_if_updates_provider_attributes(network['network'])

        session = context.session

        with session.begin(subtransactions=True):

            net = super(HyperVNeutronPlugin, self).update_network(context, id,

                                                                  network)

            self._process_l3_update(context, net, network['network'])

            self._extend_network_dict_provider(context, net)

            return net

**** CubicPower OpenStack Study ****

    def delete_network(self, context, id):

        session = context.session

        with session.begin(subtransactions=True):

            binding = self._db.get_network_binding(session, id)

            super(HyperVNeutronPlugin, self).delete_network(context, id)

            p = self._network_providers_map[binding.network_type]

            p.delete_network(session, binding)

        # the network_binding record is deleted via cascade from

        # the network record, so explicit removal is not necessary

        self.notifier.network_delete(context, id)

**** CubicPower OpenStack Study ****

    def get_network(self, context, id, fields=None):

        net = super(HyperVNeutronPlugin, self).get_network(context, id, None)

        self._extend_network_dict_provider(context, net)

        return self._fields(net, fields)

**** CubicPower OpenStack Study ****

    def get_networks(self, context, filters=None, fields=None):

        nets = super(HyperVNeutronPlugin, self).get_networks(

            context, filters, None)

        for net in nets:

            self._extend_network_dict_provider(context, net)

        return [self._fields(net, fields) for net in nets]

**** CubicPower OpenStack Study ****

    def create_port(self, context, port):

        port_data = port['port']

        port = super(HyperVNeutronPlugin, self).create_port(context, port)

        self._process_portbindings_create_and_update(context,

                                                     port_data,

                                                     port)

        return port

**** CubicPower OpenStack Study ****

    def update_port(self, context, id, port):

        original_port = super(HyperVNeutronPlugin, self).get_port(

            context, id)

        port_data = port['port']

        port = super(HyperVNeutronPlugin, self).update_port(context, id, port)

        self._process_portbindings_create_and_update(context,

                                                     port_data,

                                                     port)

        if original_port['admin_state_up'] != port['admin_state_up']:

            binding = self._db.get_network_binding(

                None, port['network_id'])

            self.notifier.port_update(context, port,

                                      binding.network_type,

                                      binding.segmentation_id,

                                      binding.physical_network)

        return port

**** CubicPower OpenStack Study ****

    def delete_port(self, context, id, l3_port_check=True):

        # if needed, check to see if this is a port owned by

        # and l3-router.  If so, we should prevent deletion.

        if l3_port_check:

            self.prevent_l3_port_deletion(context, id)

        self.disassociate_floatingips(context, id)

        super(HyperVNeutronPlugin, self).delete_port(context, id)

        self.notifier.port_delete(context, id)