¡@

Home 

OpenStack Study: cisco_ipsec.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.

import netaddr

from netaddr import core as net_exc

from neutron.common import exceptions

from neutron.common import rpc as n_rpc

from neutron.openstack.common import excutils

from neutron.openstack.common import log as logging

from neutron.openstack.common import rpc

from neutron.plugins.common import constants

from neutron.services.vpn.common import topics

from neutron.services.vpn import service_drivers

from neutron.services.vpn.service_drivers import cisco_csr_db as csr_id_map

LOG = logging.getLogger(__name__)

IPSEC = 'ipsec'

BASE_IPSEC_VERSION = '1.0'

LIFETIME_LIMITS = {'IKE Policy': {'min': 60, 'max': 86400},

'IPSec Policy': {'min': 120, 'max': 2592000}}

MIN_CSR_MTU = 1500

MAX_CSR_MTU = 9192

**** CubicPower OpenStack Study ****

class CsrValidationFailure(exceptions.BadRequest):

message = _("Cisco CSR does not support %(resource)s attribute %(key)s "

"with value '%(value)s'")

**** CubicPower OpenStack Study ****

class CsrUnsupportedError(exceptions.NeutronException):

message = _("Cisco CSR does not currently support %(capability)s")

**** CubicPower OpenStack Study ****

class CiscoCsrIPsecVpnDriverCallBack(object):

"""Handler for agent to plugin RPC messaging."""

# history

# 1.0 Initial version

RPC_API_VERSION = BASE_IPSEC_VERSION

**** CubicPower OpenStack Study ****

    def __init__(self, driver):

        self.driver = driver

**** CubicPower OpenStack Study ****

    def create_rpc_dispatcher(self):

        return n_rpc.PluginRpcDispatcher([self])

**** CubicPower OpenStack Study ****

    def get_vpn_services_on_host(self, context, host=None):

        """Retuns info on the vpnservices on the host."""

        plugin = self.driver.service_plugin

        vpnservices = plugin._get_agent_hosting_vpn_services(

            context, host)

        return [self.driver._make_vpnservice_dict(vpnservice, context)

                for vpnservice in vpnservices]

**** CubicPower OpenStack Study ****

    def update_status(self, context, status):

        """Update status of all vpnservices."""

        plugin = self.driver.service_plugin

        plugin.update_status_by_agent(context, status)

**** CubicPower OpenStack Study ****

class CiscoCsrIPsecVpnAgentApi(service_drivers.BaseIPsecVpnAgentApi):

"""API and handler for Cisco IPSec plugin to agent RPC messaging."""

RPC_API_VERSION = BASE_IPSEC_VERSION

**** CubicPower OpenStack Study ****

    def __init__(self, topic, default_version):

        super(CiscoCsrIPsecVpnAgentApi, self).__init__(

            topics.CISCO_IPSEC_AGENT_TOPIC, topic, default_version)

**** CubicPower OpenStack Study ****

class CiscoCsrIPsecVPNDriver(service_drivers.VpnDriver):

"""Cisco CSR VPN Service Driver class for IPsec."""

**** CubicPower OpenStack Study ****

    def __init__(self, service_plugin):

        super(CiscoCsrIPsecVPNDriver, self).__init__(service_plugin)

        self.callbacks = CiscoCsrIPsecVpnDriverCallBack(self)

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

        self.conn.create_consumer(

            topics.CISCO_IPSEC_DRIVER_TOPIC,

            self.callbacks.create_rpc_dispatcher(),

            fanout=False)

        self.conn.consume_in_thread()

        self.agent_rpc = CiscoCsrIPsecVpnAgentApi(

            topics.CISCO_IPSEC_AGENT_TOPIC, BASE_IPSEC_VERSION)

    @property

**** CubicPower OpenStack Study ****

    def service_type(self):

        return IPSEC

**** CubicPower OpenStack Study ****

    def validate_lifetime(self, for_policy, policy_info):

        """Ensure lifetime in secs and value is supported, based on policy."""

        units = policy_info['lifetime']['units']

        if units != 'seconds':

            raise CsrValidationFailure(resource=for_policy,

                                       key='lifetime:units',

                                       value=units)

        value = policy_info['lifetime']['value']

        if (value < LIFETIME_LIMITS[for_policy]['min'] or

            value > LIFETIME_LIMITS[for_policy]['max']):

            raise CsrValidationFailure(resource=for_policy,

                                       key='lifetime:value',

                                       value=value)

**** CubicPower OpenStack Study ****

    def validate_ike_version(self, policy_info):

        """Ensure IKE policy is v1 for current REST API."""

        version = policy_info['ike_version']

        if version != 'v1':

            raise CsrValidationFailure(resource='IKE Policy',

                                       key='ike_version',

                                       value=version)

**** CubicPower OpenStack Study ****

    def validate_mtu(self, conn_info):

        """Ensure the MTU value is supported."""

        mtu = conn_info['mtu']

        if mtu < MIN_CSR_MTU or mtu > MAX_CSR_MTU:

            raise CsrValidationFailure(resource='IPSec Connection',

                                       key='mtu',

                                       value=mtu)

**** CubicPower OpenStack Study ****

    def validate_public_ip_present(self, vpn_service):

        """Ensure there is one gateway IP specified for the router used."""

        gw_port = vpn_service.router.gw_port

        if not gw_port or len(gw_port.fixed_ips) != 1:

            raise CsrValidationFailure(resource='IPSec Connection',

                                       key='router:gw_port:ip_address',

                                       value='missing')

**** CubicPower OpenStack Study ****

    def validate_peer_id(self, ipsec_conn):

        """Ensure that an IP address is specified for peer ID."""

        # TODO(pcm) Should we check peer_address too?

        peer_id = ipsec_conn['peer_id']

        try:

            netaddr.IPAddress(peer_id)

        except net_exc.AddrFormatError:

            raise CsrValidationFailure(resource='IPSec Connection',

                                       key='peer_id', value=peer_id)

**** CubicPower OpenStack Study ****

    def validate_ipsec_connection(self, context, ipsec_conn, vpn_service):

        """Validate attributes w.r.t. Cisco CSR capabilities."""

        ike_policy = self.service_plugin.get_ikepolicy(

            context, ipsec_conn['ikepolicy_id'])

        ipsec_policy = self.service_plugin.get_ipsecpolicy(

            context, ipsec_conn['ipsecpolicy_id'])

        self.validate_lifetime('IKE Policy', ike_policy)

        self.validate_lifetime('IPSec Policy', ipsec_policy)

        self.validate_ike_version(ike_policy)

        self.validate_mtu(ipsec_conn)

        self.validate_public_ip_present(vpn_service)

        self.validate_peer_id(ipsec_conn)

        LOG.debug(_("IPSec connection %s validated for Cisco CSR"),

                  ipsec_conn['id'])

**** CubicPower OpenStack Study ****

    def create_ipsec_site_connection(self, context, ipsec_site_connection):

        vpnservice = self.service_plugin._get_vpnservice(

            context, ipsec_site_connection['vpnservice_id'])

        try:

            self.validate_ipsec_connection(context, ipsec_site_connection,

                                           vpnservice)

        except CsrValidationFailure:

            with excutils.save_and_reraise_exception():

                self.service_plugin.update_ipsec_site_conn_status(

                    context, ipsec_site_connection['id'], constants.ERROR)

        csr_id_map.create_tunnel_mapping(context, ipsec_site_connection)

        self.agent_rpc.vpnservice_updated(context, vpnservice['router_id'],

                                          reason='ipsec-conn-create')

**** CubicPower OpenStack Study ****

    def update_ipsec_site_connection(

        self, context, old_ipsec_site_connection, ipsec_site_connection):

        capability = _("update of IPSec connections. You can delete and "

                       "re-add, as a workaround.")

        raise CsrUnsupportedError(capability=capability)

**** CubicPower OpenStack Study ****

    def delete_ipsec_site_connection(self, context, ipsec_site_connection):

        vpnservice = self.service_plugin._get_vpnservice(

            context, ipsec_site_connection['vpnservice_id'])

        self.agent_rpc.vpnservice_updated(context, vpnservice['router_id'],

                                          reason='ipsec-conn-delete')

**** CubicPower OpenStack Study ****

    def create_ikepolicy(self, context, ikepolicy):

        pass

**** CubicPower OpenStack Study ****

    def delete_ikepolicy(self, context, ikepolicy):

        pass

**** CubicPower OpenStack Study ****

    def update_ikepolicy(self, context, old_ikepolicy, ikepolicy):

        pass

**** CubicPower OpenStack Study ****

    def create_ipsecpolicy(self, context, ipsecpolicy):

        pass

**** CubicPower OpenStack Study ****

    def delete_ipsecpolicy(self, context, ipsecpolicy):

        pass

**** CubicPower OpenStack Study ****

    def update_ipsecpolicy(self, context, old_ipsec_policy, ipsecpolicy):

        pass

**** CubicPower OpenStack Study ****

    def create_vpnservice(self, context, vpnservice):

        pass

**** CubicPower OpenStack Study ****

    def update_vpnservice(self, context, old_vpnservice, vpnservice):

        self.agent_rpc.vpnservice_updated(context, vpnservice['router_id'],

                                          reason='vpn-service-update')

**** CubicPower OpenStack Study ****

    def delete_vpnservice(self, context, vpnservice):

        self.agent_rpc.vpnservice_updated(context, vpnservice['router_id'],

                                          reason='vpn-service-delete')

**** CubicPower OpenStack Study ****

    def get_cisco_connection_mappings(self, conn_id, context):

        """Obtain persisted mappings for IDs related to connection."""

        tunnel_id, ike_id, ipsec_id = csr_id_map.get_tunnel_mapping_for(

            conn_id, context.session)

        return {'site_conn_id': u'Tunnel%d' % tunnel_id,

                'ike_policy_id': u'%d' % ike_id,

                'ipsec_policy_id': u'%s' % ipsec_id}

**** CubicPower OpenStack Study ****

    def _make_vpnservice_dict(self, vpnservice, context):

        """Collect all info on service, including Cisco info per IPSec conn."""

        vpnservice_dict = dict(vpnservice)

        vpnservice_dict['ipsec_conns'] = []

        vpnservice_dict['subnet'] = dict(

            vpnservice.subnet)

        vpnservice_dict['external_ip'] = vpnservice.router.gw_port[

            'fixed_ips'][0]['ip_address']

        for ipsec_conn in vpnservice.ipsec_site_connections:

            ipsec_conn_dict = dict(ipsec_conn)

            ipsec_conn_dict['ike_policy'] = dict(ipsec_conn.ikepolicy)

            ipsec_conn_dict['ipsec_policy'] = dict(ipsec_conn.ipsecpolicy)

            ipsec_conn_dict['peer_cidrs'] = [

                peer_cidr.cidr for peer_cidr in ipsec_conn.peer_cidrs]

            ipsec_conn_dict['cisco'] = self.get_cisco_connection_mappings(

                ipsec_conn['id'], context)

            vpnservice_dict['ipsec_conns'].append(ipsec_conn_dict)

        return vpnservice_dict