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