Make sure flow classifier removal doesn't effect other chains

Some flow classifiers can share the same provider/consumer network.
When removed from a chain, we need to make sure we don't unset
the corresponding contract for other chains sharing the same provider.

Change-Id: I196850de422b1ba6da9598c81f2e7e5f24b643a0
This commit is contained in:
Ivar Lazzaro 2018-02-19 17:28:25 -08:00
parent 96bcf44602
commit 8a7375f10b
No known key found for this signature in database
GPG Key ID: ACEEC8CB558DC3CF
2 changed files with 77 additions and 27 deletions

View File

@ -619,30 +619,31 @@ class SfcAIMDriver(SfcAIMDriverBase):
aim_ctx = aim_context.AimContext(plugin_context.session)
l3out = self.aim_mech._get_svi_net_l3out(net)
cidr = netaddr.IPNetwork(cidr)
epg = None
ext_net = None
if l3out:
if cidr.prefixlen != 0:
ext_net = aim_resource.ExternalNetwork(
tenant_name=l3out.tenant_name, l3out_name=l3out.name,
name=flc_aid, display_name=flc_aname)
self.aim.delete(aim_ctx, ext_net, cascade=True)
else:
ext_net = self.aim_mech._get_svi_default_external_epg(net)
epg = self.aim.get(aim_ctx, ext_net)
else:
epg = self.aim.get(
aim_ctx, self.aim_mech._get_svi_default_external_epg(net))
else:
epg = self.aim.get(aim_ctx, self.aim_mech._get_epg_by_network_id(
plugin_context.session, net['id']))
if epg:
contract = self._get_flc_contract(plugin_context.session, flowc,
tenant)
try:
if prefix == FLOWC_SRC:
epg.consumed_contract_names.remove(contract.name)
else:
epg.provided_contract_names.remove(contract.name)
self.aim.create(aim_ctx, epg, overwrite=True)
except ValueError:
pass
if prefix == FLOWC_SRC:
epg.consumed_contract_names.remove(contract.name)
else:
epg.provided_contract_names.remove(contract.name)
self.aim.create(aim_ctx, epg, overwrite=True)
if (ext_net and not epg.consumed_contract_names and not
epg.provided_contract_names):
# Only remove external network if completely empty
self.aim.delete(aim_ctx, ext_net, cascade=True)
def _get_chains_by_classifier_id(self, plugin_context, flowc_id):
context = plugin_context

View File

@ -305,7 +305,7 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
'mac': eprt['mac_address']} for eprt in eprts]),
erp.destinations)
def _verify_pc_mapping(self, pc):
def _verify_pc_mapping(self, pc, multiple=False):
ctx = self._aim_context
flowcs = [self.show_flow_classifier(x)['flow_classifier'] for x in
pc['flow_classifiers']]
@ -314,19 +314,22 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
for flowc in flowcs])
ppgs = [self.show_port_pair_group(x)['port_pair_group'] for x in
pc['port_pair_groups']]
self.assertEqual(
len(flowcs), len(self.aim_mgr.find(ctx, aim_res.Contract)))
self.assertEqual(
len(flowcs), len(self.aim_mgr.find(ctx, aim_res.ContractSubject)))
self.assertEqual(
len(flowc_tenants) * len(ppgs),
len(self.aim_mgr.find(ctx, aim_sg.DeviceClusterContext)))
self.assertEqual(
len(flowc_tenants) * len(ppgs) * 2,
len(self.aim_mgr.find(ctx, aim_sg.DeviceClusterInterfaceContext)))
self.assertEqual(
len(flowc_tenants),
len(self.aim_mgr.find(ctx, aim_sg.ServiceGraph)))
if not multiple:
self.assertEqual(
len(flowcs), len(self.aim_mgr.find(ctx, aim_res.Contract)))
self.assertEqual(
len(flowcs), len(self.aim_mgr.find(ctx,
aim_res.ContractSubject)))
self.assertEqual(
len(flowc_tenants) * len(ppgs),
len(self.aim_mgr.find(ctx, aim_sg.DeviceClusterContext)))
self.assertEqual(
len(flowc_tenants) * len(ppgs) * 2,
len(self.aim_mgr.find(ctx,
aim_sg.DeviceClusterInterfaceContext)))
self.assertEqual(
len(flowc_tenants),
len(self.aim_mgr.find(ctx, aim_sg.ServiceGraph)))
for flowc in flowcs:
src_net = self._show_network(
flowc['l7_parameters']['logical_source_network'])
@ -375,7 +378,9 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
self.assertTrue(
contract.name in (ext_net.consumed_contract_names if
pref == 'src_' else
ext_net.provided_contract_names))
ext_net.provided_contract_names),
"%s not in ext net %s" % (contract.name,
ext_net.__dict__))
else:
epg = self.aim_mgr.get(
ctx, aim_res.EndpointGroup.from_dn(
@ -1022,6 +1027,50 @@ class TestPortChain(TestAIMServiceFunctionChainingBase):
ppg3['id'], ppg4['id']],
expected_res_status=500)
def test_pc_move_fc(self):
fc = self._create_simple_flowc(src_svi=self.src_svi,
dst_svi=self.dst_svi)
fcs = [fc]
for i in range(3):
fcs.append(self.create_flow_classifier(
l7_parameters={
'logical_source_network': fc[
'l7_parameters']['logical_source_network'],
'logical_destination_network': fc[
'l7_parameters']['logical_destination_network']},
source_ip_prefix='192.168.%s.0/24' % (i + 3),
destination_ip_prefix=fc['destination_ip_prefix'],
expected_res_status=201)['flow_classifier'])
# We have four FCs
ppg1 = self._create_simple_ppg(pairs=1)
ppg2 = self._create_simple_ppg(pairs=1)
pc1 = self.create_port_chain(port_pair_groups=[ppg1['id']],
flow_classifiers=[fcs[0]['id'],
fcs[1]['id']],
expected_res_status=201)['port_chain']
pc2 = self.create_port_chain(port_pair_groups=[ppg2['id']],
flow_classifiers=[fcs[2]['id'],
fcs[3]['id']],
expected_res_status=201)['port_chain']
self._verify_pc_mapping(pc1, multiple=True)
self._verify_pc_mapping(pc2, multiple=True)
# Remove FC 2
pc1 = self.update_port_chain(pc1['id'],
flow_classifiers=[fcs[0]['id']],
expected_res_status=200)['port_chain']
self._verify_pc_mapping(pc1, multiple=True)
self._verify_pc_mapping(pc2, multiple=True)
if self.dst_svi:
self.delete_port_chain(pc1['id'])
dst_net_id = fc['l7_parameters']['logical_destination_network']
ext_net = self.aim_mgr.find(
self._aim_context, aim_res.ExternalNetwork,
name=fc['destination_ip_prefix'].replace(
'/', '_') + '_' + 'net_' + dst_net_id)[0]
self.assertEqual(2, len(ext_net.provided_contract_names))
self.delete_port_chain(pc2['id'])
self.assertIsNone(self.aim_mgr.get(self._aim_context, ext_net))
class TestPortChainSVI(TestPortChain):