Merge "Send VRF notifications"

This commit is contained in:
Zuul 2019-04-11 03:58:35 +00:00 committed by Gerrit Code Review
commit 5a9991f18f
2 changed files with 682 additions and 402 deletions

View File

@ -1023,9 +1023,29 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if subnets_size > 1:
raise exceptions.OnlyOneSubnetInSVINetwork()
if network_db.aim_mapping:
# Provide VRF notifications if creating subnets in
# unscoped networks.
# REVISIT: We may need to handle VRF notifications for
# external networks as well.
vrf = self._get_network_vrf(network_db.aim_mapping)
if (vrf and (self._is_unrouted_vrf(vrf) or
self._is_default_vrf(vrf))
and not network_db.external):
vrfs_to_notify = self._add_vrf_notification(vrf)
self._notify_vrf_update(context._plugin_context,
vrfs_to_notify)
# Neutron subnets in non-external networks are mapped to AIM
# Subnets as they are added to routers as interfaces.
def _is_unrouted_vrf(self, vrf):
return (vrf.tenant_name == COMMON_TENANT_NAME and
vrf.name == self.apic_system_id + '_' + UNROUTED_VRF_NAME)
def _is_default_vrf(self, vrf):
return vrf.name == DEFAULT_VRF_NAME
def update_subnet_precommit(self, context):
current = context.current
original = context.original
@ -1097,6 +1117,19 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
ns.delete_subnet(aim_ctx, l3out,
self._subnet_to_gw_ip_mask(current))
if network_db.aim_mapping:
# Provide VRF notifications if deleting subnets from
# unscoped networks.
# REVISIT: We may need to handle VRF notifications for
# external networks as well.
vrf = self._get_network_vrf(network_db.aim_mapping)
if (vrf and (self._is_unrouted_vrf(vrf) or
self._is_default_vrf(vrf))
and not network_db.external):
vrfs_to_notify = self._add_vrf_notification(vrf)
self._notify_vrf_update(context._plugin_context,
vrfs_to_notify)
# Non-external neutron subnets are unmapped from AIM Subnets as
# they are removed from routers.
@ -1166,6 +1199,20 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
self.extend_subnet_dict_bulk(session, [(result, subnet_db)])
def _notify_vrf_for_scope(self, context):
session = context._plugin_context.session
scope_id = context.current['address_scope_id']
mapping = self._get_address_scope_mapping(session, scope_id)
if mapping:
vrf = self._get_address_scope_vrf(mapping)
if vrf:
vrfs_to_notify = self._add_vrf_notification(vrf)
self._notify_vrf_update(context._plugin_context,
vrfs_to_notify)
def create_subnetpool_precommit(self, context):
self._notify_vrf_for_scope(context)
def update_subnetpool_precommit(self, context):
current = context.current
original = context.original
@ -1216,6 +1263,14 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# just reject the update.
raise exceptions.ScopeUpdateNotSupported()
current_prefixes = set(current['prefixes'])
original_prefixes = set(original['prefixes'])
if current_scope_id and current_prefixes != original_prefixes:
self._notify_vrf_for_scope(context)
def delete_subnetpool_precommit(self, context):
self._notify_vrf_for_scope(context)
def create_address_scope_precommit(self, context):
current = context.current
LOG.debug("APIC AIM MD creating address scope: %s", current)
@ -1637,6 +1692,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
raise exceptions.NonIsomorphicNetworkRoutingUnsupported()
nets_to_notify = set()
vrfs_to_notify = set()
ports_to_notify = set()
router_topo_moved = False
@ -1677,7 +1733,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
vrf = self._ensure_default_vrf(aim_ctx, intf_vrf)
self._move_topology(
context, aim_ctx, router_topology, router_vrf, vrf,
nets_to_notify)
nets_to_notify, vrfs_to_notify)
router_topo_moved = True
self._cleanup_default_vrf(aim_ctx, router_vrf)
elif router_shared_net:
@ -1688,7 +1744,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if net_intfs:
self._move_topology(
context, aim_ctx, intf_topology, intf_vrf, vrf,
nets_to_notify)
nets_to_notify, vrfs_to_notify)
self._cleanup_default_vrf(aim_ctx, intf_vrf)
else:
# This should never happen.
@ -1708,10 +1764,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# First interface for network.
if network_db.aim_mapping.epg_name:
bd, epg = self._associate_network_with_vrf(
context, aim_ctx, network_db, vrf, nets_to_notify)
context, aim_ctx, network_db, vrf, nets_to_notify,
scope_id, vrfs_to_notify)
elif network_db.aim_mapping.l3out_name:
l3out, epg = self._associate_network_with_vrf(
context, aim_ctx, network_db, vrf, nets_to_notify)
context, aim_ctx, network_db, vrf, nets_to_notify,
scope_id, vrfs_to_notify)
else:
# Network is already routed.
#
@ -1795,6 +1853,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
ports_to_notify.update(port_ids)
if ports_to_notify:
self._notify_port_update_bulk(context, ports_to_notify)
if vrfs_to_notify:
self._notify_vrf_update(context, vrfs_to_notify)
def remove_router_interface(self, context, router_id, port, subnets):
LOG.debug("APIC AIM MD removing subnets %(subnets)s from router "
@ -1867,6 +1927,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
provided_contract_names=contracts)
nets_to_notify = set()
vrfs_to_notify = set()
ports_to_notify = set()
router_topo_moved = False
@ -1888,7 +1949,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
intf_vrf = self._ensure_default_vrf(aim_ctx, intf_vrf)
self._move_topology(
context, aim_ctx, intf_topology, old_vrf, intf_vrf,
nets_to_notify)
nets_to_notify, vrfs_to_notify)
# See if the router's topology must be moved.
router_topology = self._router_topology(session, router_db.id)
@ -1901,14 +1962,15 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
router_vrf = self._ensure_default_vrf(aim_ctx, router_vrf)
self._move_topology(
context, aim_ctx, router_topology, old_vrf, router_vrf,
nets_to_notify)
nets_to_notify, vrfs_to_notify)
router_topo_moved = True
# If network is no longer connected to any router, make the
# network's BD unrouted.
if not router_ids:
self._dissassociate_network_from_vrf(
context, aim_ctx, network_db, old_vrf, nets_to_notify)
context, aim_ctx, network_db, old_vrf, nets_to_notify,
scope_id, vrfs_to_notify)
if scope_id == NO_ADDR_SCOPE:
self._cleanup_default_vrf(aim_ctx, old_vrf)
@ -1957,6 +2019,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
ports_to_notify.update(port_ids)
if ports_to_notify:
self._notify_port_update_bulk(context, ports_to_notify)
if vrfs_to_notify:
self._notify_vrf_update(context, vrfs_to_notify)
def bind_port(self, context):
port = context.current
@ -2745,7 +2809,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
return rtr_dbs
def _associate_network_with_vrf(self, ctx, aim_ctx, network_db, new_vrf,
nets_to_notify):
nets_to_notify, scope_id, vrfs_to_notify):
LOG.debug("Associating previously unrouted network %(net_id)s named "
"'%(net_name)s' in project %(net_tenant)s with VRF %(vrf)s",
{'net_id': network_db.id, 'net_name': network_db.name,
@ -2817,6 +2881,13 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# Tenants have changed.
nets_to_notify.add(network_db.id)
# Notify VRFs not associated with address_scopes that the
# subnet CIDRs within them have changed.
old_vrf = self._get_network_vrf(network_db.aim_mapping)
if self._is_default_vrf(new_vrf):
self._add_vrf_notification(new_vrf, vrfs_to_notify)
self._add_vrf_notification(old_vrf, vrfs_to_notify)
if not self._is_svi_db(network_db):
return bd, epg
else:
@ -2824,7 +2895,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
return l3out, ext_net
def _dissassociate_network_from_vrf(self, ctx, aim_ctx, network_db,
old_vrf, nets_to_notify):
old_vrf, nets_to_notify, scope_id,
vrfs_to_notify):
LOG.debug("Dissassociating network %(net_id)s named '%(net_name)s' in "
"project %(net_tenant)s from VRF %(vrf)s",
{'net_id': network_db.id, 'net_name': network_db.name,
@ -2896,8 +2968,20 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# Tenants have changed.
nets_to_notify.add(network_db.id)
# Notify VRFs not associated with address_scopes that the
# subnet CIDRs within them have changed
if self._is_default_vrf(old_vrf):
self._add_vrf_notification(old_vrf, vrfs_to_notify)
self._add_vrf_notification(new_vrf, vrfs_to_notify)
def _add_vrf_notification(self, vrf, vrfs_to_notify=None):
vrfs_to_notify = set() if vrfs_to_notify is None else vrfs_to_notify
vrf_to_notify = '%s %s' % (vrf.tenant_name, vrf.name)
vrfs_to_notify.add(vrf_to_notify)
return vrfs_to_notify
def _move_topology(self, ctx, aim_ctx, topology, old_vrf, new_vrf,
nets_to_notify):
nets_to_notify, vrfs_to_notify):
LOG.info("Moving routed networks %(topology)s from VRF "
"%(old_vrf)s to VRF %(new_vrf)s",
{'topology': topology.keys(),
@ -2976,6 +3060,9 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# EPGs' Tenants have changed.
nets_to_notify.update(topology.keys())
self._add_vrf_notification(old_vrf, vrfs_to_notify)
self._add_vrf_notification(new_vrf, vrfs_to_notify)
def _router_topology(self, session, router_id):
LOG.debug("Getting topology for router %s", router_id)
visited_networks = {}
@ -3480,6 +3567,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
portbindings.VIF_TYPE_BINDING_FAILED]
def _notify_port_update(self, plugin_context, port_id):
# REVISIT: Avoid getting the port resource, if possible.
port = self.plugin.get_port(plugin_context.elevated(), port_id)
if self._is_port_bound(port):
LOG.debug("Enqueing notify for port %s", port['id'])
@ -3524,6 +3612,15 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
for p_id in port_ids:
self._notify_port_update(plugin_context, p_id)
def _notify_vrf_update(self, plugin_context, vrfs_to_notify):
txn = local_api.get_outer_transaction(
plugin_context.session.transaction)
for vrf in vrfs_to_notify:
local_api.send_or_queue_notification(plugin_context.session,
txn, self.notifier,
'opflex_notify_vrf',
[plugin_context, vrf])
def get_or_allocate_snat_ip(self, plugin_context, host_or_vrf,
ext_network):
"""Fetch or allocate SNAT IP on the external network.