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