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