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