6162c540ee3bbb6b05000c22a30788bf0f5ad0de
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / endpoint / EndpointManager.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint;
10
11 import static org.opendaylight.groupbasedpolicy.util.DataStoreHelper.readFromDs;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
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.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentMap;
23 import java.util.concurrent.CopyOnWriteArrayList;
24 import java.util.concurrent.ScheduledExecutorService;
25
26 import javax.annotation.Nullable;
27
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
30 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
34 import org.opendaylight.groupbasedpolicy.dto.EgKey;
35 import org.opendaylight.groupbasedpolicy.dto.EpKey;
36 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
37 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointListener;
38 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.arp.ArpTasker;
39 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
40 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
41 import org.opendaylight.groupbasedpolicy.util.IidFactory;
42 import org.opendaylight.groupbasedpolicy.util.SetUtils;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointFields;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
67 import org.opendaylight.yangtools.concepts.ListenerRegistration;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 import com.google.common.base.Function;
72 import com.google.common.base.Optional;
73 import com.google.common.base.Preconditions;
74 import com.google.common.base.Predicate;
75 import com.google.common.collect.Collections2;
76 import com.google.common.collect.ImmutableList;
77 import com.google.common.collect.ImmutableSet;
78 import com.google.common.collect.Sets;
79
80 /**
81  * Keep track of endpoints on the system. Maintain an index of endpoints and
82  * their locations for rendering. The endpoint manager will maintain
83  * appropriate indexes only for switches that are attached to the current
84  * controller node.
85  * In order to render the policy, we need to be able to efficiently enumerate
86  * all endpoints on a particular switch and also all the switches containing
87  * each particular endpoint group
88  */
89 public class EndpointManager implements AutoCloseable {
90
91     private static final Logger LOG = LoggerFactory.getLogger(EndpointManager.class);
92     private final EndpointManagerListener endpointListener;
93     private final OfOverlayContextListener ofOverlayContextListener;
94     private final OfOverlayL3ContextListener ofOverlayL3ContextListener;
95     private final ConcurrentMap<EpKey, Endpoint> endpoints = new ConcurrentHashMap<>();
96     private final ConcurrentMap<EpKey, Endpoint> externalEndpointsWithoutLocation = new ConcurrentHashMap<>();
97     private final ConcurrentMap<NodeId, ConcurrentMap<EgKey, Set<EpKey>>> endpointsByGroupByNode =
98             new ConcurrentHashMap<>();
99     private final ConcurrentMap<NodeId, Set<EpKey>> endpointsByNode = new ConcurrentHashMap<>();
100     private final ConcurrentMap<EgKey, Set<EpKey>> endpointsByGroup = new ConcurrentHashMap<>();
101     private final ScheduledExecutorService executor;
102     private final DataBroker dataProvider;
103     private final ArpTasker arpTasker;
104     private final ListenerRegistration<ArpTasker> notificationListenerRegistration;
105     private List<EndpointListener> listeners = new CopyOnWriteArrayList<>();
106     private Function<EpKey, Endpoint> indexTransform = new Function<EpKey, Endpoint>() {
107
108         @Override
109         public Endpoint apply(EpKey input) {
110             return endpoints.get(input);
111         }
112     };
113
114     public EndpointManager(DataBroker dataProvider, RpcProviderRegistry rpcRegistry,
115             NotificationService notificationService, ScheduledExecutorService executor, SwitchManager switchManager) {
116         this.executor = executor;
117         this.dataProvider = dataProvider;
118         if (rpcRegistry != null) {
119             if (notificationService != null && dataProvider != null) {
120                 this.arpTasker = new ArpTasker(rpcRegistry, dataProvider);
121                 notificationListenerRegistration = notificationService.registerNotificationListener(arpTasker);
122             } else {
123                 LOG.info("Missing service {}", NotificationService.class.getSimpleName());
124                 this.arpTasker = null;
125                 this.notificationListenerRegistration = null;
126             }
127         } else {
128             LOG.warn("Missing service {}", RpcProviderRegistry.class.getSimpleName());
129             this.arpTasker = null;
130             this.notificationListenerRegistration = null;
131         }
132         if (dataProvider != null) {
133             endpointListener = new EndpointManagerListener(this.dataProvider, this);
134             ofOverlayContextListener = new OfOverlayContextListener(dataProvider, switchManager);
135             ofOverlayL3ContextListener = new OfOverlayL3ContextListener(dataProvider, switchManager);
136         } else {
137             endpointListener = null;
138             ofOverlayContextListener = null;
139             ofOverlayL3ContextListener = null;
140         }
141         LOG.debug("Initialized OFOverlay endpoint manager");
142     }
143
144     /**
145      * Add a {@link EndpointListener} to get notifications of switch events
146      *
147      * @param listener - the {@link EndpointListener} to add
148      */
149     public void registerListener(EndpointListener listener) {
150         listeners.add(listener);
151     }
152
153     /**
154      * Get a collection of endpoints attached to a particular switch
155      *
156      * @param nodeId - the nodeId of the switch to get endpoints for
157      * @return a collection of {@link Endpoint} objects.
158      */
159     public synchronized Set<EgKey> getGroupsForNode(NodeId nodeId) {
160         Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
161         if (nodeEps == null)
162             return Collections.emptySet();
163         return ImmutableSet.copyOf(nodeEps.keySet());
164     }
165
166     /**
167      * Get the set of nodes
168      *
169      * @param egKey - the egKey of the endpoint group to get nodes for
170      * @return a collection of {@link NodeId} objects.
171      */
172     public synchronized Set<NodeId> getNodesForGroup(final EgKey egKey) {
173         return ImmutableSet.copyOf(Sets.filter(endpointsByGroupByNode.keySet(), new Predicate<NodeId>() {
174
175             @Override
176             public boolean apply(NodeId input) {
177                 Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(input);
178                 return (nodeEps != null && nodeEps.containsKey(egKey));
179             }
180
181         }));
182     }
183
184     /**
185      * Get the endpoints in a particular group on a particular node
186      *
187      * @param nodeId - the node ID to look up
188      * @param eg - the group to look up
189      * @return the endpoints
190      */
191     public synchronized Collection<Endpoint> getEndpointsForNode(NodeId nodeId, EgKey eg) {
192         // TODO: alagalah Create method findEndpointsByNode() that uses
193         // data store
194
195         Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
196         if (nodeEps == null)
197             return Collections.emptyList();
198         Collection<EpKey> ebn = nodeEps.get(eg);
199         if (ebn == null)
200             return Collections.emptyList();
201         return ImmutableList.copyOf(Collections2.transform(ebn, indexTransform));
202     }
203
204     /**
205      * Get the endpoints on a particular node
206      *
207      * @param nodeId - the node ID to look up
208      * @return the endpoints
209      */
210     public synchronized Collection<Endpoint> getEndpointsForNode(final NodeId nodeId) {
211         // TODO: alagalah Create method findEndpointsByNode() that uses
212         // data store. See commented code below.
213
214         Collection<EpKey> ebn = endpointsByNode.get(nodeId);
215         if (ebn == null)
216             return Collections.emptyList();
217         return ImmutableList.copyOf(Collections2.transform(ebn, indexTransform));
218     }
219
220     /**
221      * Get the endpoint object for the given key
222      *
223      * @param epKey - the key
224      * @return the {@link Endpoint} corresponding to the key
225      */
226     public Endpoint getEndpoint(EpKey epKey) {
227         return endpoints.get(epKey);
228     }
229
230     /**
231      * Get a collection of endpoints in a particular endpoint group
232      *
233      * @param eg - Endpoint group key (contains endpoint group and tenant ID)
234      * @return a collection of {@link Endpoint} objects.
235      */
236     public synchronized Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
237         Collection<EpKey> ebg = endpointsByGroup.get(eg);
238         if (ebg == null)
239             return Collections.emptyList();
240         return ImmutableList.copyOf(Collections2.transform(ebg, indexTransform));
241     }
242
243     /**
244      * Return set of external endpoints without location belonging to a particular endpoint group
245      *
246      * @param eg - Endpoint group key (contains endpoint group and tenant ID)
247      * @return a collection of {@link Endpoint} objects.
248      */
249     public synchronized Collection<Endpoint> getExtEpsNoLocForGroup(final EgKey eg) {
250
251         return ImmutableSet
252             .copyOf(Collections2.filter(externalEndpointsWithoutLocation.values(), new Predicate<Endpoint>() {
253
254                 @Override
255                 public boolean apply(Endpoint input) {
256                     Set<EndpointGroupId> epgIds = new HashSet<>();
257                     if (input.getEndpointGroup() != null) {
258                         epgIds.add(input.getEndpointGroup());
259                     }
260                     if (input.getEndpointGroups() != null) {
261                         epgIds.addAll(input.getEndpointGroups());
262                     }
263                     if (epgIds.isEmpty()) {
264                         LOG.error("No EPGs for {}. This is not a valid Endpoint.", input.getKey());
265                         return false;
266                     }
267                     return (epgIds.contains(eg.getEgId()));
268                 }
269
270             }));
271     }
272
273     /**
274      * Character of input parameters will determine action - create, update or delete L3Endpoint
275      *
276      * @param oldL3Ep the old L3 endpoint
277      * @param newL3Ep the new L3 endpoint
278      */
279     protected synchronized void processL3Endpoint(EndpointL3 oldL3Ep, EndpointL3 newL3Ep) {
280         // TODO Bug 3543
281         // create L3 endpoint
282         if (oldL3Ep == null && newL3Ep != null) {
283             createL3Endpoint(newL3Ep);
284         }
285
286         // update L3 endpoint
287         if (oldL3Ep != null && newL3Ep != null) {
288             updateL3Endpoint(newL3Ep);
289         }
290
291         // remove L3 endpoint
292         if (oldL3Ep != null && newL3Ep == null) {
293             removeL3Endpoint(oldL3Ep);
294         }
295     }
296
297     /**
298      * Character of input parameters will determine action - create, update or delete Endpoint
299      *
300      * @param oldEp - oldEp the new endpoint
301      * @param newEp - newEp the new endpoint
302      */
303     protected synchronized void processEndpoint(Endpoint oldEp, Endpoint newEp) {
304         NodeId oldLoc = getLocation(oldEp);
305         NodeId newLoc = getLocation(newEp);
306         EpKey oldEpKey = getEpKey(oldEp);
307         EpKey newEpKey = getEpKey(newEp);
308         TenantId tenantId = (newEp == null) ? null : newEp.getTenant();
309
310         Set<EndpointGroupId> oldEpgIds = getEndpointGroupsFromEndpoint(oldEp);
311         Set<EndpointGroupId> newEpgIds = getEndpointGroupsFromEndpoint(newEp);
312
313         boolean notifyOldLoc = false;
314         boolean notifyNewLoc = false;
315         boolean notifyOldEg = false;
316         boolean notifyNewEg = false;
317
318         // create endpoint
319         if (oldEp == null && newEp != null) {
320             if (newLoc != null) {
321                 createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
322                 endpoints.put(newEpKey, newEp);
323                 notifyEndpointUpdated(newEpKey);
324                 notifyNewLoc = true;
325                 notifyNewEg = true;
326             } else {
327                 externalEndpointsWithoutLocation.put(newEpKey, newEp);
328             }
329         }
330
331         // update endpoint
332         else if (oldEp != null && newEp != null && oldEpKey != null && newEpKey != null) {
333             // endpoint is not external anymore
334             if (newLoc != null && oldLoc == null) {
335                 createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
336                 externalEndpointsWithoutLocation.remove(oldEpKey);
337                 endpoints.put(newEpKey, newEp);
338                 notifyEndpointUpdated(newEpKey);
339                 notifyNewLoc = true;
340                 notifyNewEg = true;
341             }
342             // endpoint changed to external
343             else if (newLoc == null && oldLoc != null) {
344                 removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
345                 externalEndpointsWithoutLocation.put(newEpKey, newEp);
346                 endpoints.remove(oldEpKey);
347                 notifyEndpointUpdated(oldEpKey);
348                 notifyOldLoc = true;
349                 notifyOldEg = true;
350             // endpoint might have changed location, EPGs or it's properties
351             } else if (newLoc != null && oldLoc != null) {
352                     // endpoit changed location
353                     if (!(oldLoc.getValue().equals(newLoc.getValue()))) {
354                         notifyOldLoc = true;
355                         notifyNewLoc = true;
356                     }
357                     // endpoint changed EPGs
358                     if (!oldEpgIds.equals(newEpgIds)) {
359                         notifyOldEg = true;
360                         notifyNewEg = true;
361                     }
362                     removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
363                     createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
364                     notifyEndpointUpdated(newEpKey);
365             }
366         }
367
368         // remove endpoint
369         else if (oldEp != null && newEp == null) {
370             if (oldLoc != null) {
371                 removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
372                 endpoints.remove(oldEpKey);
373                 notifyEndpointUpdated(oldEpKey);
374                 notifyOldLoc = true;
375                 notifyOldEg = true;
376             } else {
377                 externalEndpointsWithoutLocation.remove(oldEpKey);
378             }
379         }
380
381         // notifications
382         if (notifyOldLoc)
383             notifyNodeEndpointUpdated(oldLoc, oldEpKey);
384         if (notifyNewLoc)
385             notifyNodeEndpointUpdated(newLoc, newEpKey);
386         if (notifyOldEg)
387             for (EndpointGroupId oldEpgId : oldEpgIds) {
388                 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
389                 notifyGroupEndpointUpdated(oldEgKey, oldEpKey);
390             }
391         if (notifyNewEg)
392             for (EndpointGroupId newEpgId : newEpgIds) {
393                 EgKey newEgKey = new EgKey(newEp.getTenant(), newEpgId);
394                 notifyGroupEndpointUpdated(newEgKey, newEpKey);
395             }
396     }
397
398     private void createEndpoint(NodeId newLoc, EpKey newEpKey, Set<EndpointGroupId> newEpgIds, TenantId tenantId) {
399         // Update endpointsByNode
400         if (endpointsByNode.get(newLoc) == null) {
401             Set<EpKey> epsNode = new HashSet<>();
402             epsNode.add(newEpKey);
403             endpointsByNode.put(newLoc, epsNode);
404             SwitchManager.activatingSwitch(newLoc);
405         } else {
406             Set<EpKey> epsNode = endpointsByNode.get(newLoc);
407             epsNode.add(newEpKey);
408         }
409
410         // Update endpointsByGroupByNode and endpointsByGroup
411         for (EndpointGroupId newEpgId : newEpgIds) {
412             // endpointsByGroupByNode
413             EgKey newEgKey = new EgKey(tenantId, newEpgId);
414             Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
415             eps.add(newEpKey);
416             // endpointsByGroup
417             Set<EpKey> geps = endpointsByGroup.get(newEgKey);
418             if (geps == null) {
419                 geps = new HashSet<>();
420             }
421             geps.add(newEpKey);
422             endpointsByGroup.put(newEgKey, geps);
423             LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
424
425         }
426     }
427
428     private void removeEndpoint(Endpoint oldEp, NodeId oldLoc, EpKey oldEpKey, Set<EndpointGroupId> oldEpgIds) {
429         // Update endpointsByNode
430         Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
431         if (epsNode != null) {
432             epsNode.remove(oldEpKey);
433             if (epsNode.isEmpty()) {
434                 endpointsByNode.remove(oldLoc);
435                 SwitchManager.deactivatingSwitch(oldLoc);
436             }
437         }
438
439         // Update endpointsByGroupByNode and endpointsByGroup, get map of EPGs and their Endpoints
440         // for Node
441         ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(oldLoc);
442         for (EndpointGroupId oldEpgId : oldEpgIds) {
443             // endpointsByGroupByNode
444             EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
445             Set<EpKey> eps = map.get(oldEgKey);
446             if (eps != null) {
447                 eps.remove(oldEpKey);
448                 if (eps.isEmpty())
449                     map.remove(oldEgKey, Collections.emptySet());
450             }
451             // endpointsByGroup
452             Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
453             if (geps != null) {
454                 geps.remove(oldEpKey);
455                 if (geps.isEmpty())
456                     endpointsByGroup.remove(oldEgKey);
457             }
458         }
459
460         // If map is empty, no more EPGs on this node, remove node from map
461         if (map.isEmpty())
462             endpointsByGroupByNode.remove(oldLoc);
463
464     }
465
466     private void createL3Endpoint(EndpointL3 newL3Ep) {
467         LOG.trace("Processing L3Endpoint {}", newL3Ep.getKey());
468         if (isValidL3Ep(newL3Ep)) {
469             if (newL3Ep.getMacAddress() == null) {
470                 if (newL3Ep.getNetworkContainment() != null) {
471                     arpTasker.addMacForL3EpAndCreateEp(newL3Ep);
472                 } else {
473                     LOG.error("Cannot generate MacAddress for L3Endpoint {}. NetworkContainment is null.", newL3Ep);
474                     return;
475                 }
476             }
477             if (newL3Ep.getL2Context() != null && newL3Ep.getMacAddress() != null) {
478                 notifyEndpointUpdated(new EpKey(newL3Ep.getL2Context(), newL3Ep.getMacAddress()));
479                 return;
480             }
481         } else {
482             LOG.error("{} is not a valid L3 Endpoint", newL3Ep);
483             return;
484         }
485         if (newL3Ep.getAugmentation(OfOverlayL3Context.class) == null) {
486             LOG.info("L3Endpoint created but no augmentation information");
487         }
488     }
489
490     private void updateL3Endpoint(EndpointL3 newL3Ep) {
491         LOG.trace("Updating L3 Endpoint {}");
492         notifyEndpointUpdated(new EpKey(newL3Ep.getL2Context(), newL3Ep.getMacAddress()));
493         if (newL3Ep.getAugmentation(OfOverlayL3Context.class) == null) {
494             LOG.info("L3Endpoint updated but no augmentation information");
495         }
496     }
497
498     private void removeL3Endpoint(EndpointL3 oldL3Ep) {
499         LOG.trace("Removing L3 Endpoint {}");
500         notifyEndpointUpdated(new EpKey(oldL3Ep.getL2Context(), oldL3Ep.getMacAddress()));
501
502     }
503
504     // auto closeable
505     @Override
506     public void close() throws Exception {
507         if (endpointListener != null) {
508             endpointListener.close();
509         }
510         if (notificationListenerRegistration != null) {
511             notificationListenerRegistration.close();
512         }
513         if (ofOverlayContextListener != null) {
514             ofOverlayContextListener.close();
515         }
516         if (ofOverlayL3ContextListener != null) {
517             ofOverlayL3ContextListener.close();
518         }
519     }
520
521     private Set<EpKey> getEpNGSet(NodeId location, EgKey eg) {
522         ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(location);
523         if (map == null) {
524             map = new ConcurrentHashMap<>();
525             ConcurrentMap<EgKey, Set<EpKey>> old = endpointsByGroupByNode.putIfAbsent(location, map);
526             if (old != null)
527                 map = old;
528         }
529         return SetUtils.getNestedSet(eg, map);
530     }
531
532     /**
533      * An endpoint is external if its endpoint-group is external implicit group.
534      * 
535      * @param ep an endpoint
536      * @param eigs external implicit groups
537      * @return {@code true} if the given endpoint has EPG representing external implicit group;
538      *         {@code false} otherwise
539      * @throws NullPointerException if the given endpoint is {@code null}
540      * @throws IllegalArgumentException if the given endpoint does not contain any endpoint-group
541      */
542     public static boolean isExternal(Endpoint ep, @Nullable Collection<ExternalImplicitGroup> eigs) {
543         return !isInternal(ep, eigs);
544     }
545
546     /**
547      * An endpoint is internal if none of its endpoint-groups is external implicit group.
548      * 
549      * @param ep an endpoint
550      * @param eigs external implicit groups
551      * @return {@code true} if the given endpoint does not have EPG representing external implicit
552      *         group;
553      *         {@code false} otherwise
554      * @throws NullPointerException if the given endpoint is {@code null}
555      * @throws IllegalArgumentException if the given endpoint does not contain any endpoint-group
556      */
557     public static boolean isInternal(Endpoint ep, @Nullable Collection<ExternalImplicitGroup> eigs) {
558         Preconditions.checkNotNull(ep);
559         if (eigs == null || eigs.isEmpty()) {
560             return true;
561         }
562         Set<EndpointGroupId> epgs = getEpgs(ep);
563         Preconditions.checkArgument(!epgs.isEmpty());
564         for (EndpointGroupId epg : epgs) {
565             for (ExternalImplicitGroup eig : eigs) {
566                 if (epg.equals(eig.getId())) {
567                     return false;
568                 }
569             }
570         }
571         return true;
572     }
573
574     private static Set<EndpointGroupId> getEpgs(EndpointFields ep) {
575         EndpointGroupId epgId = ep.getEndpointGroup();
576         List<EndpointGroupId> epgsId = ep.getEndpointGroups();
577         Set<EndpointGroupId> result = new HashSet<>();
578         if (epgId != null) {
579             result.add(epgId);
580         }
581         if (epgsId != null) {
582             result.addAll(epgsId);
583         }
584         return result;
585     }
586
587     /**
588      * Get the endpoints container from data store.
589      * Note: There are maps maintained by listener when higher performance is required.
590      *
591      * @return the
592      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints}
593      */
594     protected Endpoints getEndpointsFromDataStore() {
595         /*
596          * XXX: alagalah I wanted to avoid adding another Map. Due to not being able to
597          * get to the granularity of the L3PrefixEndpoint List within the Endpoints container
598          * in the data store, we have to pull all the Endpoints. If this causes performance issues
599          * we may have to revisit a Map in updateEndpoint but note, this Endpoint doesn't have a
600          * location
601          * and hence we would have to process it outside the null location check.
602          */
603         if (dataProvider == null) {
604             LOG.error("Null DataProvider in EndpointManager getEndpointsL3Prefix");
605             return null;
606         }
607         ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
608         Optional<Endpoints> endpoints =
609                 DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointsIidWildcard(), rTx);
610         if (!endpoints.isPresent()) {
611             LOG.warn("No Endpoints present in data store.");
612             return null;
613         }
614         return endpoints.get();
615     }
616
617     /**
618      * Return all L3Endpoints from data store.
619      *
620      * @return the
621      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3}
622      * @return {@link Collection} of the {@link EndpointL3}.
623      *   Empty {@link Collection} if no {@link EndpointL3} is found.
624      */
625     protected Collection<EndpointL3> getL3Endpoints() {
626         Endpoints endpoints = getEndpointsFromDataStore();
627         if (endpoints == null || endpoints.getEndpointL3() == null) {
628             LOG.warn("No L3  Endpoints present in data store.");
629             return null;
630         }
631         return endpoints.getEndpointL3();
632     }
633
634     /**
635      * Return all L3Prefix Endpoints from data store.
636      *
637      * @return the
638      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix}
639      */
640     private Collection<EndpointL3Prefix> getEndpointsL3Prefix() {
641         Endpoints endpoints = getEndpointsFromDataStore();
642         if (endpoints == null || endpoints.getEndpointL3Prefix() == null) {
643             LOG.warn("No L3 Prefix Endpoints present in data store.");
644             return null;
645         }
646         return endpoints.getEndpointL3Prefix();
647     }
648
649     /**
650      * Return all L3Prefix Endpoints which come under particular tenant
651      *
652      * @param tenantId - the
653      *        {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId}
654      *        to resolve
655      * @return the
656      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix}
657      */
658     public Collection<EndpointL3Prefix> getEndpointsL3PrefixForTenant(final TenantId tenantId) {
659         Collection<EndpointL3Prefix> l3PrefixEndpoints = getEndpointsL3Prefix();
660         if (l3PrefixEndpoints == null) {
661             // Log message already generated in getEndpointsL3Prefix()
662             return null;
663         }
664         return ImmutableSet.copyOf(Collections2.filter(l3PrefixEndpoints, new Predicate<EndpointL3Prefix>() {
665
666             @Override
667             public boolean apply(EndpointL3Prefix input) {
668                 return (input.getTenant().equals(tenantId));
669             }
670
671         }));
672     }
673
674     /**
675      * Return all L3Endpoints containing network and port address translation in augmentation
676      *
677      * @return the
678      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3}
679      */
680     public Collection<EndpointL3> getL3EndpointsWithNat() {
681         Collection<EndpointL3> l3Endpoints = getL3Endpoints();
682         if (l3Endpoints == null) {
683             return null;
684         }
685         l3Endpoints = Collections2.filter(l3Endpoints, new Predicate<EndpointL3>() {
686
687             @Override
688             public boolean apply(EndpointL3 input) {
689                 return !((input.getAugmentation(NatAddress.class) == null)
690                         || (input.getAugmentation(NatAddress.class).getNatAddress() == null));
691             }
692         });
693         if (l3Endpoints == null) {
694             return Collections.emptySet();
695         }
696         return ImmutableSet.copyOf(l3Endpoints);
697     }
698
699     /**
700      * Set the learning mode to the specified value
701      *
702      * @param learningMode - the learning mode to set
703      */
704     @SuppressWarnings({"UnusedParameters", "EmptyMethod"})
705     public void setLearningMode(OfOverlayConfig.LearningMode learningMode) {
706         // No-op for now
707     }
708
709     /**
710      * Get the effective list of conditions that apply to a particular endpoint.
711      * This could include additional conditions over the condition labels
712      * directly represented in the endpoint object
713      * set
714      *
715      * @param endpoint - the
716      *        {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint}
717      *        to resolve
718      * @return the list of
719      *         {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName}
720      */
721     public List<ConditionName> getConditionsForEndpoint(Endpoint endpoint) {
722         // TODO Be alagalah From Helium: consider group conditions as well. Also
723         // need to notify
724         // endpoint updated if the endpoint group conditions change
725         if (endpoint.getCondition() != null)
726             return endpoint.getCondition();
727         else
728             return Collections.emptyList();
729     }
730
731     private void notifyEndpointUpdated(EpKey epKey) {
732         for (EndpointListener l : listeners) {
733             l.endpointUpdated(epKey);
734         }
735     }
736
737     private void notifyNodeEndpointUpdated(NodeId nodeId, EpKey epKey) {
738         for (EndpointListener l : listeners) {
739             l.nodeEndpointUpdated(nodeId, epKey);
740         }
741     }
742
743     private void notifyGroupEndpointUpdated(EgKey egKey, EpKey epKey) {
744         for (EndpointListener l : listeners) {
745             l.groupEndpointUpdated(egKey, epKey);
746         }
747     }
748
749     private boolean isValidEp(Endpoint endpoint) {
750         return (endpoint != null && endpoint.getTenant() != null
751                 && (endpoint.getEndpointGroup() != null || endpoint.getEndpointGroups() != null)
752                 && endpoint.getL2Context() != null && endpoint.getMacAddress() != null);
753     }
754
755     private boolean isValidL3Ep(EndpointL3 endpoint) {
756         return (endpoint != null && endpoint.getTenant() != null
757                 && (endpoint.getEndpointGroup() != null || endpoint.getEndpointGroups() != null)
758                 && endpoint.getL3Context() != null && endpoint.getIpAddress() != null);
759     }
760
761     private NodeId getLocation(Endpoint endpoint) {
762         if (isValidEp(endpoint)) {
763             OfOverlayContext context = endpoint.getAugmentation(OfOverlayContext.class);
764             if (context != null)
765                 return context.getNodeId();
766         }
767         return null;
768     }
769
770     private EpKey getEpKey(Endpoint endpoint) {
771         if (isValidEp(endpoint))
772             return new EpKey(endpoint.getL2Context(), endpoint.getMacAddress());
773         return null;
774     }
775
776     public Set<EgKey> getEgKeysForEndpoint(Endpoint ep) {
777         Set<EgKey> egKeys = new HashSet<>();
778
779         if (ep.getEndpointGroup() != null) {
780             egKeys.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
781         }
782         if (ep.getEndpointGroups() != null) {
783             for (EndpointGroupId epgId : ep.getEndpointGroups()) {
784                 egKeys.add(new EgKey(ep.getTenant(), epgId));
785             }
786         }
787         return egKeys;
788     }
789
790     private Set<EndpointGroupId> getEndpointGroupsFromEndpoint(Endpoint ep) {
791         if (ep == null)
792             return new HashSet<>();
793         Set<EndpointGroupId> epgIds = new HashSet<>();
794         if (ep.getEndpointGroups() != null) {
795             epgIds.addAll(ep.getEndpointGroups());
796         }
797         if (ep.getEndpointGroup() != null) {
798             epgIds.add(ep.getEndpointGroup());
799         }
800         return epgIds;
801     }
802
803     protected Map<EndpointKey, EndpointL3> getL3EpWithNatByL2Key() {
804         Map<EndpointKey, EndpointL3> l3EpByL2EpKey = new HashMap<>();
805
806         Collection<EndpointL3> l3Eps = getL3EndpointsWithNat();
807         if (l3Eps == null) {
808             l3EpByL2EpKey = Collections.emptyMap();
809             return l3EpByL2EpKey;
810         }
811         for (EndpointL3 l3Ep : l3Eps) {
812             if (l3Ep.getL2Context() != null && l3Ep.getMacAddress() != null) {
813                 EndpointKey epKey = new EndpointKey(l3Ep.getL2Context(), l3Ep.getMacAddress());
814                 l3EpByL2EpKey.put(epKey, l3Ep);
815             }
816         }
817         if (l3EpByL2EpKey.isEmpty()) {
818             l3EpByL2EpKey = Collections.emptyMap();
819         }
820         return l3EpByL2EpKey;
821     }
822
823     public EgKey getEgKey(Endpoint endpoint) {
824         if (!isValidEp(endpoint))
825             return null;
826         return new EgKey(endpoint.getTenant(), endpoint.getEndpointGroup());
827     }
828 }