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