¡@

Home 

OpenStack Study: nec_router.py

OpenStack Index

**** CubicPower OpenStack Study ****

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

#

# Copyright 2013 NEC Corporation. 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: Akihiro Motoki

from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api

from neutron.api.v2 import attributes as attr

from neutron.common import exceptions as n_exc

from neutron.db import db_base_plugin_v2

from neutron.db import extraroute_db

from neutron.db import l3_agentschedulers_db

from neutron.db import l3_db

from neutron.db import l3_gwmode_db

from neutron.db import models_v2

from neutron.extensions import l3

from neutron.openstack.common import excutils

from neutron.openstack.common import importutils

from neutron.openstack.common import log as logging

from neutron.plugins.nec.common import config

from neutron.plugins.nec.common import constants as nconst

from neutron.plugins.nec.common import exceptions as nexc

from neutron.plugins.nec.db import router as rdb

from neutron.plugins.nec.extensions import router_provider as ext_provider

LOG = logging.getLogger(__name__)

PROVIDER_L3AGENT = nconst.ROUTER_PROVIDER_L3AGENT

PROVIDER_OPENFLOW = nconst.ROUTER_PROVIDER_OPENFLOW

ROUTER_DRIVER_PATH = 'neutron.plugins.nec.router_drivers.'

ROUTER_DRIVER_MAP = {

PROVIDER_L3AGENT: ROUTER_DRIVER_PATH + 'RouterL3AgentDriver',

PROVIDER_OPENFLOW: ROUTER_DRIVER_PATH + 'RouterOpenFlowDriver'

}

ROUTER_DRIVERS = {}

STATUS_ACTIVE = nconst.ROUTER_STATUS_ACTIVE

STATUS_ERROR = nconst.ROUTER_STATUS_ERROR

**** CubicPower OpenStack Study ****

class RouterMixin(extraroute_db.ExtraRoute_db_mixin, l3_gwmode_db.L3_NAT_db_mixin):

**** CubicPower OpenStack Study ****

    def create_router(self, context, router):

        """Create a new router entry on DB, and create it on OFC."""

        LOG.debug(_("RouterMixin.create_router() called, "

                    "router=%s ."), router)

        tenant_id = self._get_tenant_id_for_create(context, router['router'])

        provider = get_provider_with_default(

            router['router'].get(ext_provider.ROUTER_PROVIDER))

        driver = get_driver_by_provider(provider)

        with context.session.begin(subtransactions=True):

            new_router = super(RouterMixin, self).create_router(context,

                                                                router)

            new_router['gw_port'] = self._get_gw_port_detail(

                context, driver, new_router['gw_port_id'])

            rdb.add_router_provider_binding(context.session,

                                            provider, str(new_router['id']))

            self._extend_router_dict_provider(new_router, provider)

        # create router on the network controller

        try:

            return driver.create_router(context, tenant_id, new_router)

        except nexc.RouterOverLimit:

            with excutils.save_and_reraise_exception():

                super(RouterMixin, self).delete_router(context,

                                                       new_router['id'])

**** CubicPower OpenStack Study ****

    def update_router(self, context, router_id, router):

        LOG.debug(_("RouterMixin.update_router() called, "

                    "id=%(id)s, router=%(router)s ."),

                  {'id': router_id, 'router': router})

        with context.session.begin(subtransactions=True):

            old_rtr = super(RouterMixin, self).get_router(context, router_id)

            provider = old_rtr[ext_provider.ROUTER_PROVIDER]

            driver = get_driver_by_provider(provider)

            old_rtr['gw_port'] = self._get_gw_port_detail(

                context, driver, old_rtr['gw_port_id'])

            new_rtr = super(RouterMixin, self).update_router(

                context, router_id, router)

            new_rtr['gw_port'] = self._get_gw_port_detail(

                context, driver, new_rtr['gw_port_id'])

        driver.update_router(context, router_id, old_rtr, new_rtr)

        return new_rtr

**** CubicPower OpenStack Study ****

    def delete_router(self, context, router_id):

        LOG.debug(_("RouterMixin.delete_router() called, id=%s."), router_id)

        router = super(RouterMixin, self).get_router(context, router_id)

        tenant_id = router['tenant_id']

        # Since l3_db.delete_router() has no interaction with the plugin layer,

        # we need to check if the router can be deleted first.

        self._check_router_in_use(context, router_id)

        driver = self._get_router_driver_by_id(context, router_id)

        # If gw_port exists, remove it.

        gw_port = self._get_gw_port(context, router_id)

        if gw_port:

            driver.delete_interface(context, router_id, gw_port)

        driver.delete_router(context, router_id, router)

        super(RouterMixin, self).delete_router(context, router_id)

        self._cleanup_ofc_tenant(context, tenant_id)

**** CubicPower OpenStack Study ****

    def add_router_interface(self, context, router_id, interface_info):

        LOG.debug(_("RouterMixin.add_router_interface() called, "

                    "id=%(id)s, interface=%(interface)s."),

                  {'id': router_id, 'interface': interface_info})

        return super(RouterMixin, self).add_router_interface(

            context, router_id, interface_info)

**** CubicPower OpenStack Study ****

    def remove_router_interface(self, context, router_id, interface_info):

        LOG.debug(_("RouterMixin.remove_router_interface() called, "

                    "id=%(id)s, interface=%(interface)s."),

                  {'id': router_id, 'interface': interface_info})

        return super(RouterMixin, self).remove_router_interface(

            context, router_id, interface_info)

**** CubicPower OpenStack Study ****

    def create_router_port(self, context, port):

        # This method is called from plugin.create_port()

        router_id = port['device_id']

        driver = self._get_router_driver_by_id(context, router_id)

        port = driver.add_interface(context, router_id, port)

        return port

**** CubicPower OpenStack Study ****

    def delete_router_port(self, context, port):

        # This method is called from plugin.delete_port()

        router_id = port['device_id']

        driver = self._get_router_driver_by_id(context, router_id)

        return driver.delete_interface(context, router_id, port)

**** CubicPower OpenStack Study ****

    def _get_gw_port_detail(self, context, driver, gw_port_id):

        if not gw_port_id or not driver.need_gw_info:

            return

        ctx_elevated = context.elevated()

        gw_port = self._get_port(ctx_elevated, gw_port_id)

        # At this moment gw_port has been created, so it is guaranteed

        # that fixed_ip is assigned for the gw_port.

        ext_subnet_id = gw_port['fixed_ips'][0]['subnet_id']

        ext_subnet = self._get_subnet(ctx_elevated, ext_subnet_id)

        gw_info = {'network_id': gw_port['network_id'],

                   'ip_address': gw_port['fixed_ips'][0]['ip_address'],

                   'mac_address': gw_port['mac_address'],

                   'cidr': ext_subnet['cidr'],

                   'gateway_ip': ext_subnet['gateway_ip']}

        return gw_info

**** CubicPower OpenStack Study ****

    def _get_gw_port(self, context, router_id):

        device_filter = {'device_id': [router_id],

                         'device_owner': [l3_db.DEVICE_OWNER_ROUTER_GW]}

        ports = self.get_ports(context.elevated(), filters=device_filter)

        if ports:

            return ports[0]

**** CubicPower OpenStack Study ****

    def _check_router_in_use(self, context, router_id):

        with context.session.begin(subtransactions=True):

            # Ensure that the router is not used

            router_filter = {'router_id': [router_id]}

            fips = self.get_floatingips_count(context.elevated(),

                                              filters=router_filter)

            if fips:

                raise l3.RouterInUse(router_id=router_id)

            device_filter = {'device_id': [router_id],

                             'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF]}

            ports = self.get_ports_count(context.elevated(),

                                         filters=device_filter)

            if ports:

                raise l3.RouterInUse(router_id=router_id)

**** CubicPower OpenStack Study ****

    def _get_router_for_floatingip(self, context, internal_port,

                                   internal_subnet_id,

                                   external_network_id):

        """Get a router for a requested floating IP.

        OpenFlow vrouter does not support NAT, so we need to exclude them

        from candidate routers for floating IP association.

        This method is called in l3_db.get_assoc_data().

        """

        subnet_db = self._get_subnet(context, internal_subnet_id)

        if not subnet_db['gateway_ip']:

            msg = (_('Cannot add floating IP to port on subnet %s '

                     'which has no gateway_ip') % internal_subnet_id)

            raise n_exc.BadRequest(resource='floatingip', msg=msg)

        # find router interface ports on this network

        router_intf_qry = context.session.query(models_v2.Port)

        router_intf_ports = router_intf_qry.filter_by(

            network_id=internal_port['network_id'],

            device_owner=l3_db.DEVICE_OWNER_ROUTER_INTF)

        for intf_p in router_intf_ports:

            if intf_p['fixed_ips'][0]['subnet_id'] == internal_subnet_id:

                router_id = intf_p['device_id']

                router_gw_qry = context.session.query(models_v2.Port)

                has_gw_port = router_gw_qry.filter_by(

                    network_id=external_network_id,

                    device_id=router_id,

                    device_owner=l3_db.DEVICE_OWNER_ROUTER_GW).count()

                driver = self._get_router_driver_by_id(context, router_id)

                if (has_gw_port and driver.floating_ip_support()):

                    return router_id

        raise l3.ExternalGatewayForFloatingIPNotFound(

            subnet_id=internal_subnet_id,

            external_network_id=external_network_id,

            port_id=internal_port['id'])

**** CubicPower OpenStack Study ****

    def _get_sync_routers(self, context, router_ids=None, active=None):

        """Query routers and their gw ports for l3 agent.

        The difference from the superclass in l3_db is that this method

        only lists routers hosted on l3-agents.

        """

        router_list = super(RouterMixin, self)._get_sync_routers(

            context, router_ids, active)

        if router_list:

            _router_ids = [r['id'] for r in router_list]

            agent_routers = rdb.get_routers_by_provider(

                context.session, 'l3-agent',

                router_ids=_router_ids)

            router_list = [r for r in router_list

                           if r['id'] in agent_routers]

        return router_list

**** CubicPower OpenStack Study ****

    def _get_router_driver_by_id(self, context, router_id):

        provider = self._get_provider_by_router_id(context, router_id)

        return get_driver_by_provider(provider)

**** CubicPower OpenStack Study ****

    def _get_provider_by_router_id(self, context, router_id):

        return rdb.get_provider_by_router(context.session, router_id)

**** CubicPower OpenStack Study ****

    def _extend_router_dict_provider(self, router_res, provider):

        router_res[ext_provider.ROUTER_PROVIDER] = provider

**** CubicPower OpenStack Study ****

    def extend_router_dict_provider(self, router_res, router_db):

        # NOTE: router_db.provider is None just after creating a router,

        # so we need to skip setting router_provider here.

        if not router_db.provider:

            return

        self._extend_router_dict_provider(router_res,

                                          router_db.provider['provider'])

    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(

        l3.ROUTERS, [extend_router_dict_provider])

**** CubicPower OpenStack Study ****

class L3AgentSchedulerDbMixin(l3_agentschedulers_db.L3AgentSchedulerDbMixin):

**** CubicPower OpenStack Study ****

    def auto_schedule_routers(self, context, host, router_ids):

        router_ids = rdb.get_routers_by_provider(

            context.session, nconst.ROUTER_PROVIDER_L3AGENT, router_ids)

        # If no l3-agent hosted router, there is no need to schedule.

        if not router_ids:

            return

        return super(L3AgentSchedulerDbMixin, self).auto_schedule_routers(

            context, host, router_ids)

**** CubicPower OpenStack Study ****

    def schedule_router(self, context, router):

        if (self._get_provider_by_router_id(context, router) ==

            nconst.ROUTER_PROVIDER_L3AGENT):

            return super(L3AgentSchedulerDbMixin, self).schedule_router(

                context, router)

**** CubicPower OpenStack Study ****

    def add_router_to_l3_agent(self, context, id, router_id):

        provider = self._get_provider_by_router_id(context, router_id)

        if provider != nconst.ROUTER_PROVIDER_L3AGENT:

            raise nexc.RouterProviderMismatch(

                router_id=router_id, provider=provider,

                expected_provider=nconst.ROUTER_PROVIDER_L3AGENT)

        return super(L3AgentSchedulerDbMixin, self).add_router_to_l3_agent(

            context, id, router_id)

**** CubicPower OpenStack Study ****

class L3AgentNotifyAPI(l3_rpc_agent_api.L3AgentNotifyAPI):

**** CubicPower OpenStack Study ****

    def _notification(self, context, method, router_ids, operation, data):

        """Notify all the agents that are hosting the routers.

        _notification() is called in L3 db plugin for all routers regardless

        the routers are hosted on l3 agents or not. When the routers are

        not hosted on l3 agents, there is no need to notify.

        This method filters routers not hosted by l3 agents.

        """

        router_ids = rdb.get_routers_by_provider(

            context.session, nconst.ROUTER_PROVIDER_L3AGENT, router_ids)

        super(L3AgentNotifyAPI, self)._notification(

            context, method, router_ids, operation, data)

def load_driver(plugin, ofc_manager):

    if (PROVIDER_OPENFLOW in ROUTER_DRIVER_MAP and

        not ofc_manager.driver.router_supported):

        LOG.warning(

            _('OFC does not support router with provider=%(provider)s, '

              'so removed it from supported provider '

              '(new router driver map=%(driver_map)s)'),

            {'provider': PROVIDER_OPENFLOW,

             'driver_map': ROUTER_DRIVER_MAP})

        del ROUTER_DRIVER_MAP[PROVIDER_OPENFLOW]

    if config.PROVIDER.default_router_provider not in ROUTER_DRIVER_MAP:

        LOG.error(_('default_router_provider %(default)s is supported! '

                    'Please specify one of %(supported)s'),

                  {'default': config.PROVIDER.default_router_provider,

                   'supported': ROUTER_DRIVER_MAP.keys()})

        raise SystemExit(1)

    enabled_providers = (set(config.PROVIDER.router_providers +

                             [config.PROVIDER.default_router_provider]) &

                         set(ROUTER_DRIVER_MAP.keys()))

    for driver in enabled_providers:

        driver_klass = importutils.import_class(ROUTER_DRIVER_MAP[driver])

        ROUTER_DRIVERS[driver] = driver_klass(plugin, ofc_manager)

    LOG.info(_('Enabled router drivers: %s'), ROUTER_DRIVERS.keys())

    if not ROUTER_DRIVERS:

        LOG.error(_('No router provider is enabled. neutron-server terminated!'

                    ' (supported=%(supported)s, configured=%(config)s)'),

                  {'supported': ROUTER_DRIVER_MAP.keys(),

                   'config': config.PROVIDER.router_providers})

        raise SystemExit(1)

def get_provider_with_default(provider):

    if not attr.is_attr_set(provider):

        provider = config.PROVIDER.default_router_provider

    elif provider not in ROUTER_DRIVERS:

        raise nexc.ProviderNotFound(provider=provider)

    return provider

def get_driver_by_provider(provider):

    if provider is None:

        provider = config.PROVIDER.default_router_provider

    elif provider not in ROUTER_DRIVERS:

        raise nexc.ProviderNotFound(provider=provider)

    return ROUTER_DRIVERS[provider]

**** CubicPower OpenStack Study ****

def load_driver(plugin, ofc_manager):

    if (PROVIDER_OPENFLOW in ROUTER_DRIVER_MAP and

        not ofc_manager.driver.router_supported):

        LOG.warning(

            _('OFC does not support router with provider=%(provider)s, '

              'so removed it from supported provider '

              '(new router driver map=%(driver_map)s)'),

            {'provider': PROVIDER_OPENFLOW,

             'driver_map': ROUTER_DRIVER_MAP})

        del ROUTER_DRIVER_MAP[PROVIDER_OPENFLOW]

    if config.PROVIDER.default_router_provider not in ROUTER_DRIVER_MAP:

        LOG.error(_('default_router_provider %(default)s is supported! '

                    'Please specify one of %(supported)s'),

                  {'default': config.PROVIDER.default_router_provider,

                   'supported': ROUTER_DRIVER_MAP.keys()})

        raise SystemExit(1)

    enabled_providers = (set(config.PROVIDER.router_providers +

                             [config.PROVIDER.default_router_provider]) &

                         set(ROUTER_DRIVER_MAP.keys()))

    for driver in enabled_providers:

        driver_klass = importutils.import_class(ROUTER_DRIVER_MAP[driver])

        ROUTER_DRIVERS[driver] = driver_klass(plugin, ofc_manager)

    LOG.info(_('Enabled router drivers: %s'), ROUTER_DRIVERS.keys())

    if not ROUTER_DRIVERS:

        LOG.error(_('No router provider is enabled. neutron-server terminated!'

                    ' (supported=%(supported)s, configured=%(config)s)'),

                  {'supported': ROUTER_DRIVER_MAP.keys(),

                   'config': config.PROVIDER.router_providers})

        raise SystemExit(1)

**** CubicPower OpenStack Study ****

def get_provider_with_default(provider):

    if not attr.is_attr_set(provider):

        provider = config.PROVIDER.default_router_provider

    elif provider not in ROUTER_DRIVERS:

        raise nexc.ProviderNotFound(provider=provider)

    return provider

**** CubicPower OpenStack Study ****

def get_driver_by_provider(provider):

    if provider is None:

        provider = config.PROVIDER.default_router_provider

    elif provider not in ROUTER_DRIVERS:

        raise nexc.ProviderNotFound(provider=provider)

    return ROUTER_DRIVERS[provider]