Files
group-based-policy/gbpservice/neutron/services/grouppolicy/drivers/cisco/apic/apic_mapping.py
Ivar Lazzaro 65489bbae4 Apic driver improvements
- Introducing Opflex agent;
- Multiple PTGs per L2Ps;
- Multiple PTGs same subnet.

Change-Id: I5dcb12daed669131270e589a01cee432b53cd61c
2015-07-01 17:38:44 -07:00

1451 lines
68 KiB
Python

# 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 apicapi import apic_manager
from keystoneclient.v2_0 import client as keyclient
from neutron.api.v2 import attributes
from neutron.common import constants as n_constants
from neutron.common import exceptions as n_exc
from neutron.common import rpc as n_rpc
from neutron.common import topics
from neutron import context as nctx
from neutron.extensions import portbindings
from neutron import manager
from neutron.plugins.ml2.drivers.cisco.apic import apic_model
from neutron.plugins.ml2.drivers.cisco.apic import config
from opflexagent import constants as ofcst
from opflexagent import rpc
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslo_log import log as logging
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpdb
from gbpservice.neutron.extensions import group_policy as gpolicy
from gbpservice.neutron.services.grouppolicy.common import constants as g_const
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
from gbpservice.neutron.services.grouppolicy.drivers import (
resource_mapping as api)
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
nova_client as nclient)
from gbpservice.neutron.services.grouppolicy import group_policy_context
LOG = logging.getLogger(__name__)
class PolicyRuleUpdateNotSupportedOnApicDriver(gpexc.GroupPolicyBadRequest):
message = _("Policy rule update is not supported on APIC GBP"
"driver.")
class ExactlyOneActionPerRuleIsSupportedOnApicDriver(
gpexc.GroupPolicyBadRequest):
message = _("Exactly one action per rule is supported on APIC GBP driver.")
class OnlyOneL3PolicyIsAllowedPerExternalSegment(gpexc.GroupPolicyBadRequest):
message = _("Only one L3 Policy per ES is supported on APIC GBP driver.")
class OnlyOneAddressIsAllowedPerExternalSegment(gpexc.GroupPolicyBadRequest):
message = _("Only one ip address on each ES is supported on "
"APIC GBP driver.")
class NoAddressConfiguredOnExternalSegment(gpexc.GroupPolicyBadRequest):
message = _("L3 Policy %(l3p_id)s has no address configured on "
"External Segment %(es_id)s")
class PATNotSupportedByApicDriver(gpexc.GroupPolicyBadRequest):
message = _("Port address translation is not supported by APIC driver.")
class SharedAttributeUpdateNotSupportedOnApic(gpexc.GroupPolicyBadRequest):
message = _("Resource shared attribute update not supported on APIC "
"GBP driver for resource of type %(type)s")
class ExplicitSubnetAssociationNotSupported(gpexc.GroupPolicyBadRequest):
message = _("Explicit subnet association not supported by APIC driver.")
class HierarchicalContractsNotSupported(gpexc.GroupPolicyBadRequest):
message = _("Hierarchical contracts not supported by APIC driver.")
REVERSE_PREFIX = 'reverse-'
SHADOW_PREFIX = 'Shd-'
SERVICE_PREFIX = 'Svc-'
IMPLICIT_PREFIX = 'implicit-'
ANY_PREFIX = 'any-'
PROMISCUOUS_SUFFIX = 'promiscuous'
APIC_OWNED = 'apic_owned_'
PROMISCUOUS_TYPES = [n_constants.DEVICE_OWNER_DHCP,
n_constants.DEVICE_OWNER_LOADBALANCER]
ALLOWING_ACTIONS = [g_const.GP_ACTION_ALLOW, g_const.GP_ACTION_REDIRECT]
REVERTIBLE_PROTOCOLS = [n_constants.PROTO_NAME_TCP.lower()]
class ApicMappingDriver(api.ResourceMappingDriver):
"""Apic Mapping driver for Group Policy plugin.
This driver implements group policy semantics by mapping group
policy resources to various other neutron resources, and leverages
Cisco APIC's backend for enforcing the policies.
"""
me = None
manager = None
@staticmethod
def get_apic_manager(client=True):
if not ApicMappingDriver.manager:
apic_config = cfg.CONF.ml2_cisco_apic
network_config = {
'vlan_ranges': cfg.CONF.ml2_type_vlan.network_vlan_ranges,
'vni_ranges': cfg.CONF.ml2_type_vxlan.vni_ranges,
'switch_dict': config.create_switch_dictionary(),
'vpc_dict': config.create_vpc_dictionary(),
'external_network_dict':
config.create_external_network_dictionary(),
}
apic_system_id = cfg.CONF.apic_system_id
keyclient_param = keyclient if client else None
keystone_authtoken = (cfg.CONF.keystone_authtoken if client else
None)
ApicMappingDriver.manager = apic_manager.APICManager(
apic_model.ApicDbModel(), logging, network_config, apic_config,
keyclient_param, keystone_authtoken, apic_system_id)
ApicMappingDriver.manager.ensure_infra_created_on_apic()
ApicMappingDriver.manager.ensure_bgp_pod_policy_created_on_apic()
return ApicMappingDriver.manager
def initialize(self):
super(ApicMappingDriver, self).initialize()
self._setup_rpc_listeners()
self._setup_rpc()
self.apic_manager = ApicMappingDriver.get_apic_manager()
self.name_mapper = self.apic_manager.apic_mapper
self._gbp_plugin = None
def _setup_rpc_listeners(self):
self.endpoints = [rpc.GBPServerRpcCallback(self)]
self.topic = rpc.TOPIC_OPFLEX
self.conn = n_rpc.create_connection(new=True)
self.conn.create_consumer(self.topic, self.endpoints,
fanout=False)
return self.conn.consume_in_threads()
def _setup_rpc(self):
self.notifier = rpc.AgentNotifierApi(topics.AGENT)
@property
def gbp_plugin(self):
if not self._gbp_plugin:
self._gbp_plugin = (manager.NeutronManager.get_service_plugins()
.get("GROUP_POLICY"))
return self._gbp_plugin
# RPC Method
def get_gbp_details(self, context, **kwargs):
port_id = self._core_plugin._device_to_port_id(
kwargs['device'])
port_context = self._core_plugin.get_bound_port_context(
context, port_id, kwargs['host'])
if not port_context:
LOG.warning(_("Device %(device)s requested by agent "
"%(agent_id)s not found in database"),
{'device': port_id,
'agent_id': kwargs.get('agent_id')})
return
port = port_context.current
# retrieve PTG from a given Port
ptg = self._port_id_to_ptg(context, port['id'])
l2p = self._network_id_to_l2p(context, port['network_id'])
if not ptg and not l2p:
return
context._plugin = self.gbp_plugin
context._plugin_context = context
l2_policy_id = l2p['id']
ptg_tenant = self._tenant_by_sharing_policy(ptg or l2p)
if ptg:
endpoint_group_name = self.name_mapper.policy_target_group(
context, ptg['id'])
else:
endpoint_group_name = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SHADOW_PREFIX)
def is_port_promiscuous(port):
return (port['device_owner'] in PROMISCUOUS_TYPES or
port['name'].endswith(PROMISCUOUS_SUFFIX))
details = {'device': kwargs.get('device'),
'port_id': port_id,
'mac_address': port['mac_address'],
'app_profile_name': str(
self.apic_manager.app_profile_name),
'l2_policy_id': l2_policy_id,
'tenant_id': port['tenant_id'],
'host': port[portbindings.HOST_ID],
'ptg_tenant': str(ptg_tenant),
'endpoint_group_name': str(endpoint_group_name),
'promiscuous_mode': is_port_promiscuous(port)}
if port['device_owner'].startswith('compute:') and port['device_id']:
vm = nclient.NovaClient().get_server(port['device_id'])
details['vm-name'] = vm.name if vm else port['device_id']
return details
def process_port_added(self, plugin_context, port):
pass
def create_policy_action_precommit(self, context):
pass
def create_policy_rule_precommit(self, context):
if ('policy_actions' in context.current and
len(context.current['policy_actions']) != 1):
# TODO(ivar): to be fixed when redirect is supported
raise ExactlyOneActionPerRuleIsSupportedOnApicDriver()
def create_policy_rule_postcommit(self, context, transaction=None):
action = context._plugin.get_policy_action(
context._plugin_context, context.current['policy_actions'][0])
classifier = context._plugin.get_policy_classifier(
context._plugin_context,
context.current['policy_classifier_id'])
if action['action_type'] in ALLOWING_ACTIONS:
port_min, port_max = (
gpdb.GroupPolicyMappingDbPlugin._get_min_max_ports_from_range(
classifier['port_range']))
attrs = {'etherT': 'unspecified'}
if classifier['protocol']:
attrs['etherT'] = 'ip'
attrs['prot'] = classifier['protocol'].lower()
if port_min and port_max:
attrs['dToPort'] = port_max
attrs['dFromPort'] = port_min
tenant = self._tenant_by_sharing_policy(context.current)
policy_rule = self.name_mapper.policy_rule(context,
context.current['id'])
with self.apic_manager.apic.transaction(transaction) as trs:
self.apic_manager.create_tenant_filter(
policy_rule, owner=tenant, transaction=trs, **attrs)
# Also create reverse rule
if attrs.get('prot') in REVERTIBLE_PROTOCOLS:
if attrs['prot'] == n_constants.PROTO_NAME_TCP.lower():
policy_rule = self.name_mapper.policy_rule(
context, context.current['id'],
prefix=REVERSE_PREFIX)
if attrs.get('dToPort') and attrs.get('dFromPort'):
attrs.pop('dToPort')
attrs.pop('dFromPort')
attrs['sToPort'] = port_max
attrs['sFromPort'] = port_min
attrs['tcpRules'] = 'est'
self.apic_manager.create_tenant_filter(
policy_rule, owner=tenant, transaction=trs,
**attrs)
def create_policy_rule_set_precommit(self, context):
if context.current['child_policy_rule_sets']:
raise HierarchicalContractsNotSupported()
def create_policy_rule_set_postcommit(self, context):
# Create APIC policy_rule_set
tenant = self._tenant_by_sharing_policy(context.current)
contract = self.name_mapper.policy_rule_set(context,
context.current['id'])
with self.apic_manager.apic.transaction(None) as trs:
self.apic_manager.create_contract(
contract, owner=tenant, transaction=trs)
rules = self.gbp_plugin.get_policy_rules(
context._plugin_context,
{'id': context.current['policy_rules']})
self._apply_policy_rule_set_rules(
context, context.current, rules, transaction=trs)
def create_policy_target_postcommit(self, context):
if not context.current['port_id']:
self._use_implicit_port(context)
port = self._core_plugin.get_port(context._plugin_context,
context.current['port_id'])
if self._is_port_bound(port):
self._notify_port_update(context._plugin_context, port['id'])
def create_policy_target_group_precommit(self, context):
if context.current['subnets']:
raise ExplicitSubnetAssociationNotSupported()
def create_policy_target_group_postcommit(self, context):
if not context.current['subnets']:
self._use_implicit_subnet(context)
tenant = self._tenant_by_sharing_policy(context.current)
l2_policy = self.name_mapper.l2_policy(context,
context.current['l2_policy_id'])
epg = self.name_mapper.policy_target_group(context,
context.current['id'])
l2_policy_object = context._plugin.get_l2_policy(
context._plugin_context, context.current['l2_policy_id'])
bd_owner = self._tenant_by_sharing_policy(l2_policy_object)
with self.apic_manager.apic.transaction(None) as trs:
self.apic_manager.ensure_epg_created(tenant, epg,
bd_owner=bd_owner,
bd_name=l2_policy)
l2p = context._plugin.get_l2_policy(
context._plugin_context, context.current['l2_policy_id'])
self._configure_epg_service_contract(
context, context.current, l2p, epg, transaction=trs)
self._configure_epg_implicit_contract(
context, context.current, l2p, epg, transaction=trs)
self._manage_ptg_policy_rule_sets(
context, context.current['provided_policy_rule_sets'],
context.current['consumed_policy_rule_sets'], [], [])
def create_l2_policy_precommit(self, context):
self._reject_non_shared_net_on_shared_l2p(context)
def update_l2_policy_precommit(self, context):
self._reject_non_shared_net_on_shared_l2p(context)
self._reject_shared_update(context, 'l2_policy')
def create_l2_policy_postcommit(self, context):
super(ApicMappingDriver, self).create_l2_policy_postcommit(context)
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context,
context.current['l3_policy_id'])
l2_policy = self.name_mapper.l2_policy(context, context.current['id'])
l3_policy_object = context._plugin.get_l3_policy(
context._plugin_context, context.current['l3_policy_id'])
ctx_owner = self._tenant_by_sharing_policy(l3_policy_object)
with self.apic_manager.apic.transaction(None) as trs:
self.apic_manager.ensure_bd_created_on_apic(
tenant, l2_policy, ctx_owner=ctx_owner, ctx_name=l3_policy,
transaction=trs)
# Create neutron port EPG
self._configure_shadow_epg(context, context.current, l2_policy,
transaction=trs)
self._configure_implicit_contract(context, context.current,
transaction=trs)
# Add existing subnets
net_id = context.current['network_id']
subnets = self._core_plugin.get_subnets(context._plugin_context,
{'network_id': [net_id]})
self._manage_l2p_subnets(
context._plugin_context, context.current['id'], subnets, [],
transaction=trs)
def update_l2_policy_postcommit(self, context):
pass
def create_l3_policy_precommit(self, context):
self._check_l3p_es(context)
def create_l3_policy_postcommit(self, context):
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context, context.current['id'])
self.apic_manager.ensure_context_enforced(tenant, l3_policy)
external_segments = context.current['external_segments']
if external_segments:
# Create a L3 ext for each External Segment
ess = context._plugin.get_external_segments(
context._plugin_context,
filters={'id': external_segments.keys()})
for es in ess:
self._plug_l3p_to_es(context, es)
def delete_policy_rule_postcommit(self, context):
for prs in context._plugin.get_policy_rule_sets(
context._plugin_context,
filters={'id': context.current['policy_rule_sets']}):
self._remove_policy_rule_set_rules(context, prs, [context.current])
self._delete_policy_rule_from_apic(context)
def _delete_policy_rule_from_apic(self, context, transaction=None):
tenant = self._tenant_by_sharing_policy(context.current)
policy_rule = self.name_mapper.policy_rule(context,
context.current['id'])
with self.apic_manager.apic.transaction(transaction) as trs:
self.apic_manager.delete_tenant_filter(policy_rule, owner=tenant,
transaction=trs)
# Delete policy reverse rule
policy_rule = self.name_mapper.policy_rule(
context, context.current['id'], prefix=REVERSE_PREFIX)
self.apic_manager.delete_tenant_filter(policy_rule, owner=tenant,
transaction=trs)
def delete_policy_rule_set_precommit(self, context):
# Intercept Parent Call
pass
def delete_policy_rule_set_postcommit(self, context):
tenant = self._tenant_by_sharing_policy(context.current)
contract = self.name_mapper.policy_rule_set(context,
context.current['id'])
self.apic_manager.delete_contract(contract, owner=tenant)
def delete_policy_target_postcommit(self, context):
try:
if context.current['port_id']:
port = self._core_plugin.get_port(context._plugin_context,
context.current['port_id'])
# Delete Neutron's port
port_id = context.current['port_id']
self._cleanup_port(context._plugin_context, port_id)
# Notify the agent. If the port has been deleted by the
# parent method the notification will not be done
self._notify_port_update(context._plugin_context, port['id'])
except n_exc.PortNotFound:
LOG.warn(_("Port %s is missing") % context.current['port_id'])
return
def delete_policy_target_group_precommit(self, context):
pass
def delete_policy_target_group_postcommit(self, context):
tenant = self._tenant_by_sharing_policy(context.current)
ptg = self.name_mapper.policy_target_group(context,
context.current['id'])
self.apic_manager.delete_epg_for_network(tenant, ptg)
def delete_l2_policy_postcommit(self, context):
super(ApicMappingDriver, self).delete_l2_policy_postcommit(context)
tenant = self._tenant_by_sharing_policy(context.current)
l2_policy = self.name_mapper.l2_policy(context, context.current['id'])
with self.apic_manager.apic.transaction(None) as trs:
self.apic_manager.delete_bd_on_apic(
tenant, l2_policy, transaction=trs)
# Delete neutron port EPG
self._delete_shadow_epg(context, context.current, transaction=trs)
self._delete_implicit_contract(context, context.current,
transaction=trs)
def delete_l3_policy_postcommit(self, context):
tenant = self._tenant_by_sharing_policy(context.current)
l3_policy = self.name_mapper.l3_policy(context, context.current['id'])
self.apic_manager.ensure_context_deleted(tenant, l3_policy)
external_segments = context.current['external_segments']
if external_segments:
# Create a L3 ext for each External Segment
ess = context._plugin.get_external_segments(
context._plugin_context,
filters={'id': external_segments.keys()})
for es in ess:
self._unplug_l3p_from_es(context, es)
def update_policy_rule_set_precommit(self, context):
self._reject_shared_update(context, 'policy_rule_set')
self._reject_multiple_redirects_in_prs(context)
if context.current['child_policy_rule_sets']:
raise HierarchicalContractsNotSupported()
# If a redirect action is added (from 0 to one) we have to validate
# the providing and consuming PTGs
old_red_count = self._multiple_pr_redirect_action_number(
context._plugin_context.session, context.original['policy_rules'])
new_red_count = self._multiple_pr_redirect_action_number(
context._plugin_context.session, context.current['policy_rules'])
if new_red_count > old_red_count:
self._validate_new_prs_redirect(context, context.current)
def update_policy_rule_set_postcommit(self, context):
# Update policy_rule_set rules
old_rules = set(context.original['policy_rules'])
new_rules = set(context.current['policy_rules'])
to_add = context._plugin.get_policy_rules(
context._plugin_context, {'id': new_rules - old_rules})
to_remove = context._plugin.get_policy_rules(
context._plugin_context, {'id': old_rules - new_rules})
self._remove_policy_rule_set_rules(context, context.current, to_remove)
self._apply_policy_rule_set_rules(context, context.current, to_add)
def update_policy_target_precommit(self, context):
if (context.original['policy_target_group_id'] !=
context.current['policy_target_group_id']):
if context.current['policy_target_group_id']:
self._validate_pt_port_subnets(context)
def update_policy_target_postcommit(self, context):
if (context.original['policy_target_group_id'] !=
context.current['policy_target_group_id']):
self._notify_port_update(context._plugin_context,
context.current['port_id'])
def update_policy_rule_precommit(self, context):
self._reject_multiple_redirects_in_rule(context)
old_redirect = self._get_redirect_action(context, context.original)
new_redirect = self._get_redirect_action(context, context.current)
if not old_redirect and new_redirect:
# If redirect action is added, check that there's no contract that
# already has a redirect action
for prs in context._plugin.get_policy_rule_sets(
context._plugin_context,
{'id': context.current['policy_rule_sets']}):
# Make sure the PRS can have a new redirect action
self._validate_new_prs_redirect(context, prs)
def update_policy_rule_postcommit(self, context):
self._update_policy_rule_on_apic(context)
def update_policy_action_postcommit(self, context):
pass
def _update_policy_rule_on_apic(self, context):
self._delete_policy_rule_from_apic(context, transaction=None)
# The following only creates the APIC reference
self.create_policy_rule_postcommit(context, transaction=None)
def update_policy_target_group_precommit(self, context):
if set(context.original['subnets']) != set(context.current['subnets']):
raise ExplicitSubnetAssociationNotSupported()
self._reject_shared_update(context, 'policy_target_group')
def update_policy_target_group_postcommit(self, context):
# TODO(ivar): refactor parent to avoid code duplication
orig_provided_policy_rule_sets = context.original[
'provided_policy_rule_sets']
curr_provided_policy_rule_sets = context.current[
'provided_policy_rule_sets']
orig_consumed_policy_rule_sets = context.original[
'consumed_policy_rule_sets']
curr_consumed_policy_rule_sets = context.current[
'consumed_policy_rule_sets']
new_provided_policy_rule_sets = list(
set(curr_provided_policy_rule_sets) - set(
orig_provided_policy_rule_sets))
new_consumed_policy_rule_sets = list(
set(curr_consumed_policy_rule_sets) - set(
orig_consumed_policy_rule_sets))
removed_provided_policy_rule_sets = list(
set(orig_provided_policy_rule_sets) - set(
curr_provided_policy_rule_sets))
removed_consumed_policy_rule_sets = list(
set(orig_consumed_policy_rule_sets) - set(
curr_consumed_policy_rule_sets))
self._manage_ptg_policy_rule_sets(
context, new_provided_policy_rule_sets,
new_consumed_policy_rule_sets, removed_provided_policy_rule_sets,
removed_consumed_policy_rule_sets)
def update_l3_policy_precommit(self, context):
self._reject_shared_update(context, 'l3_policy')
self._check_l3p_es(context)
def update_l3_policy_postcommit(self, context):
old_segment_dict = context.original['external_segments']
new_segment_dict = context.current['external_segments']
if (context.current['external_segments'] !=
context.original['external_segments']):
new_segments = set(new_segment_dict.keys())
old_segments = set(old_segment_dict.keys())
added = new_segments - old_segments
removed = old_segments - new_segments
# Modified ES are treated like new ones
modified = set(x for x in (new_segments - added) if
(set(old_segment_dict[x]) != set(new_segment_dict[x])))
added |= modified
# The following operations could be intra-tenant, can't be executed
# in a single transaction
if added:
# Create a L3 ext for each External Segment
added_ess = context._plugin.get_external_segments(
context._plugin_context, filters={'id': added})
for es in added_ess:
self._plug_l3p_to_es(context, es)
if removed:
removed_ess = context._plugin.get_external_segments(
context._plugin_context, filters={'id': removed})
for es in removed_ess:
self._unplug_l3p_from_es(context, es)
def create_policy_classifier_precommit(self, context):
pass
def create_policy_classifier_postcommit(self, context):
pass
def update_policy_classifier_precommit(self, context):
pass
def update_policy_classifier_postcommit(self, context):
admin_context = nctx.get_admin_context()
if not context.current['policy_rules']:
return
rules = context._plugin.get_policy_rules(
admin_context,
filters={'id': context.current['policy_rules']})
# Rewrite the rule on the APIC
for rule in rules:
rule_context = group_policy_context.PolicyRuleContext(
context._plugin, context._plugin_context, rule)
self._update_policy_rule_on_apic(rule_context)
# If direction or protocol changed, the contracts should be updated
o_dir = context.original['direction']
c_dir = context.current['direction']
o_prot = context.original['protocol']
c_prot = context.current['protocol']
# TODO(ivar): Optimize by aggregating on PRS ID
if ((o_dir != c_dir) or
((o_prot in REVERTIBLE_PROTOCOLS) !=
(c_prot in REVERTIBLE_PROTOCOLS))):
for prs in context._plugin.get_policy_rule_sets(
admin_context,
filters={'id': rule['policy_rule_sets']}):
self._remove_policy_rule_set_rules(
context, prs, [(rule, context.original)])
self._apply_policy_rule_set_rules(context, prs, [rule])
def create_external_segment_precommit(self, context):
if context.current['port_address_translation']:
raise PATNotSupportedByApicDriver()
ext_info = self.apic_manager.ext_net_dict.get(
context.current['name'])
if ext_info and ext_info.get('cidr_exposed'):
db_es = context._plugin._get_external_segment(
context._plugin_context, context.current['id'])
net = netaddr.IPNetwork(ext_info.get('cidr_exposed'))
db_es.cidr = str(net)
db_es.ip_version = net[0].version
context.current['cidr'] = db_es.cidr
context.current['ip_version'] = db_es.ip_version
else:
LOG.warn(_("External Segment %s is not managed by APIC mapping "
"driver.") % context.current['id'])
def create_external_segment_postcommit(self, context):
external_info = self.apic_manager.ext_net_dict.get(
context.current['name'])
if not external_info:
LOG.warn(_("External Segment %s is not managed by APIC mapping "
"driver.") % context.current['id'])
def update_external_segment_precommit(self, context):
if context.current['port_address_translation']:
raise PATNotSupportedByApicDriver()
def update_external_segment_postcommit(self, context):
ext_info = self.apic_manager.ext_net_dict.get(
context.current['name'])
if not ext_info:
LOG.warn(_("External Segment %s is not managed by APIC mapping "
"driver.") % context.current['id'])
return
if (context.current['external_routes'] !=
context.original['external_routes']):
new_routes_dict = self._build_routes_dict(
context.current['external_routes'])
new_routes = set((x['destination'], x['nexthop'])
for x in context.current['external_routes'])
old_routes = set((x['destination'], x['nexthop'])
for x in context.original['external_routes'])
added = new_routes - old_routes
removed = old_routes - new_routes
switch = ext_info['switch']
default_gateway = ext_info['gateway_ip']
es_name = self.name_mapper.external_segment(
context, context.current['id'])
es_tenant = self._tenant_by_sharing_policy(context.current)
ep_names = [self.name_mapper.external_policy(context, x)
for x in context.current['external_policies']]
nexthop = lambda h: h if h else default_gateway
with self.apic_manager.apic.transaction() as trs:
for route in removed:
if route[0] not in new_routes_dict:
# Remove Route completely
self.apic_manager.ensure_static_route_deleted(
es_name, switch, route[0], owner=es_tenant,
transaction=trs)
# Also from External EPG
del_epg = (self.apic_manager.
ensure_external_epg_routes_deleted)
for ep in ep_names:
del_epg(
es_name, external_epg=ep, owner=es_tenant,
subnets=[route[0]], transaction=trs)
else:
# Only remove nexthop
self.apic_manager.ensure_next_hop_deleted(
es_name, switch, route[0], nexthop(route[1]),
owner=es_tenant, transaction=trs)
for route in added:
# Create Static Route on External Routed Network
self.apic_manager.ensure_static_route_created(
es_name, switch, nexthop(route[1]),
owner=es_tenant, subnet=route[0], transaction=trs)
# And on the External EPGs
for ep in ep_names:
self.apic_manager.ensure_external_epg_created(
es_name, subnet=route[0], external_epg=ep,
owner=es_tenant, transaction=trs)
def delete_external_segment_precommit(self, context):
pass
def delete_external_segment_postcommit(self, context):
# If not in use, there's no representation of it in the APIC
pass
def create_external_policy_precommit(self, context):
pass
def create_external_policy_postcommit(self, context):
segments = context.current['external_segments']
provided_prs = context.current['provided_policy_rule_sets']
consumed_prs = context.current['consumed_policy_rule_sets']
self._plug_externa_policy_to_segment(
context, context.current, segments, provided_prs, consumed_prs)
def update_external_policy_precommit(self, context):
pass
def update_external_policy_postcommit(self, context):
added_segments = (set(context.current['external_segments']) -
set(context.original['external_segments']))
removed_segments = (set(context.original['external_segments']) -
set(context.current['external_segments']))
# Remove segments
self._unplug_external_policy_from_segment(
context, context.current, removed_segments)
# Add new segments
provided_prs = context.current['provided_policy_rule_sets']
consumed_prs = context.current['consumed_policy_rule_sets']
self._plug_externa_policy_to_segment(
context, context.current, added_segments, provided_prs,
consumed_prs)
# Manage updated PRSs
added_p_prs = (set(context.current['provided_policy_rule_sets']) -
set(context.original['provided_policy_rule_sets']))
removed_p_prs = (set(context.original['provided_policy_rule_sets']) -
set(context.current['provided_policy_rule_sets']))
added_c_prs = (set(context.current['consumed_policy_rule_sets']) -
set(context.original['consumed_policy_rule_sets']))
removed_c_prs = (set(context.original['consumed_policy_rule_sets']) -
set(context.current['consumed_policy_rule_sets']))
# Avoid duplicating requests
delta_segments = [x for x in context.current['external_segments']
if x not in added_segments]
new_ess = context._plugin.get_external_segments(
context._plugin_context,
filters={'id': delta_segments})
for es in new_ess:
self._manage_ep_policy_rule_sets(
context._plugin_context, es, context.current, added_p_prs,
added_c_prs, removed_p_prs, removed_c_prs)
def delete_external_policy_precommit(self, context):
pass
def delete_external_policy_postcommit(self, context):
external_segments = context.current['external_segments']
self._unplug_external_policy_from_segment(
context, context.current, external_segments)
def process_subnet_changed(self, context, old, new):
if old['gateway_ip'] != new['gateway_ip']:
l2p = self._network_id_to_l2p(context, new['network_id'])
if l2p:
# Is GBP owned, reflect on APIC
self._manage_l2p_subnets(context, l2p['id'], [new], [old])
def process_subnet_added(self, context, subnet):
l2p = self._network_id_to_l2p(context, subnet['network_id'])
if l2p:
self._sync_epg_subnets(context, l2p)
self._manage_l2p_subnets(context, l2p['id'], [subnet], [])
def process_subnet_deleted(self, context, subnet):
l2p = self._network_id_to_l2p(context, subnet['network_id'])
if l2p:
self._manage_l2p_subnets(context, l2p['id'], [], [subnet])
def process_port_changed(self, context, old, new):
pass
def process_pre_port_deleted(self, context, port):
pt = self._port_id_to_pt(context, port['id'])
if pt:
context.policy_target_id = pt['id']
def process_port_deleted(self, context, port):
try:
self.gbp_plugin.delete_policy_target(
context, context.policy_target_id)
except AttributeError:
pass
def _apply_policy_rule_set_rules(
self, context, policy_rule_set, policy_rules, transaction=None):
# TODO(ivar): parent contract filtering when supported
self._manage_policy_rule_set_rules(
context, policy_rule_set, policy_rules, transaction=transaction)
def _remove_policy_rule_set_rules(
self, context, policy_rule_set, policy_rules, transaction=None):
self._manage_policy_rule_set_rules(
context, policy_rule_set, policy_rules, unset=True,
transaction=transaction)
def _manage_policy_rule_set_rules(
self, context, policy_rule_set, policy_rules, unset=False,
transaction=None, classifier=None):
# REVISIT(ivar): figure out what should be moved in apicapi instead
if policy_rules:
tenant = self._tenant_by_sharing_policy(policy_rule_set)
contract = self.name_mapper.policy_rule_set(
context, policy_rule_set['id'])
in_dir = [g_const.GP_DIRECTION_BI, g_const.GP_DIRECTION_IN]
out_dir = [g_const.GP_DIRECTION_BI, g_const.GP_DIRECTION_OUT]
for rule in policy_rules:
if isinstance(rule, tuple):
classifier = rule[1]
rule = rule[0]
else:
classifier = context._plugin.get_policy_classifier(
context._plugin_context,
rule['policy_classifier_id'])
policy_rule = self.name_mapper.policy_rule(context, rule['id'])
reverse_policy_rule = self.name_mapper.policy_rule(
context, rule['id'], prefix=REVERSE_PREFIX)
rule_owner = self._tenant_by_sharing_policy(rule)
with self.apic_manager.apic.transaction(transaction) as trs:
if classifier['direction'] in in_dir:
# PRS and subject are the same thing in this case
self.apic_manager.manage_contract_subject_in_filter(
contract, contract, policy_rule, owner=tenant,
transaction=trs, unset=unset,
rule_owner=rule_owner)
if (classifier['protocol'].lower() in
REVERTIBLE_PROTOCOLS):
(self.apic_manager.
manage_contract_subject_out_filter(
contract, contract, reverse_policy_rule,
owner=tenant, transaction=trs, unset=unset,
rule_owner=rule_owner))
if classifier['direction'] in out_dir:
# PRS and subject are the same thing in this case
self.apic_manager.manage_contract_subject_out_filter(
contract, contract, policy_rule, owner=tenant,
transaction=trs, unset=unset,
rule_owner=rule_owner)
if (classifier['protocol'].lower() in
REVERTIBLE_PROTOCOLS):
(self.apic_manager.
manage_contract_subject_in_filter(
contract, contract, reverse_policy_rule,
owner=tenant, transaction=trs, unset=unset,
rule_owner=rule_owner))
def _manage_ptg_policy_rule_sets(
self, ptg_context, added_provided, added_consumed,
removed_provided, removed_consumed, transaction=None):
context = ptg_context
plugin_context = context._plugin_context
ptg = context.current
ptg_params = []
# TODO(ivar): change APICAPI to not expect a resource context
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
mapped_tenant = self._tenant_by_sharing_policy(ptg)
mapped_ptg = self.name_mapper.policy_target_group(
plugin_context, ptg['id'])
ptg_params.append((mapped_tenant, mapped_ptg))
provided = [added_provided, removed_provided]
consumed = [added_consumed, removed_consumed]
methods = [self.apic_manager.set_contract_for_epg,
self.apic_manager.unset_contract_for_epg]
for x in xrange(len(provided)):
for c in self.gbp_plugin.get_policy_rule_sets(
plugin_context, filters={'id': provided[x]}):
c_owner = self._tenant_by_sharing_policy(c)
c = self.name_mapper.policy_rule_set(plugin_context,
c['id'])
for params in ptg_params:
methods[x](params[0], params[1], c, provider=True,
contract_owner=c_owner, transaction=None)
for x in xrange(len(consumed)):
for c in self.gbp_plugin.get_policy_rule_sets(
plugin_context, filters={'id': consumed[x]}):
c_owner = self._tenant_by_sharing_policy(c)
c = self.name_mapper.policy_rule_set(plugin_context,
c['id'])
for params in ptg_params:
methods[x](params[0], params[1], c, provider=False,
contract_owner=c_owner, transaction=None)
def _manage_ep_policy_rule_sets(
self, plugin_context, es, ep, added_provided, added_consumed,
removed_provided, removed_consumed, transaction=None):
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
if not ext_info:
LOG.warn(_("External Segment %s is not managed by APIC "
"mapping driver.") % es['id'])
return
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
mapped_tenant = self._tenant_by_sharing_policy(es)
mapped_es = self.name_mapper.external_segment(plugin_context, es['id'])
mapped_ep = self.name_mapper.external_policy(plugin_context,
ep['id'])
provided = [added_provided, removed_provided]
consumed = [added_consumed, removed_consumed]
methods = [self.apic_manager.set_contract_for_external_epg,
self.apic_manager.unset_contract_for_external_epg]
with self.apic_manager.apic.transaction(transaction) as trs:
for x in xrange(len(provided)):
for c in provided[x]:
c = self.name_mapper.policy_rule_set(plugin_context, c)
methods[x](mapped_es, c, external_epg=mapped_ep,
owner=mapped_tenant, provided=True,
transaction=trs)
for x in xrange(len(consumed)):
for c in consumed[x]:
c = self.name_mapper.policy_rule_set(plugin_context, c)
methods[x](mapped_es, c, external_epg=mapped_ep,
owner=mapped_tenant, provided=False,
transaction=trs)
def _manage_l2p_subnets(self, plugin_context, l2p_id, added_subnets,
removed_subnets, transaction=None):
# TODO(ivar): change APICAPI to not expect a resource context
plugin_context._plugin = self.gbp_plugin
plugin_context._plugin_context = plugin_context
l2_policy_object = self.gbp_plugin.get_l2_policy(
plugin_context, l2p_id)
mapped_tenant = self._tenant_by_sharing_policy(l2_policy_object)
mapped_l2p = self.name_mapper.l2_policy(plugin_context, l2p_id)
subnets = [added_subnets, removed_subnets]
methods = [self.apic_manager.ensure_subnet_created_on_apic,
self.apic_manager.ensure_subnet_deleted_on_apic]
with self.apic_manager.apic.transaction(transaction) as trs:
for x in xrange(len(subnets)):
for s in subnets[x]:
methods[x](mapped_tenant, mapped_l2p, self._gateway_ip(s),
transaction=trs)
def _update_default_security_group(self, plugin_context, ptg_id,
tenant_id, subnets=None):
pass
def _assoc_ptg_sg_to_pt(self, context, pt_id, ptg_id):
pass
def _handle_policy_rule_sets(self, context):
pass
def _gateway_ip(self, subnet):
cidr = netaddr.IPNetwork(subnet['cidr'])
return '%s/%s' % (subnet['gateway_ip'], str(cidr.prefixlen))
def _subnet_ids_to_objects(self, plugin_context, ids):
return self._core_plugin.get_subnets(plugin_context,
filters={'id': ids})
def _port_to_ptg_network(self, context, port_id):
ptg = self._port_id_to_ptg(context, port_id)
if not ptg:
# Not GBP port
return None, None
network = self._l2p_id_to_network(context, ptg['l2_policy_id'])
return ptg, network
def _port_id_to_pt(self, context, port_id):
pt = (context.session.query(gpdb.PolicyTargetMapping).
filter_by(port_id=port_id).first())
if pt:
db_utils = gpdb.GroupPolicyMappingDbPlugin()
return db_utils._make_policy_target_dict(pt)
def _port_id_to_ptg(self, context, port_id):
pt = self._port_id_to_pt(context, port_id)
if pt:
return self.gbp_plugin.get_policy_target_group(
context, pt['policy_target_group_id'])
return
def _l2p_id_to_network(self, context, l2p_id):
l2_policy = self.gbp_plugin.get_l2_policy(context, l2p_id)
return self._core_plugin.get_network(context, l2_policy['network_id'])
def _network_id_to_l2p(self, context, network_id):
l2ps = self.gbp_plugin.get_l2_policies(
context, filters={'network_id': [network_id]})
for l2p in l2ps:
if l2p['network_id'] == network_id:
return l2p
def _subnet_to_ptg(self, context, subnet_id):
ptg = (context.session.query(gpdb.PolicyTargetGroupMapping).
join(gpdb.PolicyTargetGroupMapping.subnets).
filter(gpdb.PTGToSubnetAssociation.subnet_id ==
subnet_id).
first())
if ptg:
db_utils = gpdb.GroupPolicyMappingDbPlugin()
return db_utils._make_policy_target_group_dict(ptg)
def _plug_l3p_to_es(self, context, external_segment):
l3_policy = self.name_mapper.l3_policy(context, context.current['id'])
es = external_segment
external_segments = context.current['external_segments']
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
if not ext_info:
LOG.warn(
_("External Segment %s is not managed by APIC mapping "
"driver.") % es['id'])
return
ip = external_segments[es['id']]
if ip and ip[0]:
ip = ip[0]
exposed = ip + '/' + es['cidr'].split('/')[1]
else:
ip = ext_info.get('cidr_exposed', '/').split('/')[0]
exposed = ext_info.get('cidr_exposed')
if not ip:
raise NoAddressConfiguredOnExternalSegment(
l3p_id=context.current['id'], es_id=es['id'])
context.set_external_fixed_ips(es['id'], [ip])
encap = ext_info.get('encap') # No encap if None
switch = ext_info['switch']
module, sport = ext_info['port'].split('/')
router_id = ext_info['router_id']
default_gateway = ext_info['gateway_ip']
es_name = self.name_mapper.external_segment(
context, es['id'])
es_tenant = self._tenant_by_sharing_policy(es)
with self.apic_manager.apic.transaction() as trs:
# Create External Routed Network connected to the proper
# L3 Context
self.apic_manager.ensure_external_routed_network_created(
es_name, owner=es_tenant, context=l3_policy,
transaction=trs)
self.apic_manager.ensure_logical_node_profile_created(
es_name, switch, module, sport, encap,
exposed, owner=es_tenant,
router_id=router_id, transaction=trs)
for route in es['external_routes']:
self.apic_manager.ensure_static_route_created(
es_name, switch, route['nexthop'] or default_gateway,
owner=es_tenant,
subnet=route['destination'], transaction=trs)
def _unplug_l3p_from_es(self, context, es):
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self._tenant_by_sharing_policy(es)
self.apic_manager.delete_external_routed_network(
es_name, owner=es_tenant)
def _build_routes_dict(self, routes):
result = {}
for route in routes:
if route['destination'] not in result:
result[route['destination']] = []
result[route['destination']].append(route['nexthop'])
return result
def _plug_externa_policy_to_segment(self, context, ep, segments,
provided_prs, consumed_prs):
if segments:
added_ess = context._plugin.get_external_segments(
context._plugin_context, filters={'id': segments})
ep_name = self.name_mapper.external_policy(
context, ep['id'])
for es in added_ess:
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
if not ext_info:
LOG.warn(_("External Segment %s is not managed by APIC "
"mapping driver.") % es['id'])
continue
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self._tenant_by_sharing_policy(es)
with self.apic_manager.apic.transaction() as trs:
# Create External EPG
subnets = set(x['destination'] for
x in es['external_routes'])
for s in subnets:
self.apic_manager.ensure_external_epg_created(
es_name, subnet=s, external_epg=ep_name,
owner=es_tenant, transaction=trs)
# Provide and consume contracts
self._manage_ep_policy_rule_sets(
context._plugin_context, es, ep,
provided_prs, consumed_prs, [], [], transaction=trs)
def _unplug_external_policy_from_segment(self, context, ep, segments):
if segments:
added_ess = context._plugin.get_external_segments(
context._plugin_context, filters={'id': segments})
ep_name = self.name_mapper.external_policy(
context, ep['id'])
for es in added_ess:
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
if not ext_info:
LOG.warn(_("External Segment %s is not managed by APIC "
"mapping driver.") % es['id'])
continue
es_name = self.name_mapper.external_segment(context, es['id'])
es_tenant = self._tenant_by_sharing_policy(es)
self.apic_manager.ensure_external_epg_deleted(
es_name, external_epg=ep_name, owner=es_tenant)
def _check_l3p_es(self, context):
l3p = context.current
if l3p['external_segments']:
# Check not used
ess = context._plugin.get_external_segments(
context._plugin_context,
filters={'id': l3p['external_segments'].keys()})
for es in ess:
if [x for x in es['l3_policies'] if x != l3p['id']]:
raise OnlyOneL3PolicyIsAllowedPerExternalSegment()
for allocations in l3p['external_segments'].values():
if len(allocations) > 1:
raise OnlyOneAddressIsAllowedPerExternalSegment()
def _get_ptg_by_subnet(self, plugin_context, subnet_id):
ptgass = (plugin_context.session.query(gpdb.PTGToSubnetAssociation).
filter_by(subnet_id=subnet_id).first())
if ptgass:
return self.gbp_plugin.get_policy_target_group(
plugin_context, ptgass['policy_target_group_id'])
def _reject_shared_update(self, context, type):
if context.original.get('shared') != context.current.get('shared'):
raise SharedAttributeUpdateNotSupportedOnApic(type=type)
def _tenant_by_sharing_policy(self, object):
if not object.get('shared'):
return self.name_mapper.tenant(None, object['tenant_id'])
else:
return apic_manager.TENANT_COMMON
def _notify_port_update(self, plugin_context, port_id):
try:
port = self._core_plugin.get_port(plugin_context, port_id)
if self._is_port_bound(port):
self.notifier.port_update(plugin_context, port)
except n_exc.PortNotFound:
# Notification not needed
pass
def _get_port_network_type(self, context, port):
try:
network = self._core_plugin.get_network(context,
port['network_id'])
return network['provider:network_type']
except n_exc.NetworkNotFound:
pass
def _is_apic_network_type(self, context, port):
return (self._get_port_network_type(context, port) ==
ofcst.TYPE_OPFLEX)
def _is_port_bound(self, port):
return port.get(portbindings.VIF_TYPE) not in [
portbindings.VIF_TYPE_UNBOUND,
portbindings.VIF_TYPE_BINDING_FAILED]
def _use_implicit_subnet(self, context, force_add=False):
"""Implicit subnet for APIC driver.
The first PTG of a given BD will allocate a new subnet from the L3P.
Any subsequent PTG in the same BD will use the same subnet.
More subnets will be allocated whenever the existing ones go out of
addresses.
"""
l2p_id = context.current['l2_policy_id']
with lockutils.lock(l2p_id, external=True):
subs = self._get_l2p_subnets(context._plugin_context, l2p_id)
subs = set([x['id'] for x in subs])
added = None
if not subs or force_add:
added = self._internal_use_implicit_subnet(context)
subs.add(added['id'])
context.add_subnets(subs - set(context.current['subnets']))
if added:
self.process_subnet_added(context._plugin_context, added)
def _internal_use_implicit_subnet(self, context):
l2p_id = context.current['l2_policy_id']
l2p = context._plugin.get_l2_policy(context._plugin_context, l2p_id)
l3p_id = l2p['l3_policy_id']
l3p = context._plugin.get_l3_policy(context._plugin_context, l3p_id)
pool = netaddr.IPNetwork(l3p['ip_pool'])
admin_context = nctx.get_admin_context()
l2ps = context._plugin.get_l2_policies(
admin_context, filters={'l3_policy_id': [l3p['id']]})
ptgs = context._plugin.get_policy_target_groups(
admin_context, filters={'l2_policy_id': [x['id'] for x in l2ps]})
subnets = []
for ptg in ptgs:
subnets.extend(ptg['subnets'])
subnets = self._core_plugin.get_subnets(admin_context,
filters={'id': subnets})
for cidr in pool.subnet(l3p['subnet_prefix_length']):
if not self._validate_subnet_overlap_for_l3p(subnets,
cidr.__str__()):
continue
try:
attrs = {'tenant_id': context.current['tenant_id'],
'name': APIC_OWNED + l2p['name'],
'network_id': l2p['network_id'],
'ip_version': l3p['ip_version'],
'cidr': cidr.__str__(),
'enable_dhcp': True,
'gateway_ip': attributes.ATTR_NOT_SPECIFIED,
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
'dns_nameservers': attributes.ATTR_NOT_SPECIFIED,
'host_routes': attributes.ATTR_NOT_SPECIFIED}
subnet = self._create_subnet(context._plugin_context, attrs)
return subnet
except n_exc.BadRequest:
# This is expected (CIDR overlap) until we have a
# proper subnet allocation algorithm. We ignore the
# exception and repeat with the next CIDR.
pass
raise gpexc.NoSubnetAvailable()
def _sync_epg_subnets(self, plugin_context, l2p):
l2p_subnets = [x['id'] for x in
self._get_l2p_subnets(plugin_context, l2p['id'])]
epgs = self.gbp_plugin.get_policy_target_groups(
nctx.get_admin_context(), {'l2_policy_id': [l2p['id']]})
for sub in l2p_subnets:
# Add to EPG
for epg in epgs:
if sub not in epg['subnets']:
try:
(self.gbp_plugin.
_add_subnet_to_policy_target_group(
nctx.get_admin_context(), epg['id'], sub))
except gpolicy.PolicyTargetGroupNotFound as e:
LOG.warn(e)
def _get_l2p_subnets(self, plugin_context, l2p_id):
l2p = self.gbp_plugin.get_l2_policy(plugin_context, l2p_id)
return self._core_plugin.get_subnets(
plugin_context, {'network_id': [l2p['network_id']]})
def _configure_implicit_contract(self, context, l2p, transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
tenant = self._tenant_by_sharing_policy(l2p)
# Create Service contract
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=IMPLICIT_PREFIX)
self.apic_manager.create_contract(
contract, owner=tenant, transaction=trs)
# Create ARP filter/subject
attrs = {'etherT': 'arp'}
self._associate_service_filter(tenant, contract, 'arp',
'arp', transaction=trs, **attrs)
def _configure_shadow_epg(self, context, l2p, bd_name, transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
tenant = self._tenant_by_sharing_policy(l2p)
shadow_epg = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SHADOW_PREFIX)
self.apic_manager.ensure_epg_created(
tenant, shadow_epg, bd_owner=tenant, bd_name=bd_name,
transaction=trs)
# Create Service contract
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SERVICE_PREFIX)
self.apic_manager.create_contract(
contract, owner=tenant, transaction=trs)
# Shadow EPG provides this contract
self.apic_manager.set_contract_for_epg(
tenant, shadow_epg, contract, provider=True,
contract_owner=tenant, transaction=trs)
# Create DNS filter/subject
attrs = {'etherT': 'ip',
'prot': 'udp',
'dToPort': 'dns',
'dFromPort': 'dns'}
self._associate_service_filter(tenant, contract, 'dns',
'dns', transaction=trs, **attrs)
attrs = {'etherT': 'ip',
'prot': 'udp',
'sToPort': 'dns',
'sFromPort': 'dns'}
self._associate_service_filter(tenant, contract, 'dns',
'r-dns', transaction=trs, **attrs)
# Create HTTP filter/subject
attrs = {'etherT': 'ip',
'prot': 'tcp',
'dToPort': 80,
'dFromPort': 80}
self._associate_service_filter(tenant, contract, 'http',
'http', transaction=trs, **attrs)
attrs = {'etherT': 'ip',
'prot': 'tcp',
'sToPort': 80,
'sFromPort': 80}
self._associate_service_filter(tenant, contract, 'http',
'r-http', transaction=trs, **attrs)
attrs = {'etherT': 'ip',
'prot': 'icmp'}
self._associate_service_filter(tenant, contract, 'icmp',
'icmp', transaction=trs, **attrs)
# Create DHCP filter/subject
attrs = {'etherT': 'ip',
'prot': 'udp',
'dToPort': 68,
'dFromPort': 68,
'sToPort': 67,
'sFromPort': 67}
self._associate_service_filter(tenant, contract, 'dhcp',
'dhcp', transaction=trs, **attrs)
attrs = {'etherT': 'ip',
'prot': 'udp',
'dToPort': 67,
'dFromPort': 67,
'sToPort': 68,
'sFromPort': 68}
self._associate_service_filter(tenant, contract, 'dhcp',
'r-dhcp', transaction=trs, **attrs)
# Create ARP filter/subject
attrs = {'etherT': 'arp'}
self._associate_service_filter(tenant, contract, 'arp',
'arp', transaction=trs, **attrs)
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=IMPLICIT_PREFIX)
# Shadow EPG provides and consumes implicit contract
self.apic_manager.set_contract_for_epg(
tenant, shadow_epg, contract, provider=False,
contract_owner=tenant, transaction=trs)
self.apic_manager.set_contract_for_epg(
tenant, shadow_epg, contract, provider=True,
contract_owner=tenant, transaction=trs)
def _associate_service_filter(self, tenant, contract, filter_name,
entry_name, transaction=None, **attrs):
with self.apic_manager.apic.transaction(transaction) as trs:
filter_name = '%s-%s' % (str(self.apic_manager.app_profile_name),
filter_name)
self.apic_manager.create_tenant_filter(
filter_name, owner=tenant, entry=entry_name,
transaction=trs, **attrs)
self.apic_manager.manage_contract_subject_bi_filter(
contract, contract, filter_name, owner=tenant,
transaction=trs, rule_owner=tenant)
def _delete_shadow_epg(self, context, l2p, transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
tenant = self._tenant_by_sharing_policy(l2p)
shadow_epg = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SHADOW_PREFIX)
self.apic_manager.delete_epg_for_network(
tenant, shadow_epg, transaction=trs)
# Delete Service Contract
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SERVICE_PREFIX)
self.apic_manager.delete_contract(
contract, owner=tenant, transaction=trs)
def _delete_implicit_contract(self, context, l2p, transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
tenant = self._tenant_by_sharing_policy(l2p)
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=IMPLICIT_PREFIX)
self.apic_manager.delete_contract(
contract, owner=tenant, transaction=trs)
def _configure_epg_service_contract(self, context, ptg, l2p, epg_name,
transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
contract_owner = self._tenant_by_sharing_policy(l2p)
tenant = self._tenant_by_sharing_policy(ptg)
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=SERVICE_PREFIX)
self.apic_manager.set_contract_for_epg(
tenant, epg_name, contract, provider=False,
contract_owner=contract_owner, transaction=trs)
def _configure_epg_implicit_contract(self, context, ptg, l2p, epg_name,
transaction=None):
with self.apic_manager.apic.transaction(transaction) as trs:
contract_owner = self._tenant_by_sharing_policy(l2p)
tenant = self._tenant_by_sharing_policy(ptg)
contract = self.name_mapper.l2_policy(
context, l2p['id'], prefix=IMPLICIT_PREFIX)
self.apic_manager.set_contract_for_epg(
tenant, epg_name, contract, provider=False,
contract_owner=contract_owner, transaction=trs)
self.apic_manager.set_contract_for_epg(
tenant, epg_name, contract, provider=True,
contract_owner=contract_owner, transaction=trs)
def _get_redirect_action(self, context, policy_rule):
for action in context._plugin.get_policy_actions(
context._plugin_context,
filters={'id': policy_rule['policy_actions']}):
if action['action_type'] == g_const.GP_ACTION_REDIRECT:
return action
def _validate_new_prs_redirect(self, context, prs):
if self._prss_redirect_rules(context._plugin_context.session,
[prs['id']]) > 1:
raise gpexc.MultipleRedirectActionsNotSupportedForPRS()
def _prss_redirect_rules(self, session, prs_ids):
if len(prs_ids) == 0:
# No result will be found in this case
return 0
query = (session.query(gpdb.gpdb.PolicyAction).
join(gpdb.gpdb.PolicyRuleActionAssociation).
join(gpdb.gpdb.PolicyRule).
join(gpdb.gpdb.PRSToPRAssociation).
filter(
gpdb.gpdb.PRSToPRAssociation.policy_rule_set_id.in_(prs_ids)).
filter(gpdb.gpdb.PolicyAction.action_type ==
g_const.GP_ACTION_REDIRECT))
return query.count()
def _multiple_pr_redirect_action_number(self, session, pr_ids):
# Given a set of rules, gives the total number of redirect actions
# found
if len(pr_ids) == 0:
# No result will be found in this case
return 0
return (session.query(gpdb.gpdb.PolicyAction).
join(gpdb.gpdb.PolicyRuleActionAssociation).
filter(
gpdb.gpdb.PolicyRuleActionAssociation.policy_rule_id.in_(
pr_ids)).
filter(gpdb.gpdb.PolicyAction.action_type ==
g_const.GP_ACTION_REDIRECT)).count()