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