neutron/neutron/services/l3_router/l3_apic.py

185 lines
7.5 KiB
Python

# Copyright (c) 2014 Cisco Systems Inc.
# 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.
from apicapi import apic_mapper
from oslo_utils import excutils
from neutron.db import db_base_plugin_v2
from neutron.db import extraroute_db
from neutron.db import l3_dvr_db
from neutron.plugins.common import constants
from neutron.plugins.ml2.drivers.cisco.apic import mechanism_apic
class ApicL3ServicePlugin(db_base_plugin_v2.NeutronDbPluginV2,
l3_dvr_db.L3_NAT_with_dvr_db_mixin,
extraroute_db.ExtraRoute_db_mixin):
supported_extension_aliases = ["router", "ext-gw-mode", "extraroute"]
def __init__(self):
super(ApicL3ServicePlugin, self).__init__()
self.manager = mechanism_apic.APICMechanismDriver.get_apic_manager()
self.name_mapper = self.manager.apic_mapper
self.synchronizer = None
self.manager.ensure_infra_created_on_apic()
self.manager.ensure_bgp_pod_policy_created_on_apic()
def _map_names(self, context,
tenant_id, router_id, net_id, subnet_id):
context._plugin = self
with apic_mapper.mapper_context(context) as ctx:
atenant_id = tenant_id and self.name_mapper.tenant(ctx, tenant_id)
arouter_id = router_id and self.name_mapper.router(ctx, router_id)
anet_id = net_id and self.name_mapper.network(ctx, net_id)
asubnet_id = subnet_id and self.name_mapper.subnet(ctx, subnet_id)
return atenant_id, arouter_id, anet_id, asubnet_id
@staticmethod
def get_plugin_type():
return constants.L3_ROUTER_NAT
@staticmethod
def get_plugin_description():
"""Returns string description of the plugin."""
return _("L3 Router Service Plugin for basic L3 using the APIC")
def sync_init(f):
def inner(inst, *args, **kwargs):
if not inst.synchronizer:
inst.synchronizer = (
mechanism_apic.APICMechanismDriver.
get_router_synchronizer(inst))
inst.synchronizer.sync_router()
# pylint: disable=not-callable
return f(inst, *args, **kwargs)
return inner
def add_router_interface_postcommit(self, context, router_id,
interface_info):
# Update router's state first
router = self.get_router(context, router_id)
self.update_router_postcommit(context, router)
# Add router interface
if 'subnet_id' in interface_info:
subnet = self.get_subnet(context, interface_info['subnet_id'])
network_id = subnet['network_id']
tenant_id = subnet['tenant_id']
else:
port = self.get_port(context, interface_info['port_id'])
network_id = port['network_id']
tenant_id = port['tenant_id']
# Map openstack IDs to APIC IDs
atenant_id, arouter_id, anetwork_id, _ = self._map_names(
context, tenant_id, router_id, network_id, None)
# Program APIC
self.manager.add_router_interface(atenant_id, arouter_id,
anetwork_id)
def remove_router_interface_precommit(self, context, router_id,
interface_info):
if 'subnet_id' in interface_info:
subnet = self.get_subnet(context, interface_info['subnet_id'])
network_id = subnet['network_id']
tenant_id = subnet['tenant_id']
else:
port = self.get_port(context, interface_info['port_id'])
network_id = port['network_id']
tenant_id = port['tenant_id']
# Map openstack IDs to APIC IDs
atenant_id, arouter_id, anetwork_id, _ = self._map_names(
context, tenant_id, router_id, network_id, None)
# Program APIC
self.manager.remove_router_interface(atenant_id, arouter_id,
anetwork_id)
def delete_router_precommit(self, context, router_id):
context._plugin = self
with apic_mapper.mapper_context(context) as ctx:
arouter_id = router_id and self.name_mapper.router(ctx, router_id)
self.manager.delete_router(arouter_id)
def update_router_postcommit(self, context, router):
context._plugin = self
with apic_mapper.mapper_context(context) as ctx:
arouter_id = router['id'] and self.name_mapper.router(ctx,
router['id'])
with self.manager.apic.transaction() as trs:
self.manager.create_router(arouter_id, transaction=trs)
if router['admin_state_up']:
self.manager.enable_router(arouter_id, transaction=trs)
else:
self.manager.disable_router(arouter_id, transaction=trs)
# Router API
@sync_init
def create_router(self, *args, **kwargs):
return super(ApicL3ServicePlugin, self).create_router(*args, **kwargs)
@sync_init
def update_router(self, context, id, router):
result = super(ApicL3ServicePlugin, self).update_router(context,
id, router)
self.update_router_postcommit(context, result)
return result
@sync_init
def get_router(self, *args, **kwargs):
return super(ApicL3ServicePlugin, self).get_router(*args, **kwargs)
@sync_init
def get_routers(self, *args, **kwargs):
return super(ApicL3ServicePlugin, self).get_routers(*args, **kwargs)
@sync_init
def get_routers_count(self, *args, **kwargs):
return super(ApicL3ServicePlugin, self).get_routers_count(*args,
**kwargs)
def delete_router(self, context, router_id):
self.delete_router_precommit(context, router_id)
result = super(ApicL3ServicePlugin, self).delete_router(context,
router_id)
return result
# Router Interface API
@sync_init
def add_router_interface(self, context, router_id, interface_info):
# Create interface in parent
result = super(ApicL3ServicePlugin, self).add_router_interface(
context, router_id, interface_info)
try:
self.add_router_interface_postcommit(context, router_id,
interface_info)
except Exception:
with excutils.save_and_reraise_exception():
# Rollback db operation
super(ApicL3ServicePlugin, self).remove_router_interface(
context, router_id, interface_info)
return result
def remove_router_interface(self, context, router_id, interface_info):
self.remove_router_interface_precommit(context, router_id,
interface_info)
return super(ApicL3ServicePlugin, self).remove_router_interface(
context, router_id, interface_info)