Split the default ext epg 0/0 subnet into 0/1 and 128/1

Since each SVI ext epg subnet is 0/0 so if there are multiple
SVI networks under this VRF then the system doesn't know which
contract to use. We still need 0/0 in each SVI so that BGP can
work properly but for each VRF we will create a separate default
SVI l3out that will have subnets 0/1 and 128/1.

We will create this default SVI l3out when the first SVI l3out
is created under this VRF. Vice versa We will delete this default
SVI l3out when the last SVI l3out is being deleted under this VRF.

When a SVI network is connected to a router then we will apply the
router contract to this default SVI ext epg instead. This way there
will be no ambiguity regarding which contract to use when traffic
comes in.

Change-Id: I7d7a737664d0cdeb88b0197e12215a804a174d1b
This commit is contained in:
Kent Wu 2018-03-30 15:34:36 -07:00
parent 40902d04cc
commit e83f71dbe4
5 changed files with 228 additions and 31 deletions

View File

@ -145,6 +145,20 @@ class DbMixin(object):
vrf_name=vrf.name).
first() is not None)
def _is_vrf_used_by_l3outs(self, session, vrf):
return (session.query(NetworkMapping.network_id).
filter(NetworkMapping.vrf_tenant_name == vrf.tenant_name,
NetworkMapping.vrf_name == vrf.name,
NetworkMapping.l3out_name.isnot(None)).
first() is not None)
def _get_l3outs_for_vrf(self, session, vrf):
return (session.query(NetworkMapping).
filter(NetworkMapping.vrf_tenant_name == vrf.tenant_name,
NetworkMapping.vrf_name == vrf.name,
NetworkMapping.l3out_name.isnot(None)).
all())
def _get_network_bd(self, mapping):
return aim_resource.BridgeDomain(
tenant_name=mapping.bd_tenant_name,

View File

@ -89,6 +89,7 @@ DEFAULT_SG_NAME = 'DefaultSecurityGroup'
L3OUT_NODE_PROFILE_NAME = 'NodeProfile'
L3OUT_IF_PROFILE_NAME = 'IfProfile'
L3OUT_EXT_EPG = 'ExtEpg'
DEFAULT_SVI_L3OUT_NAME = 'DefaultSVIL3Out'
SUPPORTED_VNIC_TYPES = [portbindings.VNIC_NORMAL,
portbindings.VNIC_DIRECT]
@ -463,6 +464,66 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
'name': mapping.domain_name})
return domains
def _scope_default_svi_l3out_name_by_vrf(self, vrf_name):
return DEFAULT_SVI_L3OUT_NAME + '_' + vrf_name
def _create_default_svi_l3out(self, aim_ctx, vrf):
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
vrf.name)
default_svi_l3out = aim_resource.L3Outside(
tenant_name=vrf.tenant_name,
name=default_l3out_name,
display_name=DEFAULT_SVI_L3OUT_NAME, vrf_name=vrf.name,
l3_domain_dn=self.l3_domain_dn)
self.aim.create(aim_ctx, default_svi_l3out,
overwrite=True)
default_svi_ext_net = aim_resource.ExternalNetwork(
tenant_name=vrf.tenant_name,
l3out_name=default_l3out_name, name=L3OUT_EXT_EPG)
# Can't overwrite this as it will wipe out the existing contracts
if not self.aim.get(aim_ctx, default_svi_ext_net):
self.aim.create(aim_ctx, default_svi_ext_net)
ext_subnet_ipv4_1 = aim_resource.ExternalSubnet(
tenant_name=vrf.tenant_name,
l3out_name=default_l3out_name,
external_network_name=L3OUT_EXT_EPG, cidr='0.0.0.0/1')
self.aim.create(aim_ctx, ext_subnet_ipv4_1,
overwrite=True)
ext_subnet_ipv4_2 = aim_resource.ExternalSubnet(
tenant_name=vrf.tenant_name,
l3out_name=default_l3out_name,
external_network_name=L3OUT_EXT_EPG, cidr='128.0.0.0/1')
self.aim.create(aim_ctx, ext_subnet_ipv4_2,
overwrite=True)
ext_subnet_ipv6_1 = aim_resource.ExternalSubnet(
tenant_name=vrf.tenant_name,
l3out_name=default_l3out_name,
external_network_name=L3OUT_EXT_EPG, cidr='::/1')
self.aim.create(aim_ctx, ext_subnet_ipv6_1,
overwrite=True)
ext_subnet_ipv6_2 = aim_resource.ExternalSubnet(
tenant_name=vrf.tenant_name,
l3out_name=default_l3out_name,
external_network_name=L3OUT_EXT_EPG, cidr='8000::/1')
self.aim.create(aim_ctx, ext_subnet_ipv6_2,
overwrite=True)
def _delete_default_svi_l3out(self, aim_ctx, vrf):
if not self._is_vrf_used_by_l3outs(aim_ctx.db_session,
vrf):
LOG.debug("Deleting default SVI for %(vrf)s from tenant "
"%(tenant)s",
{'vrf': vrf.name,
'tenant': vrf.tenant_name})
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
vrf.name)
aim_l3outs = self.aim.find(
aim_ctx, aim_resource.L3Outside, tenant_name=vrf.tenant_name,
name=default_l3out_name, vrf_name=vrf.name,
monitored=False)
if aim_l3outs:
self.aim.delete(aim_ctx, aim_l3outs[0], cascade=True)
def create_network_precommit(self, context):
current = context.current
LOG.debug("APIC AIM MD creating network: %s", current)
@ -566,6 +627,9 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
self._add_network_mapping(session, current['id'], None, None,
vrf, aim_ext_net)
# Create the SVI default l3out also
self._create_default_svi_l3out(aim_ctx, vrf)
return
else:
bd, epg = self._map_network(session, current)
@ -781,12 +845,18 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
self.aim.delete(aim_ctx, aim_l3out_np, cascade=True)
else:
self.aim.delete(aim_ctx, l3out, cascade=True)
# Before we can clean up the default vrf, we have to
# remove the association in the network_mapping first.
mapping = self._get_network_mapping(session, current['id'])
l3out_vrf = self._get_network_vrf(mapping)
self._set_network_vrf(mapping, self._map_unrouted_vrf())
vrf = self._map_default_vrf(session, current)
self._cleanup_default_vrf(aim_ctx, vrf)
# Also delete the default SVI if this is the last
# SVI l3out in this vrf
self._delete_default_svi_l3out(aim_ctx, l3out_vrf)
else:
mapping = self._get_network_mapping(session, current['id'])
bd = self._get_network_bd(mapping)
@ -1492,8 +1562,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
bd = self._get_network_bd(network_db.aim_mapping)
epg = self._get_network_epg(network_db.aim_mapping)
elif network_db.aim_mapping.l3out_name:
epg = self._get_network_l3out_ext_net(
network_db.aim_mapping)
epg = self._get_default_svi_ext_epg(network_db)
if network_db.aim_mapping.epg_name:
# Create AIM Subnet(s) for each added Neutron subnet.
@ -1582,9 +1651,9 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
filter_by(id=router_id).
one())
contract = self._map_router(session, router_db, True)
old_vrf = self._get_network_vrf(network_db.aim_mapping)
epg = None
old_vrf = self._get_network_vrf(network_db.aim_mapping)
if network_db.aim_mapping.epg_name:
bd = self._get_network_bd(network_db.aim_mapping)
epg = self._get_network_epg(network_db.aim_mapping)
@ -1595,7 +1664,20 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
self.aim.delete(aim_ctx, sn)
# SVI network with auto l3out.
elif network_db.aim_mapping.l3out_name:
epg = self._get_network_l3out_ext_net(network_db.aim_mapping)
# Need to make sure this is the last SVI network in this vrf
# that connects to this router
l3out_net_ids = self._get_l3out_ids_for_vrf(session, old_vrf)
rtr_ports = (session.query(l3_db.RouterPort.port_id).
join(models_v2.Port,
models_v2.Port.id == l3_db.RouterPort.port_id).
filter(l3_db.RouterPort.router_id == router_id,
l3_db.RouterPort.port_type ==
n_constants.DEVICE_OWNER_ROUTER_INTF,
models_v2.Port.network_id.in_(l3out_net_ids)
).
first())
if not rtr_ports:
epg = self._get_default_svi_ext_epg(network_db)
# Find remaining routers with interfaces to this network.
router_ids = [r[0] for r in
@ -2358,6 +2440,10 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
mappings = self._get_network_mappings_for_vrf(session, vrf)
return [mapping.network_id for mapping in mappings]
def _get_l3out_ids_for_vrf(self, session, vrf):
mappings = self._get_l3outs_for_vrf(session, vrf)
return [mapping.network_id for mapping in mappings]
def _get_routers_for_vrf(self, session, vrf):
# REVISIT: Persist router/VRF relationship?
@ -2403,6 +2489,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# NOTE: Must only be called for networks that are not yet
# attached to any router.
old_vrf = self._get_network_vrf(network_db.aim_mapping)
if not self._is_svi_db(network_db):
bd = self._get_network_bd(network_db.aim_mapping)
epg = self._get_network_epg(network_db.aim_mapping)
@ -2444,6 +2531,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
l3out = self.aim.create(aim_ctx, l3out)
self._set_network_l3out(network_db.aim_mapping,
l3out)
self._create_default_svi_l3out(aim_ctx, new_vrf)
for old_child in self.aim.get_subtree(aim_ctx, old_l3out):
new_child = copy.copy(old_child)
new_child.tenant_name = new_vrf.tenant_name
@ -2458,8 +2546,11 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
else:
l3out = self.aim.update(aim_ctx, l3out,
vrf_name=new_vrf.name)
self._create_default_svi_l3out(aim_ctx, new_vrf)
self._set_network_vrf_and_notify(ctx, network_db.aim_mapping, new_vrf)
if self._is_svi_db(network_db):
self._delete_default_svi_l3out(aim_ctx, old_vrf)
# All non-router ports on this network need to be notified
# since their BD's VRF and possibly their BD's and EPG's
@ -2469,8 +2560,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if not self._is_svi_db(network_db):
return bd, epg
else:
ext_net = self._get_network_l3out_ext_net(network_db.aim_mapping)
return l3out, ext_net
default_ext_net = self._get_default_svi_ext_epg(network_db)
return l3out, default_ext_net
def _dissassociate_network_from_vrf(self, ctx, aim_ctx, network_db,
old_vrf, nets_to_notify):
@ -2521,6 +2612,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
l3out = self.aim.create(aim_ctx, l3out)
self._set_network_l3out(network_db.aim_mapping,
l3out)
self._create_default_svi_l3out(aim_ctx, new_vrf)
for old_child in self.aim.get_subtree(aim_ctx, old_l3out):
new_child = copy.copy(old_child)
new_child.tenant_name = new_tenant_name
@ -2537,8 +2629,11 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
l3out = self._get_network_l3out(network_db.aim_mapping)
l3out = self.aim.update(aim_ctx, l3out,
vrf_name=new_vrf.name)
self._create_default_svi_l3out(aim_ctx, new_vrf)
self._set_network_vrf_and_notify(ctx, network_db.aim_mapping, new_vrf)
if self._is_svi_db(network_db):
self._delete_default_svi_l3out(aim_ctx, old_vrf)
# All non-router ports on this network need to be notified
# since their BD's VRF and possibly their BD's and EPG's
@ -2600,6 +2695,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
l3out = self.aim.create(aim_ctx, l3out)
self._set_network_l3out(network_db.aim_mapping,
l3out)
self._create_default_svi_l3out(aim_ctx, new_vrf)
for old_child in self.aim.get_subtree(aim_ctx, old_l3out):
new_child = copy.copy(old_child)
new_child.tenant_name = new_vrf.tenant_name
@ -2616,9 +2712,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
l3out = self._get_network_l3out(network_db.aim_mapping)
l3out = self.aim.update(aim_ctx, l3out,
vrf_name=new_vrf.name)
self._create_default_svi_l3out(aim_ctx, new_vrf)
self._set_network_vrf_and_notify(ctx, network_db.aim_mapping,
new_vrf)
if network_db.aim_mapping.l3out_name:
self._delete_default_svi_l3out(aim_ctx, old_vrf)
# All non-router ports on all networks in topology need to be
# notified since their BDs' VRFs and possibly their BDs' and
@ -3796,20 +3895,28 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
port = self.plugin.get_port(plugin_context, port_id)
return port['network_id']
def _get_svi_default_external_epg(self, network):
if not network.get(cisco_apic.SVI):
return None
ext_net_dn = network.get(cisco_apic.DIST_NAMES, {}).get(
cisco_apic.EXTERNAL_NETWORK)
return aim_resource.ExternalNetwork.from_dn(ext_net_dn)
def _get_svi_net_l3out(self, network):
aim_ext_net = self._get_svi_default_external_epg(network)
def _get_default_svi_l3out(self, network_db):
aim_ext_net = self._get_default_svi_ext_epg(network_db)
if not aim_ext_net:
return None
return aim_resource.L3Outside(
tenant_name=aim_ext_net.tenant_name, name=aim_ext_net.l3out_name)
def _get_default_svi_ext_epg(self, network_db):
if self._is_svi_db(network_db):
# SVI network with pre-existing l3out
if network_db.aim_extension_mapping.external_network_dn:
return aim_resource.ExternalNetwork.from_dn(
network_db.aim_extension_mapping.external_network_dn)
# SVI auto-l3out
l3out_vrf = self._get_network_vrf(network_db.aim_mapping)
l3out_name = self._scope_default_svi_l3out_name_by_vrf(
l3out_vrf.name)
return aim_resource.ExternalNetwork(
tenant_name=l3out_vrf.tenant_name, l3out_name=l3out_name,
name=L3OUT_EXT_EPG)
return None
def _get_bd_by_network_id(self, session, network_id):
net_mapping = self._get_network_mapping(session, network_id)
return self._get_network_bd(net_mapping)
@ -3823,7 +3930,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
if vrf_dn:
return aim_resource.VRF.from_dn(vrf_dn)
# Pre-existing EXT NET.
l3out = self._get_svi_net_l3out(network)
l3out = self._get_default_svi_l3out(network)
if l3out:
aim_ctx = aim_context.AimContext(db_session=session)
l3out = self.aim.get(aim_ctx, l3out)

View File

@ -576,11 +576,12 @@ class SfcAIMDriver(SfcAIMDriverBase):
flc_aname = aim_utils.sanitize_display_name(flowc['name'])
aim_ctx = aim_context.AimContext(plugin_context.session)
cidr = netaddr.IPNetwork(cidr)
l3out = self.aim_mech._get_svi_net_l3out(net)
network_db = self.plugin._get_network(plugin_context, net['id'])
l3out = self.aim_mech._get_default_svi_l3out(network_db)
if l3out:
if cidr.prefixlen == 0:
# Use default External Network
ext_net = self.aim_mech._get_svi_default_external_epg(net)
ext_net = self.aim_mech._get_default_svi_ext_epg(network_db)
ext_net_db = self.aim.get(aim_ctx, ext_net)
if not ext_net_db:
raise exceptions.DefaultExternalNetworkNotFound(
@ -622,7 +623,8 @@ class SfcAIMDriver(SfcAIMDriverBase):
prefix)
flc_aname = aim_utils.sanitize_display_name(flowc['name'])
aim_ctx = aim_context.AimContext(plugin_context.session)
l3out = self.aim_mech._get_svi_net_l3out(net)
network_db = self.plugin._get_network(plugin_context, net['id'])
l3out = self.aim_mech._get_default_svi_l3out(network_db)
cidr = netaddr.IPNetwork(cidr)
ext_net = None
if l3out:
@ -633,7 +635,8 @@ class SfcAIMDriver(SfcAIMDriverBase):
epg = self.aim.get(aim_ctx, ext_net)
else:
epg = self.aim.get(
aim_ctx, self.aim_mech._get_svi_default_external_epg(net))
aim_ctx,
self.aim_mech._get_default_svi_ext_epg(network_db))
else:
epg = self.aim.get(aim_ctx, self.aim_mech._get_epg_by_network_id(
plugin_context.session, net['id']))

View File

@ -593,6 +593,9 @@ class TestAimMapping(ApicAimTestCase):
self.assertIsNotNone(aim_ext_net)
return aim_ext_net
def _scope_default_svi_l3out_name_by_vrf(self, vrf_name):
return md.DEFAULT_SVI_L3OUT_NAME + '_' + vrf_name
def _check_network(self, net, routers=None, scope=None, project=None,
vrf=None):
dns = copy.copy(net.get(DN))
@ -650,6 +653,16 @@ class TestAimMapping(ApicAimTestCase):
self.assertEqual(net['name'], l3out.display_name)
self.assertEqual(vrf_aname, l3out.vrf_name)
self._check_dn_is_resource(dns, 'ExternalNetwork', ext_net)
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
vrf_aname)
svi_default_l3out = self._get_l3out(default_l3out_name,
vrf_tenant_aname)
self.assertEqual(tenant_aname, svi_default_l3out.tenant_name)
self.assertEqual(default_l3out_name, svi_default_l3out.name)
self.assertEqual(md.DEFAULT_SVI_L3OUT_NAME,
svi_default_l3out.display_name)
self.assertEqual(vrf_aname, svi_default_l3out.vrf_name)
else:
aim_bd = self._get_bd(aname, tenant_aname)
self.assertEqual(tenant_aname, aim_bd.tenant_name)
@ -1081,6 +1094,9 @@ class TestAimMapping(ApicAimTestCase):
self._delete('networks', net['id'])
self.assertFalse(extn.get_network_extn_db(session, net['id']))
self._check_network_deleted(net)
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
'DefaultVRF')
self._l3out_should_not_exist(default_l3out_name)
def test_security_group_lifecycle(self):
# Test create
@ -1248,6 +1264,14 @@ class TestAimMapping(ApicAimTestCase):
# Verify ports were notified.
mock_notif.assert_has_calls(port_calls, any_order=True)
if is_svi:
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
'DefaultVRF')
contract = self.name_mapper.router(None, router['id'])
tenant_aname = self.name_mapper.project(None, net['tenant_id'])
self._confirm_default_ext_epg_contract(
tenant_aname, default_l3out_name, [contract])
# Check router.
router = self._show('routers', router_id)['router']
self._check_router(router, [gw1_ip], unscoped_project=self._tenant_id,
@ -1329,6 +1353,8 @@ class TestAimMapping(ApicAimTestCase):
mock_notif.assert_has_calls(port_calls, any_order=True)
self._check_router(router, [], unscoped_project=self._tenant_id,
is_svi_net=is_svi)
self._confirm_default_ext_epg_contract(
tenant_aname, default_l3out_name, [])
# Check network.
net = self._show('networks', net_id)['network']
@ -1436,6 +1462,15 @@ class TestAimMapping(ApicAimTestCase):
self.assertRaises(webob.exc.HTTPClientError, self._make_subnet,
self.fmt, net_resp, gw2_ip, '10.0.2.0/24')
def _confirm_default_ext_epg_contract(self, tenant_name, l3out_name,
contract):
default_ext_epg = aim_resource.ExternalNetwork(
tenant_name=tenant_name,
l3out_name=l3out_name, name=md.L3OUT_EXT_EPG)
aim_ext_epg = self._get_l3out_ext_net(default_ext_epg)
self.assertEqual(contract, aim_ext_epg.provided_contract_names)
self.assertEqual(contract, aim_ext_epg.consumed_contract_names)
def _test_router_interface_with_address_scope(self, is_svi=False):
# REVISIT(rkukura): Currently follows same workflow as above,
# but might be sufficient to test with a single subnet with
@ -1516,6 +1551,19 @@ class TestAimMapping(ApicAimTestCase):
{'subnet_id': subnet1_id})
self.assertIn(subnet1_id, info['subnet_ids'])
if is_svi:
default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
'DefaultVRF')
self._l3out_should_not_exist(default_l3out_name)
tenant_aname = self.name_mapper.project(None, scope['tenant_id'])
vrf_aname = self.name_mapper.address_scope(None, scope['id'])
new_default_l3out_name = self._scope_default_svi_l3out_name_by_vrf(
vrf_aname)
contract = self.name_mapper.router(None, router['id'])
self._confirm_default_ext_epg_contract(
tenant_aname, new_default_l3out_name, [contract])
# Verify ports were notified.
mock_notif.assert_has_calls(port_calls, any_order=True)
@ -1602,6 +1650,9 @@ class TestAimMapping(ApicAimTestCase):
self._check_network(net, [router], scope)
else:
self._check_network(net, [], scope)
self._l3out_should_not_exist(new_default_l3out_name)
self._confirm_default_ext_epg_contract(
tenant_aname, default_l3out_name, [])
# Check subnet1.
subnet = self._show('subnets', subnet1_id)['subnet']

View File

@ -234,13 +234,15 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
ppg_args=None):
flowc_ids = []
ppg_args = ppg_args or []
flowcs_args = flowcs_args or []
flowcs_args = flowcs_args or [{'src_svi': self.src_svi,
'dst_svi': self.dst_svi}] * flowcs
for i in range(flowcs):
try:
flowc_ids.append(
self._create_simple_flowc(**flowcs_args[i])['id'])
except IndexError:
flowc_ids.append(self._create_simple_flowc()['id'])
flowc_ids.append(self._create_simple_flowc(
src_svi=self.src_svi, dst_svi=self.dst_svi)['id'])
ppg_ids = []
for i in range(ppgs):
try:
@ -374,7 +376,8 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
flowc['l7_parameters']['logical_source_network'])
dst_net = self._show_network(
flowc['l7_parameters']['logical_destination_network'])
apic_tn = 'prj_' + dst_net['tenant_id']
apic_tn = 'prj_' + dst_net['tenant_id'] if not self.dst_svi else (
'common')
device_clusters = []
sg = self.aim_mgr.get(ctx, aim_sg.ServiceGraph(
tenant_name=apic_tn, name='ptc_' + pc['id']))
@ -395,10 +398,12 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
for net, pref, cidr in [(src_net, 'src_', src_cidr),
(dst_net, 'dst_', dst_cird)]:
if net['apic:svi']:
# TODO(ivar): this will not work, there's no L3Outside
# DN extension for external networks.
ext = aim_res.ExternalNetwork.from_dn(
net['apic:distinguished_names']['ExternalNetwork'])
vrf = aim_res.VRF.from_dn(
net['apic:distinguished_names']['VRF'])
ext = aim_res.ExternalNetwork(
tenant_name=vrf.tenant_name,
l3out_name='DefaultSVIL3Out' + '_' + vrf.name,
name='ExtEpg')
if cidr in ['0.0.0.0/0', '::/0']:
# use default external EPG
ext_net = self.aim_mgr.get(ctx, ext)
@ -409,11 +414,23 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
l3out_name=ext.l3out_name,
name=cidr.replace(
'/', '_') + '_' + 'net_' + net['id']))
ext_sub = self.aim_mgr.get(ctx, aim_res.ExternalSubnet(
tenant_name=ext.tenant_name, l3out_name=ext.l3out_name,
external_network_name=ext_net.name, cidr=cidr))
self.assertIsNotNone(ext_net)
self.assertIsNotNone(ext_sub)
if cidr in ['0.0.0.0/0', '::/0']:
for c in ['128.0.0.0/1', '0.0.0.0/1']:
ext_sub = self.aim_mgr.get(
ctx, aim_res.ExternalSubnet(
tenant_name=ext.tenant_name,
l3out_name=ext.l3out_name,
external_network_name=ext_net.name,
cidr=c))
self.assertIsNotNone(ext_sub)
else:
ext_sub = self.aim_mgr.get(
ctx, aim_res.ExternalSubnet(
tenant_name=ext.tenant_name,
l3out_name=ext.l3out_name,
external_network_name=ext_net.name, cidr=cidr))
self.assertIsNotNone(ext_sub)
self.assertTrue(
contract.name in (ext_net.consumed_contract_names if
pref == 'src_' else
@ -1152,6 +1169,7 @@ class TestPortChain(TestAIMServiceFunctionChainingBase):
name=fc['destination_ip_prefix'].replace(
'/', '_') + '_' + 'net_' + dst_net_id)[0]
self.assertEqual(2, len(ext_net.provided_contract_names))
self.assertTrue('DefaultSVIL3Out' in ext_net.l3out_name)
self.delete_port_chain(pc2['id'])
self.assertIsNone(self.aim_mgr.get(self._aim_context, ext_net))
@ -1278,3 +1296,7 @@ class TestPortChainSVI(TestPortChain):
expected_res_status=201)['port_chain']
self._verify_pc_mapping(pc)
self._verify_pc_delete(pc)
def test_pc_mapping_two_flowcs(self):
# TODO(ivar): re enable after fixing the conflicting address scope
pass