d77da01dcb
Based on the openstack networking-sfc project API: - Introducing an SFC driver that maps the SFC model (port pairs, port pair groups, port chains) to the AIM Service Graph model; - Introducing a FlowClassifier driver that maps the FLOWC model (flow classifier) to the AIM Service Graph model; - Adding some registry notifications to the AIM MD and the FLOWC driver for business logic validation. Current divergence/limitations from the upstream SFC API: - Added 2 l7_parameters to the flow classifier API, source_logica_network and destination_logical_network. Representing the networks involved in the traffic redirection mechanism; - Every valid flow classifier must include the l7_parameters as mentioned above. Internal networks and SVI networks are valid values, but --external networks are excluded; When SVI networks are specified, the corresponding source/destination IP prefix must be specified in the API; - Any other FlowClassifier parameter other than the ones mentioned above will be ignored; - On port binding, the chain will fix itself; - Trunk ports are supported on port-pairs; - On PPGs, all the Port Pairs must be in the same network pair; - Ports in Port Pairs must have a univocally retrievable APIC Domain; - Ports in Port Pairs can't be in the same network; - Flowc src/dst networks must be distinct; - Flowc can't be updated if in use by a chain; - Networks partecipating a port chain must be in the same VRF; - Src and Dst networks in a chain must be in the same tenant (temporarily); - Port Pair's ports' network can't be external or SVI; - Port Pair's ports' networks can't be re-used in the same PPG. Change-Id: If40595584ef46f1ac2aa0cf7525e16447f491f48
149 lines
6.0 KiB
Python
149 lines
6.0 KiB
Python
# Copyright (c) 2016 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 oslo_log import log
|
|
|
|
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import exceptions
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
PROJECT_TYPE_TAG = 'prj'
|
|
NETWORK_TYPE_TAG = 'net'
|
|
ADDRESS_SCOPE_TYPE_TAG = 'as'
|
|
ROUTER_TYPE_TAG = 'rtr'
|
|
L3_POLICY_TYPE_TAG = 'l3p'
|
|
POLICY_RULE_SET_TYPE_TAG = 'prs'
|
|
POLICY_RULE_TYPE_TAG = 'pr'
|
|
APPLICATION_POLICY_GROUP_TYPE_TAG = 'apg'
|
|
PORT_PAIR_GROUP_TYPE_TAG = 'ppg'
|
|
PORT_PAIR_TYPE_TAG = 'pp'
|
|
PORT_TYPE_TAG = 'prt'
|
|
FLOW_CLASSIFIER_TYPE_TAG = 'flc'
|
|
PORT_CHAIN_TYPE_TAG = 'ptc'
|
|
|
|
|
|
class APICNameMapper(object):
|
|
# This class may be overriden to customize the mapping from
|
|
# OpenStack resource IDs to APIC resource names. Prefixes can be
|
|
# supplied in order to allow mapping a single OpenStack resource
|
|
# to multiple APIC resources of the same type. There are reverse
|
|
# mapping methods for most resources, but there is no
|
|
# reverse_project method because of potential use cases for
|
|
# mapping multiple OpenStack project IDs to the same APIC Tenant.
|
|
|
|
def project(self, session, id, prefix=""):
|
|
# REVISIT: The external connectiviy unit tests pass "common"
|
|
# as a project_id, and expect this to be mapped to the AIM
|
|
# common Tenant. Its not clear how a real deployment using
|
|
# Keystone would arrange to have "common" as a valid
|
|
# project_id, so maybe this special handling is not really
|
|
# needed.
|
|
return (id if id == "common" else
|
|
self._map(session, id, PROJECT_TYPE_TAG, prefix))
|
|
|
|
def network(self, session, id, prefix=""):
|
|
return self._map(session, id, NETWORK_TYPE_TAG, prefix)
|
|
|
|
def reverse_network(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, NETWORK_TYPE_TAG, prefix, enforce)
|
|
|
|
def address_scope(self, session, id, prefix=""):
|
|
return self._map(session, id, ADDRESS_SCOPE_TYPE_TAG, prefix)
|
|
|
|
def reverse_address_scope(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, ADDRESS_SCOPE_TYPE_TAG, prefix, enforce)
|
|
|
|
def router(self, session, id, prefix=""):
|
|
return self._map(session, id, ROUTER_TYPE_TAG, prefix)
|
|
|
|
def reverse_router(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, ROUTER_TYPE_TAG, prefix, enforce)
|
|
|
|
def l3_policy(self, session, id, prefix=""):
|
|
return self._map(session, id, L3_POLICY_TYPE_TAG, prefix)
|
|
|
|
def reverse_l3_policy(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, L3_POLICY_TYPE_TAG, prefix, enforce)
|
|
|
|
def policy_rule_set(self, session, id, prefix=""):
|
|
return self._map(session, id, POLICY_RULE_SET_TYPE_TAG, prefix)
|
|
|
|
def reverse_policy_rule_set(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, POLICY_RULE_SET_TYPE_TAG, prefix, enforce)
|
|
|
|
def policy_rule(self, session, id, prefix=""):
|
|
return self._map(session, id, POLICY_RULE_TYPE_TAG, prefix)
|
|
|
|
def reverse_policy_rule(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, POLICY_RULE_TYPE_TAG, prefix, enforce)
|
|
|
|
def application_policy_group(self, session, id, prefix=""):
|
|
return self._map(
|
|
session, id, APPLICATION_POLICY_GROUP_TYPE_TAG, prefix)
|
|
|
|
def reverse_application_policy_group(
|
|
self, session, name, prefix="", enforce=True):
|
|
return self._unmap(
|
|
session, name, APPLICATION_POLICY_GROUP_TYPE_TAG, prefix, enforce)
|
|
|
|
def port_pair_group(self, session, id, prefix=""):
|
|
return self._map(session, id, PORT_PAIR_GROUP_TYPE_TAG, prefix)
|
|
|
|
def reverse_port_pair_group(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, PORT_PAIR_GROUP_TYPE_TAG, prefix,
|
|
enforce)
|
|
|
|
def port_pair(self, session, id, prefix=""):
|
|
return self._map(session, id, PORT_PAIR_TYPE_TAG, prefix)
|
|
|
|
def reverse_port_pair(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, PORT_PAIR_TYPE_TAG, prefix, enforce)
|
|
|
|
def port(self, session, id, prefix=""):
|
|
return self._map(session, id, PORT_TYPE_TAG, prefix)
|
|
|
|
def reverse_port(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, PORT_TYPE_TAG, prefix, enforce)
|
|
|
|
def flow_classifier(self, session, id, prefix=""):
|
|
return self._map(session, id, FLOW_CLASSIFIER_TYPE_TAG, prefix)
|
|
|
|
def reverse_flow_classifier(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, FLOW_CLASSIFIER_TYPE_TAG, prefix,
|
|
enforce)
|
|
|
|
def port_chain(self, session, id, prefix=""):
|
|
return self._map(session, id, PORT_CHAIN_TYPE_TAG, prefix)
|
|
|
|
def reverse_port_chain(self, session, name, prefix="", enforce=True):
|
|
return self._unmap(session, name, PORT_CHAIN_TYPE_TAG, prefix, enforce)
|
|
|
|
def _map(self, session, id, type_tag, prefix):
|
|
return ("%(prefix)s%(type_tag)s_%(id)s" %
|
|
{'prefix': prefix, 'type_tag': type_tag, 'id': id})
|
|
|
|
def _unmap(self, session, name, type_tag, prefix, enforce):
|
|
pos = len(prefix) + len(type_tag) + 1
|
|
if self._map(session, "", type_tag, prefix) == name[:pos]:
|
|
return name[pos:]
|
|
elif enforce:
|
|
msg = _("Attempted to reverse-map invalid APIC name '%s'") % name
|
|
raise exceptions.InternalError(details=msg)
|