¡@

Home 

OpenStack Study: cisco_csr_db.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright 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.

#

# @author: Paul Michali, Cisco Systems, Inc.

import sqlalchemy as sa

from sqlalchemy.orm import exc as sql_exc

from neutron.common import exceptions

from neutron.db import model_base

from neutron.db import models_v2

from neutron.db.vpn import vpn_db

from neutron.openstack.common.db import exception as db_exc

from neutron.openstack.common import log as logging

LOG = logging.getLogger(__name__)

# Note: Artificially limit these to reduce mapping table size and performance

# Tunnel can be 0..7FFFFFFF, IKE policy can be 1..10000, IPSec policy can be

# 1..31 characters long.

MAX_CSR_TUNNELS = 10000

MAX_CSR_IKE_POLICIES = 2000

MAX_CSR_IPSEC_POLICIES = 2000

TUNNEL = 'Tunnel'

IKE_POLICY = 'IKE Policy'

IPSEC_POLICY = 'IPSec Policy'

MAPPING_LIMITS = {TUNNEL: (0, MAX_CSR_TUNNELS),

IKE_POLICY: (1, MAX_CSR_IKE_POLICIES),

IPSEC_POLICY: (1, MAX_CSR_IPSEC_POLICIES)}

**** CubicPower OpenStack Study ****

class CsrInternalError(exceptions.NeutronException):

message = _("Fatal - %(reason)s")

**** CubicPower OpenStack Study ****

class IdentifierMap(model_base.BASEV2, models_v2.HasTenant):

"""Maps OpenStack IDs to compatible numbers for Cisco CSR."""

__tablename__ = 'cisco_csr_identifier_map'

ipsec_site_conn_id = sa.Column(sa.String(64),

sa.ForeignKey('ipsec_site_connections.id',

ondelete="CASCADE"),

primary_key=True)

csr_tunnel_id = sa.Column(sa.Integer, nullable=False)

csr_ike_policy_id = sa.Column(sa.Integer, nullable=False)

csr_ipsec_policy_id = sa.Column(sa.Integer, nullable=False)

**** CubicPower OpenStack Study ****

def get_next_available_id(session, table_field, id_type):

    """Find first unused id for the specified field in IdentifierMap table.

    As entries are removed, find the first "hole" and return that as the

    next available ID. To improve performance, artificially limit

    the number of entries to a smaller range. Currently, these IDs are

    globally unique. Could enhance in the future to be unique per router

    (CSR).

    """

    min_value = MAPPING_LIMITS[id_type][0]

    max_value = MAPPING_LIMITS[id_type][1]

    rows = session.query(table_field).order_by(table_field)

    used_ids = set([row[0] for row in rows])

    all_ids = set(range(min_value, max_value + min_value))

    available_ids = all_ids - used_ids

    if not available_ids:

        msg = _("No available Cisco CSR %(type)s IDs from "

                "%(min)d..%(max)d") % {'type': id_type,

                                       'min': min_value,

                                       'max': max_value}

        LOG.error(msg)

        raise IndexError(msg)

    return available_ids.pop()

**** CubicPower OpenStack Study ****

def get_next_available_tunnel_id(session):

    """Find first available tunnel ID from 0..MAX_CSR_TUNNELS-1."""

    return get_next_available_id(session, IdentifierMap.csr_tunnel_id,

                                 TUNNEL)

**** CubicPower OpenStack Study ****

def get_next_available_ike_policy_id(session):

    """Find first available IKE Policy ID from 1..MAX_CSR_IKE_POLICIES."""

    return get_next_available_id(session, IdentifierMap.csr_ike_policy_id,

                                 IKE_POLICY)

**** CubicPower OpenStack Study ****

def get_next_available_ipsec_policy_id(session):

    """Find first available IPSec Policy ID from 1..MAX_CSR_IKE_POLICIES."""

    return get_next_available_id(session, IdentifierMap.csr_ipsec_policy_id,

                                 IPSEC_POLICY)

**** CubicPower OpenStack Study ****

def find_conn_with_policy(policy_field, policy_id, conn_id, session):

    """Return ID of another conneciton (if any) that uses same policy ID."""

    qry = session.query(vpn_db.IPsecSiteConnection.id)

    match = qry.filter_request(

        policy_field == policy_id,

        vpn_db.IPsecSiteConnection.id != conn_id).first()

    if match:

        return match[0]

**** CubicPower OpenStack Study ****

def find_connection_using_ike_policy(ike_policy_id, conn_id, session):

    """Return ID of another connection that uses same IKE policy ID."""

    return find_conn_with_policy(vpn_db.IPsecSiteConnection.ikepolicy_id,

                                 ike_policy_id, conn_id, session)

**** CubicPower OpenStack Study ****

def find_connection_using_ipsec_policy(ipsec_policy_id, conn_id, session):

    """Return ID of another connection that uses same IPSec policy ID."""

    return find_conn_with_policy(vpn_db.IPsecSiteConnection.ipsecpolicy_id,

                                 ipsec_policy_id, conn_id, session)

**** CubicPower OpenStack Study ****

def lookup_policy(policy_type, policy_field, conn_id, session):

    """Obtain specified policy's mapping from other connection."""

    try:

        return session.query(policy_field).filter_by(

            ipsec_site_conn_id=conn_id).one()[0]

    except sql_exc.NoResultFound:

        msg = _("Database inconsistency between IPSec connection and "

                "Cisco CSR mapping table (%s)") % policy_type

        raise CsrInternalError(reason=msg)

**** CubicPower OpenStack Study ****

def lookup_ike_policy_id_for(conn_id, session):

    """Obtain existing Cisco CSR IKE policy ID from another connection."""

    return lookup_policy(IKE_POLICY, IdentifierMap.csr_ike_policy_id,

                         conn_id, session)

**** CubicPower OpenStack Study ****

def lookup_ipsec_policy_id_for(conn_id, session):

    """Obtain existing Cisco CSR IPSec policy ID from another connection."""

    return lookup_policy(IPSEC_POLICY, IdentifierMap.csr_ipsec_policy_id,

                         conn_id, session)

**** CubicPower OpenStack Study ****

def determine_csr_policy_id(policy_type, conn_policy_field, map_policy_field,

                            policy_id, conn_id, session):

    """Use existing or reserve a new policy ID for Cisco CSR use.

    TODO(pcm) FUTURE: Once device driver adds support for IKE/IPSec policy

    ID sharing, add call to find_conn_with_policy() to find used ID and

    then call lookup_policy() to find the current mapping for that ID.

    """

    csr_id = get_next_available_id(session, map_policy_field, policy_type)

    LOG.debug(_("Reserved new CSR ID %(csr_id)d for %(policy)s "

                "ID %(policy_id)s"), {'csr_id': csr_id,

                                      'policy': policy_type,

                                      'policy_id': policy_id})

    return csr_id

**** CubicPower OpenStack Study ****

def determine_csr_ike_policy_id(ike_policy_id, conn_id, session):

    """Use existing, or reserve a new IKE policy ID for Cisco CSR."""

    return determine_csr_policy_id(IKE_POLICY,

                                   vpn_db.IPsecSiteConnection.ikepolicy_id,

                                   IdentifierMap.csr_ike_policy_id,

                                   ike_policy_id, conn_id, session)

**** CubicPower OpenStack Study ****

def determine_csr_ipsec_policy_id(ipsec_policy_id, conn_id, session):

    """Use existing, or reserve a new IPSec policy ID for Cisco CSR."""

    return determine_csr_policy_id(IPSEC_POLICY,

                                   vpn_db.IPsecSiteConnection.ipsecpolicy_id,

                                   IdentifierMap.csr_ipsec_policy_id,

                                   ipsec_policy_id, conn_id, session)

**** CubicPower OpenStack Study ****

def get_tunnel_mapping_for(conn_id, session):

    try:

        entry = session.query(IdentifierMap).filter_by(

            ipsec_site_conn_id=conn_id).one()

        LOG.debug(_("Mappings for IPSec connection %(conn)s - "

                    "tunnel=%(tunnel)s ike_policy=%(csr_ike)d "

                    "ipsec_policy=%(csr_ipsec)d"),

                  {'conn': conn_id, 'tunnel': entry.csr_tunnel_id,

                   'csr_ike': entry.csr_ike_policy_id,

                   'csr_ipsec': entry.csr_ipsec_policy_id})

        return (entry.csr_tunnel_id, entry.csr_ike_policy_id,

                entry.csr_ipsec_policy_id)

    except sql_exc.NoResultFound:

        msg = _("Existing entry for IPSec connection %s not found in Cisco "

                "CSR mapping table") % conn_id

        raise CsrInternalError(reason=msg)

**** CubicPower OpenStack Study ****

def create_tunnel_mapping(context, conn_info):

    """Create Cisco CSR IDs, using mapping table and OpenStack UUIDs."""

    conn_id = conn_info['id']

    ike_policy_id = conn_info['ikepolicy_id']

    ipsec_policy_id = conn_info['ipsecpolicy_id']

    tenant_id = conn_info['tenant_id']

    with context.session.begin():

        csr_tunnel_id = get_next_available_tunnel_id(context.session)

        csr_ike_id = determine_csr_ike_policy_id(ike_policy_id, conn_id,

                                                 context.session)

        csr_ipsec_id = determine_csr_ipsec_policy_id(ipsec_policy_id, conn_id,

                                                     context.session)

        map_entry = IdentifierMap(tenant_id=tenant_id,

                                  ipsec_site_conn_id=conn_id,

                                  csr_tunnel_id=csr_tunnel_id,

                                  csr_ike_policy_id=csr_ike_id,

                                  csr_ipsec_policy_id=csr_ipsec_id)

        try:

            context.session.add(map_entry)

            # Force committing to database

            context.session.flush()

        except db_exc.DBDuplicateEntry:

            msg = _("Attempt to create duplicate entry in Cisco CSR "

                    "mapping table for connection %s") % conn_id

            raise CsrInternalError(reason=msg)

        LOG.info(_("Mapped connection %(conn_id)s to Tunnel%(tunnel_id)d "

                   "using IKE policy ID %(ike_id)d and IPSec policy "

                   "ID %(ipsec_id)d"),

                 {'conn_id': conn_id, 'tunnel_id': csr_tunnel_id,

                  'ike_id': csr_ike_id, 'ipsec_id': csr_ipsec_id})

**** CubicPower OpenStack Study ****

def delete_tunnel_mapping(context, conn_info):

    conn_id = conn_info['id']

    with context.session.begin():

        sess_qry = context.session.query(IdentifierMap)

        sess_qry.filter_by(ipsec_site_conn_id=conn_id).delete()

    LOG.info(_("Removed mapping for connection %s"), conn_id)