Convert DataChangeListeners to DataTreeChangeListeners
[groupbasedpolicy.git] / renderers / faas / src / main / java / org / opendaylight / groupbasedpolicy / renderer / faas / FaasPolicyManager.java
1 /*
2  * Copyright (c) 2015 Huawei Technologies and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.groupbasedpolicy.renderer.faas;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Optional;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.Executor;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
26 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.faas.uln.datastore.api.Pair;
34 import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi;
35 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
36 import org.opendaylight.groupbasedpolicy.util.IidFactory;
37 import org.opendaylight.groupbasedpolicy.util.TenantUtils;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.logical.routers.rev151013.logical.routers.container.logical.routers.LogicalRouterBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.logical.switches.rev151013.logical.switches.container.logical.switches.LogicalSwitchBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.PortLocationAttributes.LocationType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.LogicalNetworks;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.ScopeType;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.ServiceCommunicationLayer;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetwork;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.LogicalNetworkBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.logical.network.ConsumerNetworkBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.logical.networks.logical.network.ProviderNetworkBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntity;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedEntityBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenant;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.MappedTenantBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedContract;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.FollowedTenantBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroup;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.interests.followed.tenants.followed.tenant.FollowedEndpointGroupBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.ResolvedPolicies;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.ResolvedPolicy.ExternalImplicitGroup;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.PolicyRuleGroupWithEndpointConstraints;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.resolved.policy.rev150828.resolved.policies.resolved.policy.policy.rule.group.with.endpoint.constraints.PolicyRuleGroup;
81 import org.opendaylight.yangtools.concepts.ListenerRegistration;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 public class FaasPolicyManager implements DataTreeChangeListener<ResolvedPolicy>, AutoCloseable {
87
88     private static final Logger LOG = LoggerFactory.getLogger(FaasPolicyManager.class);
89     private static final RendererName rendererName = new RendererName("faas");
90     private final ListenerRegistration<?> registerListener;
91     private final Executor executor;
92     private final DataBroker dataProvider;
93     final Map<Pair<EndpointGroupId, TenantId>, List<SubnetId>> epgSubnetsMap = new HashMap<>();
94     private final ConcurrentHashMap<TenantId, Uuid> mappedTenants = new ConcurrentHashMap<>();
95     final ConcurrentHashMap<TenantId, ArrayList<ListenerRegistration<?>>> registeredTenants =
96             new ConcurrentHashMap<>();
97
98     public FaasPolicyManager(DataBroker dataBroker, Executor executor) {
99         this.dataProvider = dataBroker;
100         this.executor = executor;
101         this.registerListener = checkNotNull(dataProvider).registerDataTreeChangeListener(new DataTreeIdentifier<>(
102                 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(ResolvedPolicies.class)
103                     .child(ResolvedPolicy.class).build()), this);
104
105         RendererBuilder rendBuilder = new RendererBuilder();
106         rendBuilder.setName(rendererName);
107         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
108         wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.rendererIid(rendererName), rendBuilder.build());
109         if (DataStoreHelper.submitToDs(wTx)) {
110             LOG.debug("{} renderer registered with the multi-renderer manager", rendererName.getValue());
111         } else {
112             LOG.error("{} renderer Failed to register with the multi-renderer manager", rendererName.getValue());
113         }
114     }
115
116     @Override
117     public void close() throws Exception {
118         synchronized (registeredTenants) {
119             for (ArrayList<ListenerRegistration<?>> list : registeredTenants.values()) {
120                 list.forEach(ListenerRegistration::close);
121             }
122             registeredTenants.clear();
123
124             LOG.debug("Closed All Tenant Registerations");
125         }
126         if (registerListener != null) {
127             registerListener.close();
128         }
129     }
130
131     @Override
132     public void onDataTreeChanged(Collection<DataTreeModification<ResolvedPolicy>> changes) {
133         executor.execute(() -> executeEvent(changes));
134     }
135
136     private void executeEvent(final Collection<DataTreeModification<ResolvedPolicy>> changes) {
137         for (DataTreeModification<ResolvedPolicy> change: changes) {
138             DataObjectModification<ResolvedPolicy> rootNode = change.getRootNode();
139             ResolvedPolicy oldPolicy = rootNode.getDataBefore();
140             switch (rootNode.getModificationType()) {
141                 case SUBTREE_MODIFIED:
142                 case WRITE:
143                     ResolvedPolicy newPolicy = rootNode.getDataAfter();
144                     if (!isEqualService(newPolicy, oldPolicy)) {
145                         removeLogicalNetwork(oldPolicy);
146                     }
147
148                     if (handledPolicy(newPolicy)) {
149                         LOG.debug("Updated Policy: Consumer EPG {}, Provider EPG {}", newPolicy.getConsumerEpgId(),
150                                 newPolicy.getProviderEpgId());
151                         updateLogicalNetwork(newPolicy);
152                     }
153                     break;
154                 case DELETE:
155                     LOG.debug("Removed Policy: Consumer EPG {}, Provider EPG {}", oldPolicy.getConsumerEpgId(),
156                             oldPolicy.getProviderEpgId());
157                     removeLogicalNetwork(oldPolicy);
158                     break;
159                 default:
160                     break;
161             }
162         }
163     }
164
165     public void registerTenant(TenantId gbpTenantId) {
166         registerTenant(gbpTenantId, null);
167     }
168
169     public void registerTenant(TenantId gbpTenantId, EndpointGroupId epgId) {
170         if (registeredTenants.get(gbpTenantId) != null) {
171             registerFollowedEndpointgroup(gbpTenantId, epgId);
172             return; // already registered
173         }
174         synchronized (this) {
175             if (registeredTenants.get(gbpTenantId) != null) {
176                 return; // already registered
177             }
178             /*
179              * map tenant's required elements to faas logical networks
180              */
181             Optional<MappedTenant> mTenantOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
182                     FaasIidFactory.mappedTenantIid(gbpTenantId), dataProvider.newReadOnlyTransaction());
183             Uuid faasTenantId;
184             if (mTenantOptional.isPresent()) {
185                 faasTenantId = mTenantOptional.get().getFaasTenantId();
186             } else {
187                 faasTenantId = getFaasTenantId(gbpTenantId);
188             }
189             // load tenant datastore info
190             Tenant tenant = null;
191             Optional<Tenant> tenantOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
192                     TenantUtils.tenantIid(gbpTenantId), dataProvider.newReadOnlyTransaction());
193             if (tenantOptional.isPresent()) {
194                 tenant = tenantOptional.get();
195             }
196             List<Contract> contracts = null;
197             List<Subnet> subnets = null;
198             if (tenant != null) {
199                 contracts = tenant.getPolicy().getContract();
200                 subnets = tenant.getForwardingContext().getSubnet();
201             }
202             Optional<MappedEntity> mEntityOptional = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
203                     FaasIidFactory.mappedEntityIid(gbpTenantId),
204                     dataProvider.newReadOnlyTransaction());
205             MappedEntity mappedEntity;
206             if (mEntityOptional.isPresent()) {
207                 mappedEntity = mEntityOptional.get();
208             } else {
209                 // This is needed as a workaround of a datastore problem
210                 MappedEntityBuilder builder = new MappedEntityBuilder();
211                 builder.setGbpTenantId(gbpTenantId);
212                 mappedEntity = builder.build();
213                 WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
214                 wTx.put(LogicalDatastoreType.OPERATIONAL,
215                         FaasIidFactory.mappedEntityIid(gbpTenantId), mappedEntity);
216                 if (DataStoreHelper.submitToDs(wTx)) {
217                     LOG.debug("Initailized Mapped Entry in Datastore for tenant {}", gbpTenantId);
218                 } else {
219                     LOG.error("Couldn't Initailized Mapped Entry in Datastore for tenant {}", gbpTenantId);
220                 }
221             }
222
223             // contracts
224             FaasContractManagerListener faasContractManagerListener = new FaasContractManagerListener(dataProvider,
225                     gbpTenantId, faasTenantId, executor);
226             faasContractManagerListener.loadAll(contracts, mappedEntity.getMappedContract());
227             // subnets
228             FaasSubnetManagerListener faasSubnetManagerListener = new FaasSubnetManagerListener(dataProvider,
229                     gbpTenantId, faasTenantId, executor);
230             faasSubnetManagerListener.loadAll(subnets, mappedEntity.getMappedSubnet());
231
232             /*
233              * tenant registrations
234              */
235             ArrayList<ListenerRegistration<?>> list = new ArrayList<>();
236             ListenerRegistration<?> reg;
237             // contracts
238             reg = dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(
239                     LogicalDatastoreType.CONFIGURATION, IidFactory.contractWildcardIid(gbpTenantId)),
240                     faasContractManagerListener);
241             list.add(reg);
242             // subnets
243             reg = dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(
244                     LogicalDatastoreType.CONFIGURATION, IidFactory.subnetWildcardIid(gbpTenantId)),
245                     faasSubnetManagerListener);
246             list.add(reg);
247
248             // tenant
249             reg = dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(
250                     LogicalDatastoreType.CONFIGURATION, IidFactory.tenantIid(gbpTenantId)),
251                     new FaasTenantManagerListener(this, gbpTenantId, faasTenantId, executor));
252             list.add(reg);
253
254             // Map previously resolved policy for this tenant
255             mapAllTenantResolvedPolicies(gbpTenantId, null);
256
257             registerFollowedTenant(gbpTenantId, epgId);
258
259             // track all registrations
260             registeredTenants.put(gbpTenantId, list);
261
262             LOG.debug("Registered tenant {}", gbpTenantId);
263         }
264     }
265
266     private void mapAllTenantResolvedPolicies(TenantId gbpTenantId, EndpointGroupId epgId) {
267         Optional<ResolvedPolicies> resolvedPoliciesOptional = DataStoreHelper.readFromDs(
268                 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(ResolvedPolicies.class).build(),
269                 dataProvider.newReadOnlyTransaction());
270         if (!resolvedPoliciesOptional.isPresent() || resolvedPoliciesOptional.get().getResolvedPolicy() == null) {
271             return;
272         }
273         //TODO forEach possible?
274         List<ResolvedPolicy> resolvedPolicies = resolvedPoliciesOptional.get().getResolvedPolicy();
275         for (ResolvedPolicy policy : resolvedPolicies) {
276             if (policy.getConsumerTenantId().equals(gbpTenantId)) {
277                 if (epgId == null || epgId.equals(policy.getConsumerEpgId()) || epgId.equals(policy.getProviderEpgId())) {
278                     // if any epg or a specific epg policy
279                     updateLogicalNetwork(policy);
280                 }
281             }
282         }
283     }
284
285     private void registerFollowedTenant(TenantId gbpTenantId, EndpointGroupId epgId) {
286         FollowedTenantBuilder fTenantBuilder = new FollowedTenantBuilder();
287         fTenantBuilder.setId(gbpTenantId);
288         if (epgId != null) {
289             List<FollowedEndpointGroup> epgs = new ArrayList<>();
290             epgs.add(new FollowedEndpointGroupBuilder().setId(epgId).build());
291             fTenantBuilder.setFollowedEndpointGroup(epgs);
292         }
293         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
294         wTx.put(LogicalDatastoreType.OPERATIONAL, IidFactory.followedTenantIid(rendererName, gbpTenantId),
295                 fTenantBuilder.build());
296         if (DataStoreHelper.submitToDs(wTx)) {
297             LOG.info("Tenant {} is followed by renderer {}", gbpTenantId.getValue(), rendererName.getValue());
298         } else {
299             LOG.info("Couldn't register Tenant {} that is followed by renderer {}", gbpTenantId.getValue(),
300                     rendererName.getValue());
301         }
302     }
303
304     @VisibleForTesting
305     void registerFollowedEndpointgroup(TenantId gbpTenantId, EndpointGroupId epgId) {
306         if (epgId == null) {
307             return;
308         }
309         FollowedEndpointGroupBuilder fEpgBuilder = new FollowedEndpointGroupBuilder();
310         fEpgBuilder.setId(epgId);
311         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
312         wTx.put(LogicalDatastoreType.OPERATIONAL,
313                 IidFactory.followedEndpointgroupIid(rendererName, gbpTenantId, epgId), fEpgBuilder.build());
314         if (DataStoreHelper.submitToDs(wTx)) {
315             LOG.trace("EPG {} in Tenant {} is followed by renderer {}", epgId.getValue(), gbpTenantId.getValue(),
316                     rendererName.getValue());
317         } else {
318             LOG.info("Couldn't register EPG {} in Tenant {} that is followed by renderer {}", epgId.getValue(),
319                     gbpTenantId.getValue(), rendererName.getValue());
320         }
321     }
322
323     public Uuid getFaasTenantId(TenantId tenantId) {
324         Uuid val = mappedTenants.get(tenantId);
325         if (val != null) {
326             return val;
327         }
328         Uuid faasTenantId;
329         if (isUUid(tenantId.getValue())) {
330             faasTenantId = new Uuid(tenantId.getValue());
331         } else {
332             faasTenantId = new Uuid(UUID.randomUUID().toString());
333         }
334         mappedTenants.putIfAbsent(tenantId, faasTenantId);
335         val = mappedTenants.get(tenantId);
336         MappedTenantBuilder builder = new MappedTenantBuilder();
337         builder.setFaasTenantId(val);
338         builder.setGbpTenantId(tenantId);
339         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
340         MappedTenant result = builder.build();
341         wTx.put(LogicalDatastoreType.OPERATIONAL, FaasIidFactory.mappedTenantIid(tenantId), result);
342         if (DataStoreHelper.submitToDs(wTx)) {
343             LOG.debug("Cached in Datastore Mapped Tenant {}", result);
344         } else {
345             LOG.error("Couldn't Cache in Datastore Mapped Tenant {}", result);
346         }
347         return val;
348     }
349
350     public static boolean isUUid(String value) {
351         return value != null && value.matches("[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}");
352     }
353
354     public void unregisterTenant(TenantId tenantId) {
355
356         ArrayList<ListenerRegistration<?>> list = registeredTenants.remove(tenantId);
357         if (list != null) {
358             for (ListenerRegistration<?> reg : list) {
359                 if (reg != null) {
360                     reg.close();
361                 }
362             }
363             LOG.debug("Unregistered tenant {}", tenantId);
364         }
365         registeredTenants.remove(tenantId);
366         Uuid faasTenantId = mappedTenants.get(tenantId);
367         if (faasTenantId != null) {
368             removeTenantLogicalNetwork(tenantId, faasTenantId, false);
369         }
370     }
371
372     public boolean isTenantRegistered(TenantId tenantId) {
373         return registeredTenants.containsKey(tenantId);
374     }
375
376     @VisibleForTesting
377     boolean handledPolicy(ResolvedPolicy policy) {
378         if (!policy.getConsumerTenantId().equals(policy.getProviderTenantId())) {
379             // FAAS always assumes consumer and provider EPGs belong to the same tenant
380             LOG.warn(
381                     "Ignore Resolved Policy between Consumer EPG {} and Provider EPG {} becuase they belong to different Tenants",
382                     policy.getConsumerTenantId().getValue(), policy.getProviderTenantId().getValue());
383             return false;
384         }
385         return isTenantRegistered(policy.getConsumerTenantId());
386     }
387
388     private boolean isEqualService(ResolvedPolicy newPolicy, ResolvedPolicy oldPolicy) {
389         return oldPolicy != null && newPolicy.getConsumerEpgId().equals(oldPolicy.getConsumerEpgId())
390                 && newPolicy.getProviderEpgId().equals(oldPolicy.getProviderEpgId())
391                 && newPolicy.getConsumerTenantId().equals(oldPolicy.getConsumerTenantId())
392                 && newPolicy.getProviderTenantId().equals(oldPolicy.getProviderTenantId());
393     }
394
395     public void registerSubnetWithEpg(EndpointGroupId epgId, TenantId tenantId, SubnetId subnetId) {
396         registerSubnetWithEpg(epgId, tenantId, subnetId, true);
397     }
398
399     private void registerSubnetWithEpg(EndpointGroupId epgId, TenantId tenantId, SubnetId subnetId, boolean updateLn) {
400         synchronized (this) {
401             List<SubnetId> subnets = cloneAndGetEpgSubnets(epgId, tenantId);
402             if(subnets.contains(subnetId)){
403                 return;
404             }
405             subnets.add(subnetId);
406             epgSubnetsMap.put(new Pair<>(epgId, tenantId), subnets);
407             LOG.debug("Registered Subnet {} with EPG {}", subnetId, epgId);
408             if (updateLn) {
409                 mapAllTenantResolvedPolicies(tenantId, epgId);
410             }
411         }
412     }
413
414     @VisibleForTesting
415     void removeLogicalNetwork(ResolvedPolicy oldPolicy) {
416         if (oldPolicy == null) {
417             return;
418         }
419         removeLogicalNetwork(oldPolicy.getConsumerEpgId(), oldPolicy.getConsumerTenantId(), getContractId(oldPolicy),
420                 oldPolicy.getProviderEpgId(), oldPolicy.getProviderTenantId());
421     }
422
423     private void removeLogicalNetwork(EndpointGroupId consumerEpgId, TenantId consumerTenantId, ContractId contractId,
424             EndpointGroupId providerEpgId, TenantId providerTenantId) {
425         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
426         Optional<LogicalNetwork> lnOp = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
427                 FaasIidFactory.logicalNetworkIid(consumerEpgId, consumerTenantId, contractId,
428                         providerEpgId, providerTenantId), rwTx);
429         if (lnOp.isPresent()) {
430             DataStoreHelper.submitToDs(rwTx);
431             LogicalNetwork logicalNetwork = lnOp.get();
432             Uuid consTenantId = getFaasTenantId(logicalNetwork.getConsumerTenantId());
433             Uuid provTenantId = getFaasTenantId(logicalNetwork.getProviderTenantId());
434
435             UlnDatastoreApi.removeLogicalSwitchFromDsIfExists(consTenantId, logicalNetwork.getConsumerNetwork()
436                 .getLogicalSwitchId());
437             UlnDatastoreApi.removeLogicalSwitchFromDsIfExists(provTenantId, logicalNetwork.getProviderNetwork()
438                 .getLogicalSwitchId());
439             if (logicalNetwork.getConsumerNetwork().getLogicalRouterId() != null) {
440                 UlnDatastoreApi.removeLogicalRouterFromDsIfExists(consTenantId, logicalNetwork.getConsumerNetwork()
441                     .getLogicalRouterId());
442             }
443             if (logicalNetwork.getProviderNetwork().getLogicalRouterId() != null) {
444                 UlnDatastoreApi.removeLogicalRouterFromDsIfExists(provTenantId, logicalNetwork.getProviderNetwork()
445                     .getLogicalRouterId());
446             }
447         }
448     }
449
450     private synchronized void updateLogicalNetwork(ResolvedPolicy policy) {
451         updateLogicalNetwork(policy.getConsumerEpgId(), getContractId(policy), policy.getProviderEpgId(),
452                 policy.getConsumerTenantId(), policy.getExternalImplicitGroup());
453     }
454
455     private synchronized void updateLogicalNetwork(EndpointGroupId consumerEpgId, ContractId contractId,
456             EndpointGroupId providerEpgId, TenantId tenantId, ExternalImplicitGroup externalImplicitGroup) {
457
458         LOG.trace("Start updateLogicalNetwork: Consumer EPG {}   Provider Epg {}   Contract {}", consumerEpgId,
459                 providerEpgId, contractId);
460
461         // Create Logical network
462         EndpointGroup consEpg = readEndpointGroup(consumerEpgId, tenantId);
463         if (consEpg == null) {
464             LOG.error("Couldn't Creat Logical Network. Missing EPG {}", consumerEpgId);
465             return;
466         }
467         List<SubnetId> consSubnetIds = cloneAndGetEpgSubnets(consEpg.getId(), tenantId);
468         if (consSubnetIds.isEmpty()) {
469             LOG.info("Couldn't Creat Logical Network. Missing Subnets for Consumer EPG {}", consumerEpgId);
470             return;
471         }
472         EndpointGroup provEpg = readEndpointGroup(providerEpgId, tenantId);
473         if (provEpg == null) {
474             LOG.error("Couldn't Creat Logical Network. Missing EPG {}", providerEpgId);
475             return;
476         }
477         List<SubnetId> provSubnetIds = cloneAndGetEpgSubnets(provEpg.getId(), tenantId);
478         if (provSubnetIds.isEmpty()) {
479             LOG.info("Couldn't Creat Logical Network. Missing Subnets for Provider EPG {}", providerEpgId);
480             return;
481         }
482
483         ServiceCommunicationLayer comLayer = findLayerNetwork(tenantId, consSubnetIds, provSubnetIds);
484         if (comLayer == null) {
485             LOG.error(
486                     "Couldn't determine forwarding Context. Couldn't Process Logical Network for Consumer EPG {}   Provider Epg {}   Contract {}",
487                     consumerEpgId, providerEpgId, contractId);
488             return;
489         }
490
491         if (needToCreateLogicalNetwork(comLayer, consSubnetIds, provSubnetIds, tenantId, contractId, provEpg, consEpg,
492                 externalImplicitGroup)) {
493             if (comLayer == ServiceCommunicationLayer.Layer2) {
494                 createLayer2LogicalNetwork(consEpg, contractId, provEpg, tenantId, comLayer, externalImplicitGroup);
495             } else if (comLayer == ServiceCommunicationLayer.Layer3) {
496                 createLayer3LogicalNetwork(consEpg, contractId, provEpg, tenantId, comLayer, externalImplicitGroup);
497             } else {
498                 LOG.error("Couldn't find the communication layer.Consumer EPG {}   Provider Epg {}   Contract {}",
499                         consumerEpgId, providerEpgId, contractId);
500             }
501         } else {
502             LOG.debug("No need to Create the Logical Network. Consumer EPG {}   Provider Epg {}   Contract {}",
503                     consumerEpgId, providerEpgId, contractId);
504         }
505     }
506
507     private boolean isConsumerPublic(ExternalImplicitGroup externalImplicitGroup) {
508         return externalImplicitGroup != null && externalImplicitGroup == ExternalImplicitGroup.ConsumerEpg;
509     }
510
511     private boolean isProviderPublic(ExternalImplicitGroup externalImplicitGroup) {
512         return externalImplicitGroup != null && externalImplicitGroup == ExternalImplicitGroup.ProviderEpg;
513     }
514
515     private List<SubnetId> cloneAndGetEpgSubnets(EndpointGroupId epgId, TenantId tenantId) {
516         synchronized (this) {
517             List<SubnetId> list1 = epgSubnetsMap.get(new Pair<>(epgId, tenantId));
518             if (list1 == null) {
519                 return new ArrayList<>();
520             }
521             List<SubnetId> list2 = new ArrayList<>();
522             for (SubnetId id : list1) {
523                 list2.add(new SubnetId(id));
524             }
525             return list2;
526         }
527     }
528
529     protected void createLayer3LogicalNetwork(EndpointGroup consEpg, ContractId contractId, EndpointGroup provEpg,
530             TenantId gbpTenantId, ServiceCommunicationLayer comLayer, ExternalImplicitGroup externalImplicitGroup) {
531         LOG.trace("Start createLayer3LogicalNetwork: Consumer EPG {}   Provider Epg {}   Contract {}", consEpg.getId()
532             .getValue(), provEpg.getId().getValue(), contractId);
533         LogicalNetworkBuilder lNetbuilder = buildLayer2LogicalNetwork(consEpg, provEpg, gbpTenantId, null,
534                 externalImplicitGroup);
535         if (lNetbuilder == null) {
536             LOG.error("Failed to create Logical Switchs layer on the Logical network");
537             return;
538         }
539         Uuid privateSecRulesId = getFaasSecRulesId(contractId, gbpTenantId);
540         if (privateSecRulesId == null) {
541             LOG.error(
542                     "Couldn't Create Logical Network because unable to find FAAS Security Rules Id based on GBP Contract {}",
543                     contractId);
544             return;
545         }
546
547         Uuid faasTenantId = getFaasTenantId(gbpTenantId);
548         LogicalRouterBuilder consLR = initLogicalRouterBuilder(consEpg, faasTenantId,
549                 isConsumerPublic(externalImplicitGroup));
550         LogicalRouterBuilder provLR = initLogicalRouterBuilder(provEpg, faasTenantId,
551                 isProviderPublic(externalImplicitGroup));
552
553         if (!UlnDatastoreApi.attachAndSubmitToDs(consLR, provLR, new Pair<>(null, privateSecRulesId), null)) {
554             LOG.error("Failed to join Logical Routers in a Logical Network");
555             return;
556         }
557
558         if (!UlnDatastoreApi.attachAndSubmitToDs(consLR.getUuid(), lNetbuilder.getConsumerNetwork()
559             .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType))) {
560             LOG.error("Failed to join Consumer Logical Router to Logical Switch in a Logical Network");
561             return;
562         }
563         LOG.debug("Attached Consumer Router {} to Consumer Switch {}", consLR.getUuid().getValue(),
564                 lNetbuilder.getConsumerNetwork().getLogicalSwitchId().getValue());
565         if (!UlnDatastoreApi.attachAndSubmitToDs(provLR.getUuid(), lNetbuilder.getProviderNetwork()
566             .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType))) {
567             LOG.error("Failed to join Provider Logical Router to Logical Switch in a Logical Network");
568             return;
569         }
570         LOG.debug("Attached Provider Router {} to Provider Switch {}", provLR.getUuid().getValue(),
571                 lNetbuilder.getProviderNetwork().getLogicalSwitchId().getValue());
572         ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder(lNetbuilder.getConsumerNetwork());
573         cNetBuilder.setLogicalRouterId(consLR.getUuid());
574         lNetbuilder.setConsumerNetwork(cNetBuilder.build());
575         ProviderNetworkBuilder pNetBuilder = new ProviderNetworkBuilder(lNetbuilder.getProviderNetwork());
576         pNetBuilder.setLogicalRouterId(provLR.getUuid());
577         lNetbuilder.setProviderNetwork(pNetBuilder.build());
578         lNetbuilder.setContractId(contractId);
579         lNetbuilder.setContractTenantId(gbpTenantId);
580         LogicalNetwork result = lNetbuilder.build();
581         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
582         InstanceIdentifier<LogicalNetwork> iid = FaasIidFactory.logicalNetworkIid(
583                 consEpg.getId(), gbpTenantId, contractId, provEpg.getId(), gbpTenantId);
584         wTx.put(LogicalDatastoreType.OPERATIONAL, iid, result);
585         if (DataStoreHelper.submitToDs(wTx)) {
586             LOG.debug("Cached in Datastore Mapped Logical Network {}", result);
587         } else {
588             LOG.error("Couldn't Cache in Datastore Mapped Logical Network {}", result);
589         }
590         LOG.debug("Created Layer 3 Logical network consEpg {}, contractId {}, provEpg {}", consEpg.getId().getValue(),
591                 contractId.getValue(), provEpg.getId().getValue());
592     }
593
594     protected void createLayer2LogicalNetwork(EndpointGroup consEpg, ContractId contractId, EndpointGroup provEpg,
595             TenantId gbpTenantId, ServiceCommunicationLayer comLayer, ExternalImplicitGroup externalImplicitGroup) {
596         LOG.trace("Start createLayer2LogicalNetwork: Consumer EPG {}   Provider Epg {}   Contract {}", consEpg.getId()
597             .getValue(), provEpg.getId().getValue(), contractId);
598         Uuid secRulesId = getFaasSecRulesId(contractId, gbpTenantId);
599         if (secRulesId == null) {
600             LOG.error(
601                     "Couldn't Create Logical Network because unable to find FAAS Security Rules Id based on GBP Contract {}",
602                     contractId);
603             return;
604         }
605         LogicalNetworkBuilder lNetbuilder = buildLayer2LogicalNetwork(consEpg, provEpg, gbpTenantId, secRulesId,
606                 externalImplicitGroup);
607         if (lNetbuilder == null) {
608             LOG.error("Failed to create Logical Switchs layer on the Logical network");
609             return;
610         }
611
612         if (isConsumerPublic(externalImplicitGroup)) {
613             Uuid faasTenantId = getFaasTenantId(gbpTenantId);
614             LogicalRouterBuilder consLR = initLogicalRouterBuilder(consEpg, faasTenantId, true);
615             UlnDatastoreApi.submitLogicalRouterToDs(consLR.build());
616             ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder(lNetbuilder.getConsumerNetwork());
617             cNetBuilder.setLogicalRouterId(consLR.getUuid());
618             lNetbuilder.setConsumerNetwork(cNetBuilder.build());
619             if (!UlnDatastoreApi.attachAndSubmitToDs(consLR.getUuid(), lNetbuilder.getConsumerNetwork()
620                 .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType),
621                     null, null)) {
622                 LOG.error("Failed to join Consumer Public Logical Router to Logical Switch in a Logical Network");
623             }
624             LOG.debug("Attached Consumer Public Router {} to Consumer Switch {}", consLR.getUuid().getValue(),
625                     lNetbuilder.getConsumerNetwork().getLogicalSwitchId().getValue());
626         }
627         if (isProviderPublic(externalImplicitGroup)) {
628             Uuid faasTenantId = getFaasTenantId(gbpTenantId);
629             LogicalRouterBuilder provLR = initLogicalRouterBuilder(provEpg, faasTenantId, true);
630             provLR.setPublic(true);
631             UlnDatastoreApi.submitLogicalRouterToDs(provLR.build());
632             ProviderNetworkBuilder cNetBuilder = new ProviderNetworkBuilder(lNetbuilder.getProviderNetwork());
633             cNetBuilder.setLogicalRouterId(provLR.getUuid());
634             lNetbuilder.setProviderNetwork(cNetBuilder.build());
635             if (!UlnDatastoreApi.attachAndSubmitToDs(provLR.getUuid(), lNetbuilder.getProviderNetwork()
636                 .getLogicalSwitchId(), faasTenantId, new Pair<>(LocationType.RouterType, LocationType.SwitchType),
637                     null, null)) {
638                 LOG.error("Failed to join Provider Public Logical Router to Logical Switch in a Logical Network");
639             }
640             LOG.debug("Attached Provider Public Router {} to Provider Switch {}", provLR.getUuid().getValue(),
641                     lNetbuilder.getProviderNetwork().getLogicalSwitchId().getValue());
642         }
643
644         lNetbuilder.setContractId(contractId);
645         lNetbuilder.setContractTenantId(gbpTenantId);
646         LogicalNetwork result = lNetbuilder.build();
647         WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
648         InstanceIdentifier<LogicalNetwork> iid = FaasIidFactory.logicalNetworkIid(
649                 consEpg.getId(), gbpTenantId, contractId, provEpg.getId(), gbpTenantId);
650         wTx.put(LogicalDatastoreType.OPERATIONAL, iid, result);
651         if (DataStoreHelper.submitToDs(wTx)) {
652             LOG.debug("Cached in Datastore Mapped Logical Network {}", result);
653         } else {
654             LOG.error("Couldn't Cache in Datastore Mapped Logical Network {}", result);
655         }
656         LOG.debug("Created Layer 2 Logical network consEpg {}, contractId {}, provEpg {}", consEpg.getId().getValue(),
657                 contractId.getValue(), provEpg.getId().getValue());
658     }
659
660     private LogicalNetworkBuilder buildLayer2LogicalNetwork(EndpointGroup consEpg, EndpointGroup provEpg,
661             TenantId gbpTenantId, Uuid layer2SecRulesId, ExternalImplicitGroup externalImplicitGroup) {
662         LOG.trace("Start buildLayer2LogicalNetwork: Consumer EPG {}   Provider Epg {}", consEpg.getId().getValue(),
663                 provEpg.getId().getValue());
664         List<SubnetId> consSubnetIds = cloneAndGetEpgSubnets(consEpg.getId(), gbpTenantId);
665         List<Uuid> consFaasSubnetIds = new ArrayList<>();
666         for (SubnetId subnetId : consSubnetIds) {
667             Uuid id = getFaasSubnetId(subnetId, gbpTenantId);
668             if (id != null) {
669                 LOG.trace("Added to Consumer Network Faas Subnet {}", id.getValue());
670                 consFaasSubnetIds.add(id);
671             }
672         }
673         if (consFaasSubnetIds.isEmpty()) {
674             LOG.error("Couldn't find Faas subnets based on EPG {} -- Unable to create Layer2 Logical Network",
675                     consEpg.getId().getValue());
676             return null;
677         }
678         List<SubnetId> provSubnetIds = cloneAndGetEpgSubnets(provEpg.getId(), gbpTenantId);
679         List<Uuid> provFaasSubnetIds = new ArrayList<>();
680         for (SubnetId subnetId : provSubnetIds) {
681             Uuid id = getFaasSubnetId(subnetId, gbpTenantId);
682             if (id != null) {
683                 LOG.trace("Added to Provider Network Faas Subnet {}", id.getValue());
684                 provFaasSubnetIds.add(id);
685             }
686         }
687         if (provFaasSubnetIds.isEmpty()) {
688             LOG.error("Couldn't find Faas subnets based on EPG {} -- Unable to create Layer2 Logical Network",
689                     provEpg.getId().getValue());
690             return null;
691         }
692         Uuid faasTenantId = getFaasTenantId(gbpTenantId);
693         LogicalSwitchBuilder consLS = initLogicalSwitchBuilder(consEpg, faasTenantId);
694         LogicalSwitchBuilder provLS = initLogicalSwitchBuilder(provEpg, faasTenantId);
695         if (layer2SecRulesId != null) {
696             if (!UlnDatastoreApi.attachAndSubmitToDs(consLS, provLS, new Pair<Uuid, Uuid>(null, layer2SecRulesId))) {
697                 LOG.error("Failed to join Logical Switches in a Logical Network");
698                 return null;
699             }
700         } else {
701             UlnDatastoreApi.submitLogicalSwitchToDs(consLS.build());
702             UlnDatastoreApi.submitLogicalSwitchToDs(provLS.build());
703         }
704         for (Uuid subnetId : consFaasSubnetIds) {
705             if (!UlnDatastoreApi.attachAndSubmitToDs(consLS.getUuid(), subnetId, consLS.getTenantId(), new Pair<>(
706                     LocationType.SwitchType, LocationType.SubnetType))) {
707                 LOG.error("Failed to join Consumer Logical Switch with Subnet {} in a Logical Network", subnetId);
708                 return null;
709             }
710             LOG.debug("Attached Consumer Switch {} to Subnet {}", consLS.getUuid().getValue(), subnetId.getValue());
711         }
712         for (Uuid subnetId : provFaasSubnetIds) {
713             if (!UlnDatastoreApi.attachAndSubmitToDs(provLS.getUuid(), subnetId, provLS.getTenantId(), new Pair<>(
714                     LocationType.SwitchType, LocationType.SubnetType))) {
715                 LOG.error("Failed to join Provider Logical Switch with Subnet {} in a Logical Network", subnetId);
716                 return null;
717             }
718             LOG.debug("Attached Provider Switch {} to Subnet {}", provLS.getUuid().getValue(), subnetId.getValue());
719         }
720         LogicalNetworkBuilder lNetbuilder = new LogicalNetworkBuilder();
721         lNetbuilder.setConsumerEpgId(consEpg.getId());
722         lNetbuilder.setConsumerTenantId(gbpTenantId);
723         lNetbuilder.setContractTenantId(gbpTenantId);
724         lNetbuilder.setProviderEpgId(provEpg.getId());
725         lNetbuilder.setProviderTenantId(gbpTenantId);
726         ConsumerNetworkBuilder cNetBuilder = new ConsumerNetworkBuilder();
727         cNetBuilder.setLogicalSwitchId(consLS.getUuid());
728         cNetBuilder.setGbpSubnetId(consSubnetIds);
729         if (isConsumerPublic(externalImplicitGroup)) {
730             cNetBuilder.setNetworkScopeType(ScopeType.Public);
731         } else {
732             cNetBuilder.setNetworkScopeType(ScopeType.Private);
733         }
734         lNetbuilder.setConsumerNetwork(cNetBuilder.build());
735         ProviderNetworkBuilder pNetBuilder = new ProviderNetworkBuilder();
736         pNetBuilder.setLogicalSwitchId(provLS.getUuid());
737         pNetBuilder.setGbpSubnetId(provSubnetIds);
738         if (isProviderPublic(externalImplicitGroup)) {
739             pNetBuilder.setNetworkScopeType(ScopeType.Public);
740         } else {
741             pNetBuilder.setNetworkScopeType(ScopeType.Private);
742         }
743         lNetbuilder.setProviderNetwork(pNetBuilder.build());
744
745         return lNetbuilder;
746
747     }
748
749     private Uuid getFaasSubnetId(SubnetId subnetId, TenantId gbpTenantId) {
750         if (subnetId != null) {
751             Optional<MappedSubnet> mSubnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
752                     FaasIidFactory.mappedSubnetIid(gbpTenantId, subnetId),
753                     dataProvider.newReadOnlyTransaction());
754             if (mSubnetOp.isPresent()) {
755                 return mSubnetOp.get().getFaasSubnetId();
756             }
757         }
758         return null;
759     }
760
761     protected Uuid getFaasSecRulesId(ContractId contractId, TenantId gbpTenantId) {
762         if (contractId != null) {
763             Optional<MappedContract> mContractOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
764                     FaasIidFactory.mappedContractIid(gbpTenantId, contractId),
765                     dataProvider.newReadOnlyTransaction());
766             if (mContractOp.isPresent()) {
767                 return mContractOp.get().getFaasSecurityRulesId();
768             }
769         }
770         return null;
771     }
772
773     private LogicalRouterBuilder initLogicalRouterBuilder(EndpointGroup epg, Uuid tenantId, boolean isPublic) {
774         LogicalRouterBuilder builder = new LogicalRouterBuilder();
775         builder.setAdminStateUp(true);
776         builder.setName(new Text(epg.getId().getValue()));
777         if (epg.getDescription() != null) {
778             builder.setDescription(new Text("gbp-epg: " + epg.getDescription().getValue()));
779         } else {
780             builder.setDescription(new Text("gbp-epg"));
781         }
782         builder.setPublic(isPublic);
783         builder.setTenantId(tenantId);
784         builder.setUuid(new Uuid(UUID.randomUUID().toString()));
785         return builder;
786     }
787
788     private LogicalSwitchBuilder initLogicalSwitchBuilder(EndpointGroup epg, Uuid tenantId) {
789         LogicalSwitchBuilder builder = new LogicalSwitchBuilder();
790         builder.setAdminStateUp(true);
791         builder.setName(new Text(epg.getId().getValue()));
792         if (epg.getDescription() != null) {
793             builder.setDescription(new Text("gbp-epg: " + epg.getDescription().getValue()));
794         } else {
795             builder.setDescription(new Text("gbp-epg"));
796         }
797         builder.setTenantId(tenantId);
798         builder.setUuid(new Uuid(UUID.randomUUID().toString()));
799         return builder;
800     }
801
802     @VisibleForTesting
803     boolean needToCreateLogicalNetwork(ServiceCommunicationLayer comLayer, List<SubnetId> consSubnetIds,
804             List<SubnetId> provSubnetIds, TenantId tenantId, ContractId contractId, EndpointGroup providerEpg,
805             EndpointGroup consumerEpg, ExternalImplicitGroup externalImplicitGroup) {
806         Optional<LogicalNetwork> lnOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
807                 FaasIidFactory.logicalNetworkIid(consumerEpg.getId(), tenantId, contractId,
808                         providerEpg.getId(), tenantId), dataProvider.newReadOnlyTransaction());
809         if (!lnOp.isPresent()) {
810             return true;
811         }
812         LogicalNetwork logicalNet = lnOp.get();
813         if (!comLayer.equals(logicalNet.getCommunicationLayer())) {
814             return true;
815         }
816
817         boolean isConsPublic = logicalNet.getConsumerNetwork().getNetworkScopeType() != null
818                 && logicalNet.getConsumerNetwork().getNetworkScopeType() == ScopeType.Public;
819         if (isConsumerPublic(externalImplicitGroup) != isConsPublic) {
820             return true;
821         }
822         boolean isProvPublic = logicalNet.getProviderNetwork().getNetworkScopeType() != null
823                 && logicalNet.getProviderNetwork().getNetworkScopeType() == ScopeType.Public;
824         if (isProviderPublic(externalImplicitGroup) != isProvPublic) {
825             return true;
826         }
827         Set<SubnetId> lnConsSubnets = new HashSet<>(logicalNet.getConsumerNetwork().getGbpSubnetId());
828         if (lnConsSubnets.size() != consSubnetIds.size() || !lnConsSubnets.containsAll(consSubnetIds)) {
829             return true;
830         }
831         Set<SubnetId> lnProvSubnets = new HashSet<>(logicalNet.getProviderNetwork().getGbpSubnetId());
832         return lnProvSubnets.size() != provSubnetIds.size() || !lnProvSubnets.containsAll(
833                 provSubnetIds);
834     }
835
836     private ServiceCommunicationLayer findLayerNetwork(TenantId tenantId, List<SubnetId> consSubnetIds,
837             List<SubnetId> provSubnetIds) {
838         Subnet consSubnet = null;
839         Subnet provSubnet = null;
840         ContextId contextId = null;
841         for (SubnetId subnetId : consSubnetIds) {
842             consSubnet = readSubnet(subnetId, tenantId);
843             if (consSubnet == null) {
844                 LOG.error("Couldn't find subnet {} in datastore", subnetId);
845                 return null;
846             }
847             if (consSubnet.getParent() == null) {
848                 LOG.error("Flood domain is set to NULL in subnet " + consSubnet.getId());
849                 return null;
850             }
851             if (contextId == null) {
852                 contextId = consSubnet.getParent();
853             } else if (!contextId.equals(consSubnet.getParent())) {
854                 LOG.error("Flood domain is not the same for all Network domains in the Consumer EPG ");
855                 return null;
856             }
857         }
858
859         contextId = null;
860         for (SubnetId subnetId : provSubnetIds) {
861             provSubnet = readSubnet(subnetId, tenantId);
862             if (provSubnet == null) {
863                 LOG.error("Couldn't find subnet {} in datastore", subnetId);
864                 return null;
865             }
866             if (provSubnet.getParent() == null) {
867                 LOG.error("Flood domain is set to NULL in subnet " + provSubnet.getId());
868                 return null;
869             }
870             if (contextId == null) {
871                 contextId = provSubnet.getParent();
872             } else if (!contextId.equals(provSubnet.getParent())) {
873                 LOG.error("Flood domain is not the same for all Network domains in the Provider EPG ");
874                 return null;
875             }
876         }
877
878         if (consSubnet == null || provSubnet == null) {
879             LOG.error("Couldn't find Consumer and/or Provider subnets");
880             return null;
881         }
882
883         L2FloodDomainId consL2FldId = new L2FloodDomainId(consSubnet.getParent().getValue());
884         L2FloodDomain consFloodDomain = readL2FloodDomain(consL2FldId, tenantId);
885         if (consFloodDomain == null) {
886             LOG.error("Couldn't find flood domain instance in datastore with id " + consL2FldId);
887             return null;
888         }
889         L2FloodDomainId provL2FldId = new L2FloodDomainId(provSubnet.getParent().getValue());
890         L2FloodDomain provFloodDomain = readL2FloodDomain(provL2FldId, tenantId);
891         if (provFloodDomain == null) {
892             LOG.error("Couldn't find flood domain instance in datastore with id " + provL2FldId);
893             return null;
894         }
895
896         if (consFloodDomain.equals(provFloodDomain)) {
897             return ServiceCommunicationLayer.Layer2;
898         }
899
900         if (consFloodDomain.getParent() == null) {
901             LOG.error("Bridge domain is set to NULL in flood domain " + consFloodDomain.getId());
902             return null;
903         }
904         if (provFloodDomain.getParent() == null) {
905             LOG.error("Bridge domain is set to NULL in flood domain " + provFloodDomain.getId());
906             return null;
907         }
908
909         L2BridgeDomain consBridgeDomain = readL2BridgeDomainInstance(tenantId, consFloodDomain.getParent());
910         if (consBridgeDomain == null) {
911             LOG.error("Couldn't find bridge domain instance in datastore with id " + consFloodDomain.getParent());
912             return null;
913         }
914         L2BridgeDomain provBridgeDomain = readL2BridgeDomainInstance(tenantId, provFloodDomain.getParent());
915         if (provBridgeDomain == null) {
916             LOG.error("Couldn't find bridge domain instance in datastore with id " + provFloodDomain.getParent());
917             return null;
918         }
919         if (consBridgeDomain.equals(provBridgeDomain)) {
920             return ServiceCommunicationLayer.Layer2;
921         }
922
923         L3Context consL3ContextDomain = readL3ContextInstance(tenantId, consBridgeDomain.getParent());
924         if (consL3ContextDomain == null) {
925             LOG.error("Couldn't find L3 context instance in datastore with id " + consBridgeDomain.getParent());
926             return null;
927         }
928         L3Context provL3ContextDomain = readL3ContextInstance(tenantId, provBridgeDomain.getParent());
929         if (provL3ContextDomain == null) {
930             LOG.error("Couldn't find L3 context instance in datastore with id " + provBridgeDomain.getParent());
931             return null;
932         }
933         if (consL3ContextDomain.equals(provL3ContextDomain)) {
934             return ServiceCommunicationLayer.Layer3;
935         }
936         return null;
937     }
938
939     @VisibleForTesting
940     L3Context readL3ContextInstance(TenantId tenantId, L3ContextId l3cId) {
941         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
942         InstanceIdentifier<L3Context> iid = IidFactory.l3ContextIid(tenantId, l3cId);
943         Optional<L3Context> l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
944         if (!l2Op.isPresent()) {
945             LOG.error("Couldn't find L3 Context Domain {} which belongs to Tenant {}", l3cId, tenantId);
946             rTx.close();
947             return null;
948         }
949         return l2Op.get();
950     }
951
952     @VisibleForTesting
953     L2BridgeDomain readL2BridgeDomainInstance(TenantId tenantId, L2BridgeDomainId l2bId) {
954         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
955         InstanceIdentifier<L2BridgeDomain> iid = IidFactory.l2BridgeDomainIid(tenantId, l2bId);
956         Optional<L2BridgeDomain> l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
957         if (!l2Op.isPresent()) {
958             LOG.error("Couldn't find L2 Brdge Domain {} which belongs to Tenant {}", l2bId, tenantId);
959             rTx.close();
960             return null;
961         }
962         return l2Op.get();
963     }
964
965     @VisibleForTesting
966     L2FloodDomain readL2FloodDomain(L2FloodDomainId l2fId, TenantId tenantId) {
967         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
968         InstanceIdentifier<L2FloodDomain> iid = IidFactory.l2FloodDomainIid(tenantId, l2fId);
969         Optional<L2FloodDomain> l2Op = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
970         if (!l2Op.isPresent()) {
971             LOG.error("Couldn't find L2 Flood Domain {} which belongs to Tenant {}", l2fId, tenantId);
972             rTx.close();
973             return null;
974         }
975         return l2Op.get();
976     }
977
978     public Subnet readSubnet(SubnetId subnetId, TenantId tenantId) {
979         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
980         InstanceIdentifier<Subnet> iid = IidFactory.subnetIid(tenantId, subnetId);
981         Optional<Subnet> subnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
982         if (!subnetOp.isPresent()) {
983             LOG.warn("Couldn't find Subnet {} which belongs to Tenant {}", subnetId, tenantId);
984             rTx.close();
985             return null;
986         }
987         return subnetOp.get();
988     }
989
990     public EndpointGroup readEndpointGroup(EndpointGroupId epgId, TenantId tenantId) {
991         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
992         InstanceIdentifier<EndpointGroup> iid = IidFactory.endpointGroupIid(tenantId, epgId);
993         Optional<EndpointGroup> epgOp = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
994         if (!epgOp.isPresent()) {
995             LOG.warn("Couldn't find EPG {} which belongs to Tenant {}", epgId, tenantId);
996             rTx.close();
997             return null;
998         }
999         return epgOp.get();
1000     }
1001
1002     private ContractId getContractId(ResolvedPolicy policy) {
1003         for (PolicyRuleGroupWithEndpointConstraints prgwec : policy.getPolicyRuleGroupWithEndpointConstraints()) {
1004             for (PolicyRuleGroup prg : prgwec.getPolicyRuleGroup()) {
1005                 return prg.getContractId();
1006             }
1007         }
1008         return null;
1009     }
1010
1011     public void removeTenantLogicalNetwork(TenantId gbpTenantId, Uuid faasTenantId) {
1012         removeTenantLogicalNetwork(gbpTenantId, faasTenantId, true);
1013     }
1014
1015     @VisibleForTesting
1016     void removeTenantLogicalNetwork(TenantId gbpTenantId, Uuid faasTenantId, boolean unregister) {
1017         UlnDatastoreApi.removeTenantFromDsIfExists(faasTenantId);
1018         synchronized (this) {
1019             mappedTenants.remove(gbpTenantId);
1020             Optional<LogicalNetworks> op3 = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
1021                     FaasIidFactory.logicalNetworksIid(), dataProvider.newReadOnlyTransaction());
1022             if (op3.isPresent()) {
1023                 LogicalNetworks logicalNetworks = op3.get();
1024                 for (LogicalNetwork ln : logicalNetworks.getLogicalNetwork()) {
1025                     if (ln.getConsumerTenantId().equals(gbpTenantId) || ln.getProviderTenantId().equals(gbpTenantId)) {
1026                         removeLogicalNetwork(ln.getConsumerEpgId(), ln.getConsumerTenantId(), ln.getContractId(),
1027                                 ln.getProviderEpgId(), ln.getProviderTenantId());
1028                     }
1029                 }
1030             }
1031             boolean toSubmit = false;
1032             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
1033             Optional<MappedEntity> op1 = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
1034                     FaasIidFactory.mappedEntityIid(gbpTenantId), rwTx);
1035             if (op1.isPresent()) {
1036                 toSubmit = true;
1037             }
1038             Optional<MappedTenant> op2 = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
1039                     FaasIidFactory.mappedTenantIid(gbpTenantId), rwTx);
1040             if (op2.isPresent()) {
1041                 toSubmit = true;
1042             }
1043             if (toSubmit) {
1044                 DataStoreHelper.submitToDs(rwTx);
1045             }
1046
1047             if (unregister) {
1048                 unregisterTenant(gbpTenantId);
1049             }
1050         }
1051     }
1052 }