2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.List;
16 import java.util.Map.Entry;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.CopyOnWriteArrayList;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.ScheduledExecutorService;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
31 import org.opendaylight.groupbasedpolicy.endpoint.EndpointRpcRegistry;
32 import org.opendaylight.groupbasedpolicy.endpoint.EpKey;
33 import org.opendaylight.groupbasedpolicy.endpoint.EpRendererAugmentation;
34 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
35 import org.opendaylight.groupbasedpolicy.util.SetUtils;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig.LearningMode;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
57 import org.opendaylight.yangtools.concepts.ListenerRegistration;
58 import org.opendaylight.yangtools.yang.binding.DataObject;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
63 import com.google.common.base.Function;
64 import com.google.common.base.Optional;
65 import com.google.common.base.Predicate;
66 import com.google.common.collect.Collections2;
67 import com.google.common.collect.Sets;
70 * Keep track of endpoints on the system. Maintain an index of endpoints and
71 * their locations for renderering. The endpoint manager will maintain
72 * appropriate indexes only for switches that are attached to the current
75 * In order to render the policy, we need to be able to efficiently enumerate
76 * all endpoints on a particular switch and also all the switches containing
77 * each particular endpoint group
81 public class EndpointManager implements AutoCloseable, DataChangeListener
83 private static final Logger LOG =
84 LoggerFactory.getLogger(EndpointManager.class);
85 private final static InstanceIdentifier<Nodes> nodesIid = InstanceIdentifier
86 .builder(Nodes.class).build();
87 private final static InstanceIdentifier<Node> nodeIid = InstanceIdentifier
88 .builder(Nodes.class).child(Node.class).build();
89 private ListenerRegistration<DataChangeListener> nodesReg;
91 private static final InstanceIdentifier<Endpoint> endpointsIid =
92 InstanceIdentifier.builder(Endpoints.class)
93 .child(Endpoint.class).build();
94 final ListenerRegistration<DataChangeListener> listenerReg;
96 private final ConcurrentHashMap<EpKey, Endpoint> endpoints =
97 new ConcurrentHashMap<>();
98 private final ConcurrentHashMap<NodeId, ConcurrentMap<EgKey, Set<EpKey>>> endpointsByGroupByNode =
99 new ConcurrentHashMap<>();
100 private final ConcurrentHashMap<NodeId, Set<EpKey>> endpointsByNode =
101 new ConcurrentHashMap<>();
103 private final ConcurrentHashMap<EgKey, Set<EpKey>> endpointsByGroup =
104 new ConcurrentHashMap<>();
106 private List<EndpointListener> listeners = new CopyOnWriteArrayList<>();
108 final private OfEndpointAug endpointRpcAug = new OfEndpointAug();
110 final private ScheduledExecutorService executor;
112 final private DataBroker dataProvider;
114 public EndpointManager(DataBroker dataProvider,
115 RpcProviderRegistry rpcRegistry,
116 ScheduledExecutorService executor,
117 SwitchManager switchManager) {
118 this.executor = executor;
119 this.dataProvider = dataProvider;
120 EndpointRpcRegistry.register(dataProvider, rpcRegistry, executor, endpointRpcAug);
121 if (dataProvider != null) {
122 listenerReg = dataProvider
123 .registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
126 DataChangeScope.ONE);
127 nodesReg = dataProvider.registerDataChangeListener(
128 LogicalDatastoreType.OPERATIONAL, nodeIid,
129 new NodesListener(), DataChangeScope.SUBTREE);
134 LOG.debug("Initialized OFOverlay endpoint manager");
142 * Add a {@link EndpointListener} to get notifications of switch events
145 * the {@link EndpointListener} to add
147 public void registerListener(EndpointListener listener) {
148 listeners.add(listener);
152 * Get a collection of endpoints attached to a particular switch
155 * the nodeId of the switch to get endpoints for
156 * @return a collection of {@link Endpoint} objects.
158 public synchronized Set<EgKey> getGroupsForNode(NodeId nodeId) {
159 Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
161 return Collections.emptySet();
162 return Collections.unmodifiableSet(nodeEps.keySet());
166 * Get the set of nodes
169 * the egKey of the endpointgroup to get nodes for
170 * @return a collection of {@link NodeId} objects.
172 public synchronized Set<NodeId> getNodesForGroup(final EgKey egKey) {
173 return Collections.unmodifiableSet(Sets.filter(endpointsByGroupByNode.keySet(),
174 new Predicate<NodeId>() {
176 public boolean apply(NodeId input) {
177 Map<EgKey, Set<EpKey>> nodeEps =
178 endpointsByGroupByNode.get(input);
179 return (nodeEps != null &&
180 nodeEps.containsKey(egKey));
187 * Get the endpoints in a particular group on a particular node
190 * the node ID to look up
192 * the group to look up
193 * @return the endpoints
195 public synchronized Collection<Endpoint> getEndpointsForNode(NodeId nodeId, EgKey eg) {
196 // TODO: alagalah Create method findEndpointsByNode() that uses
199 Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
201 return Collections.emptyList();
202 Collection<EpKey> ebn = nodeEps.get(eg);
204 return Collections.emptyList();
205 return Collections.unmodifiableCollection(Collections2
211 * Get the endpoints on a particular node
214 * the node ID to look up
215 * @return the endpoints
217 public synchronized Collection<Endpoint> getEndpointsForNode(final NodeId nodeId) {
218 // TODO: alagalah Create method findEndpointsByNode() that uses
219 // datastore. See commented code below.
221 Collection<Endpoint> epsByNode = Collections.emptyList();
222 // Blocking for test.
223 // // Predicate for filtering only the endpoints we need for this nodeID
224 // //TODO: This pulls from datastore. Will be more performant to update
225 // // endpointByNode in updateEndpoint.
226 // Predicate<Endpoint> predicate = new Predicate<Endpoint>() {
228 // public boolean apply(Endpoint ep) {
230 // ep.getAugmentation(OfOverlayContext.class).getNodeId().getValue().equals(nodeId.getValue());
234 // Optional<Endpoints> epResult;
235 // final InstanceIdentifier<Endpoints> endpointsIid =
236 // InstanceIdentifier.builder(Endpoints.class).build();
239 // dataProvider.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL,
240 // endpointsIid).get();
241 // if(epResult.isPresent()) {
242 // Endpoints endpoints = epResult.get();
244 // Collections2.filter((Collection<Endpoint>)endpoints.getEndpoint(),predicate);
246 // } catch (InterruptedException | ExecutionException e) {
247 // LOG.error("Caught exception in getEPsForNode");
249 Collection<EpKey> ebn = endpointsByNode.get(nodeId);
251 return Collections.emptyList();
252 return Collections.unmodifiableCollection(Collections2
259 * Get the endpoint object for the given key
263 * @return the {@link Endpoint} corresponding to the key
265 public Endpoint getEndpoint(EpKey epKey) {
266 return endpoints.get(epKey);
270 * Set the learning mode to the specified value
272 * @param learningMode
273 * the learning mode to set
275 public void setLearningMode(LearningMode learningMode) {
280 * Get a collection of endpoints in a particular endpoint group
283 * the nodeId of the switch to get endpoints for
284 * @return a collection of {@link Endpoint} objects.
286 public synchronized Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
287 Collection<EpKey> ebg = endpointsByGroup.get(eg);
289 return Collections.emptyList();
290 return Collections2.transform(ebg, indexTransform);
294 * Get the effective list of conditions that apply to a particular endpoint.
295 * This could include additional conditions over the condition labels
296 * directly represented in the endpoint object
299 * the {@link Endpoint} to resolve
300 * @return the list of {@link ConditionName}
302 public List<ConditionName> getCondsForEndpoint(Endpoint endpoint) {
303 // TODO Be alagalah From Helium: consider group conditions as well. Also
305 // endpoint updated if the endpoint group conditions change
306 if (endpoint.getCondition() != null)
307 return endpoint.getCondition();
309 return Collections.emptyList();
312 // ************************
313 // Endpoint Augmentation
314 // ************************
315 private class OfEndpointAug implements EpRendererAugmentation {
318 public void buildEndpointAugmentation(EndpointBuilder eb,
319 RegisterEndpointInput input) {
320 // In order to support both the port-name and the data-path
321 // information, allow
322 // an EP to register without the augmentations, and resolve later.
323 OfOverlayContextBuilder ictx = checkAugmentation(input);
325 eb.addAugmentation(OfOverlayContext.class, ictx.build());
330 public void buildEndpointL3Augmentation(EndpointL3Builder eb,
331 RegisterEndpointInput input) {
335 public void buildL3PrefixEndpointAugmentation(EndpointL3PrefixBuilder eb, RegisterL3PrefixEndpointInput input) {
336 // TODO Auto-generated method stub
340 private OfOverlayContextBuilder checkAugmentation(RegisterEndpointInput input) {
341 OfOverlayContextInput ictx = input.getAugmentation(OfOverlayContextInput.class);
346 OfOverlayContextBuilder ictxBuilder = new OfOverlayContextBuilder(ictx);
347 if (ictx.getPortName() != null && ictx.getNodeId() != null && ictx.getNodeConnectorId() != null) {
352 * In the case where they've provided just the port name,
353 * go see if we can find the NodeId and NodeConnectorId
356 if (ictx.getPortName() != null) {
357 NodeInfo augmentation = fetchAugmentation(ictx.getPortName().getValue());
358 if (augmentation != null) {
359 ictxBuilder.setNodeId(augmentation.getNode().getId());
360 ictxBuilder.setNodeConnectorId(augmentation.getNodeConnector().getId());
366 private NodeInfo fetchAugmentation(String portName) {
367 NodeInfo nodeInfo = null;
369 if (dataProvider != null) {
371 Optional<Nodes> result;
373 result = dataProvider
374 .newReadOnlyTransaction().read(
375 LogicalDatastoreType.OPERATIONAL, nodesIid).get();
376 if (result.isPresent()) {
377 Nodes nodes = result.get();
378 for (Node node : nodes.getNode()) {
379 if (node.getNodeConnector() != null) {
380 boolean found = false;
381 for (NodeConnector nc : node.getNodeConnector()) {
382 FlowCapableNodeConnector fcnc = nc
383 .getAugmentation(FlowCapableNodeConnector.class);
384 if (fcnc.getName().equals(portName)) {
385 nodeInfo = new NodeInfo();
386 nodeInfo.setNode(node);
387 nodeInfo.setNodeConnector(nc);
397 } catch (InterruptedException | ExecutionException e) {
398 LOG.error("Caught exception in fetchAugmentation portName", e);
411 public void close() throws Exception {
412 if (listenerReg != null)
414 EndpointRpcRegistry.unregister(endpointRpcAug);
417 // ******************
418 // DataChangeListener
419 // ******************
422 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
423 for (DataObject dao : change.getCreatedData().values()) {
424 if (dao instanceof Endpoint)
425 updateEndpoint(null, (Endpoint) dao);
427 for (InstanceIdentifier<?> iid : change.getRemovedPaths()) {
428 DataObject old = change.getOriginalData().get(iid);
429 if (old != null && old instanceof Endpoint)
430 updateEndpoint((Endpoint) old, null);
432 Map<InstanceIdentifier<?>, DataObject> d = change.getUpdatedData();
433 for (Entry<InstanceIdentifier<?>, DataObject> entry : d.entrySet()) {
434 if (!(entry.getValue() instanceof Endpoint))
436 DataObject old = change.getOriginalData().get(entry.getKey());
437 Endpoint oldEp = null;
438 if (old != null && old instanceof Endpoint)
439 oldEp = (Endpoint) old;
440 updateEndpoint(oldEp, (Endpoint) entry.getValue());
444 // TODO: alagalah Investigate using the internal project listener structure
445 // for this. ie Endpoint should listen to
446 // SwitchManager updates and update the EP maps accordingly (update
447 // Endpoint). Removal should include the overloaded
448 // method updateEndpoint(Node node)
449 private class NodesListener implements DataChangeListener {
451 public void onDataChanged(
452 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
453 for (DataObject dao : change.getCreatedData().values()) {
454 if (!(dao instanceof Node))
456 Node node = (Node) dao;
457 if (node.getNodeConnector() != null) {
458 updateEndpoint(node);
461 for (DataObject dao : change.getUpdatedData().values()) {
462 if (!(dao instanceof Node))
464 Node node = (Node) dao;
465 if (node.getNodeConnector() != null) {
466 updateEndpoint(node);
472 // TODO Li alagalah move this near to other updateEndpoint()
473 private void updateEndpoint(Node node) {
474 final InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class).build();
476 Optional<Endpoints> epResult;
478 for (NodeConnector nc : node.getNodeConnector()) {
479 FlowCapableNodeConnector fcnc = nc
480 .getAugmentation(FlowCapableNodeConnector.class);
482 epResult = dataProvider.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL, endpointsIid)
484 if (epResult.isPresent()) {
485 Endpoints endpoints = epResult.get();
486 if (endpoints.getEndpoint() != null) {
487 Boolean isEmpty = true;
488 for (Endpoint ep : endpoints.getEndpoint()) {
489 // 2. Search for portname
490 OfOverlayContext currentAugmentation = ep.getAugmentation(OfOverlayContext.class);
491 if (currentAugmentation.getPortName() != null && fcnc.getName() != null
492 && currentAugmentation.getPortName().getValue().equals(fcnc.getName())) {
494 NodeConnectorId nodeConnectorId;
497 nodeId = currentAugmentation.getNodeId();
498 nodeConnectorId = currentAugmentation.getNodeConnectorId();
499 name = currentAugmentation.getPortName();
500 } catch (Exception e) {
502 nodeConnectorId = null;
505 Boolean process = false;
506 if (nodeId == null && nodeConnectorId == null) {
507 LOG.debug("ep NodeID and NC ID Both null");
510 if (nodeId != null && nodeConnectorId != null) {
511 if (!(nodeConnectorId.getValue().equals(nc.getId().getValue()))) {
512 LOG.debug("ep NodeID and NC ID Both NOT null but epNCID !=nodeNCID");
517 WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
518 // 3. Update endpoint
519 EndpointBuilder epBuilder = new EndpointBuilder(ep);
520 OfOverlayContextBuilder ofOverlayAugmentation = new OfOverlayContextBuilder();
521 ofOverlayAugmentation.setNodeId(node.getId());
522 ofOverlayAugmentation.setNodeConnectorId(nc.getId());
523 ofOverlayAugmentation.setPortName(name);
524 epBuilder.addAugmentation(OfOverlayContext.class, ofOverlayAugmentation.build());
525 epBuilder.setL3Address(ep.getL3Address());
526 InstanceIdentifier<Endpoint> iidEp = InstanceIdentifier.builder(Endpoints.class)
527 .child(Endpoint.class, ep.getKey()).build();
528 tx.put(LogicalDatastoreType.OPERATIONAL, iidEp, epBuilder.build());
530 epKey = new EpKey(ep.getKey().getL2Context(), ep.getKey().getMacAddress());
531 notifyEndpointUpdated(epKey);
532 LOG.debug("Values:");
533 LOG.debug("node: Node ID:" + node.getId().getValue());
534 LOG.debug("node: NodeConnectorID: " + nc.getId().getValue());
535 if (nodeId != null && nodeConnectorId != null) {
536 LOG.debug("ep: nodeID:" + nodeId.getValue());
537 LOG.debug("ep: nodeConnectorID:" + nodeConnectorId.getValue());
545 } catch (InterruptedException | ExecutionException e) {
546 LOG.error("Exception in UpdateEndpoint", e);
555 private void notifyEndpointUpdated(EpKey epKey) {
556 for (EndpointListener l : listeners) {
557 l.endpointUpdated(epKey);
561 private void notifyNodeEndpointUpdated(NodeId nodeId, EpKey epKey) {
562 for (EndpointListener l : listeners) {
563 l.nodeEndpointUpdated(nodeId, epKey);
567 private void notifyGroupEndpointUpdated(EgKey egKey, EpKey epKey) {
568 for (EndpointListener l : listeners) {
569 l.groupEndpointUpdated(egKey, epKey);
573 private Function<EpKey, Endpoint> indexTransform =
574 new Function<EpKey, Endpoint>() {
576 public Endpoint apply(EpKey input) {
577 return endpoints.get(input);
581 private boolean validEp(Endpoint endpoint) {
582 return (endpoint != null && endpoint.getTenant() != null &&
583 (endpoint.getEndpointGroup() != null || endpoint.getEndpointGroups() != null) &&
584 endpoint.getL2Context() != null && endpoint.getMacAddress() != null);
587 private NodeId getLocation(Endpoint endpoint) {
588 if (!validEp(endpoint))
590 OfOverlayContext context =
591 endpoint.getAugmentation(OfOverlayContext.class);
593 return context.getNodeId();
598 private EpKey getEpKey(Endpoint endpoint) {
599 if (!validEp(endpoint))
601 return new EpKey(endpoint.getL2Context(), endpoint.getMacAddress());
604 public EgKey getEgKey(Endpoint endpoint) {
605 if (!validEp(endpoint))
607 return new EgKey(endpoint.getTenant(), endpoint.getEndpointGroup());
610 public Set<EgKey> getEgKeysForEndpoint(Endpoint ep) {
611 Set<EgKey> egKeys = new HashSet<EgKey>();
613 if (ep.getEndpointGroup() != null) {
614 egKeys.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
616 if (ep.getEndpointGroups() != null) {
617 for (EndpointGroupId epgId : ep.getEndpointGroups()) {
618 egKeys.add(new EgKey(ep.getTenant(), epgId));
624 private Set<EpKey> getEpNGSet(NodeId location, EgKey eg) {
625 ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(location);
627 map = new ConcurrentHashMap<>();
628 ConcurrentMap<EgKey, Set<EpKey>> old =
629 endpointsByGroupByNode.putIfAbsent(location, map);
633 return SetUtils.getNestedSet(eg, map);
636 private static final ConcurrentMap<EgKey, Set<EpKey>> EMPTY_MAP =
637 new ConcurrentHashMap<>();
639 private Set<EpKey> getEpGSet(EgKey eg) {
640 return SetUtils.getNestedSet(eg, endpointsByGroup);
644 * Update the endpoint indexes. Set newEp to null to remove.
646 protected synchronized void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
647 // TODO Be alagalah From Helium only keep track of endpoints that are
649 // to switches that are actually connected to us
651 // TODO Li alagalah: This needs a major clean up and refactor. For now
653 NodeId oldLoc = getLocation(oldEp);
654 NodeId newLoc = getLocation(newEp);
655 // EgKey oldEgKey = getEgKey(oldEp);
656 EpKey oldEpKey = getEpKey(oldEp);
657 EpKey newEpKey = getEpKey(newEp);
659 boolean notifyOldLoc = false;
660 boolean notifyNewLoc = false;
661 boolean notifyOldEg = false;
662 boolean notifyNewEg = false;
664 // When newLoc and oldLoc are null there is nothing to do
665 if (!(newLoc == null && oldLoc == null)) {
667 Set<EndpointGroupId> newEpgIds = new HashSet<EndpointGroupId>();
668 TenantId tenantId = null;
670 if (newEp.getEndpointGroups() != null) {
671 newEpgIds.addAll(newEp.getEndpointGroups());
673 if (newEp.getEndpointGroup() != null) {
674 newEpgIds.add(newEp.getEndpointGroup());
676 tenantId = newEp.getTenant();
679 Set<EndpointGroupId> oldEpgIds = new HashSet<EndpointGroupId>();
681 if (oldEp.getEndpointGroups() != null) {
682 oldEpgIds.addAll(oldEp.getEndpointGroups());
684 if (oldEp.getEndpointGroup() != null) {
685 oldEpgIds.add(oldEp.getEndpointGroup());
690 * maintainIndex(endpointsByNode,oldEp,newEp) Maintain following
691 * maps endpoints - <EpKey, Endpoint> endpointsByGroupByNode -
692 * <NodeId, ConcurrentMap<EgKey, Set<EpKey>>> endpointsByNode -
693 * <NodeId,Set<EpKey>> endpointsByGroup ConcurrentHashMap<EgKey,
697 // Maintain "endpoints" map
699 endpoints.put(newEpKey, newEp);
701 endpoints.remove(oldEpKey);
705 * New endpoint with location information
707 if (oldEp == null && newEp != null && newLoc != null) {
708 // Update endpointsByNode
709 if (endpointsByNode.get(newLoc) == null) {
710 // TODO: alagalah cleaner way with checking epsNode
712 Set<EpKey> epsNode = new HashSet<EpKey>();
713 epsNode.add(newEpKey);
714 endpointsByNode.put(newLoc, epsNode);
716 Set<EpKey> epsNode = endpointsByNode.get(newLoc);
717 epsNode.add(newEpKey);
719 // Update endpointsByGroupByNode and endpointsByGroup
720 for (EndpointGroupId newEpgId : newEpgIds) {
721 // endpointsByGroupByNode
722 EgKey newEgKey = new EgKey(tenantId, newEpgId);
723 Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
726 Set<EpKey> geps = endpointsByGroup.get(newEgKey);
728 geps = new HashSet<>();
731 endpointsByGroup.put(newEgKey, geps);
732 LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
743 if (oldEp != null && newEp == null) {
744 // Update endpointsByNode
745 Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
746 if (epsNode != null) {
747 epsNode.remove(oldEpKey);
748 if (epsNode.isEmpty())
749 endpointsByNode.remove(oldLoc);
751 // Update endpointsByGroupByNode
752 // Update endpointsByGroup
753 // Get map of EPGs and their Endpoints for Node
754 ConcurrentMap<EgKey, Set<EpKey>> map =
755 endpointsByGroupByNode.get(oldLoc);
756 // For each EPG in the removed endpoint...
757 for (EndpointGroupId oldEpgId : newEpgIds) {
758 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
759 // Get list of endpoints for EPG
760 Set<EpKey> eps = map.get(oldEgKey);
761 // Remove the endpoint from the map
763 eps.remove(oldEpKey);
765 map.remove(oldEgKey, Collections.emptySet());
768 Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
770 geps.remove(oldEpKey);
772 endpointsByGroup.remove(oldEgKey);
775 // If map is empty, no more EPGs on this node, remove node from
778 endpointsByGroupByNode.remove(oldLoc, EMPTY_MAP);
784 * Moved endpoint (from node to node or from NULL to node)
786 if ((oldEp != null && newEp != null && oldEpKey != null && newEpKey != null) &&
787 (oldEpKey.toString().equals(newEpKey.toString()))) {
788 // old and new Endpoints have same key. (same endpoint)
791 * Remove old endpoint if moved.
793 if (oldLoc != null && !(oldLoc.getValue().equals(newLoc.getValue()))) {
794 // This is an endpoint that has moved, remove from old node
795 Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
796 if (epsNode != null) {
797 epsNode.remove(oldEpKey);
798 if (epsNode.isEmpty())
799 endpointsByNode.remove(oldLoc);
801 // Update endpointsByGroupByNode
802 // Get map of EPGs and their Endpoints for Node
803 ConcurrentMap<EgKey, Set<EpKey>> map =
804 endpointsByGroupByNode.get(oldLoc);
805 // For each EPG in the removed endpoint...
806 for (EndpointGroupId oldEpgId : oldEpgIds) {
807 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
808 // Get list of endpoints for EPG
809 Set<EpKey> eps = map.get(oldEgKey);
810 // Remove the endpoint from the map
812 eps.remove(oldEpKey);
814 map.remove(oldEgKey, Collections.emptySet());
817 Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
820 geps.remove(oldEpKey);
822 endpointsByGroup.remove(oldEgKey);
825 // If map is empty, no more EPGs on this node, remove node
828 endpointsByGroupByNode.remove(oldLoc, EMPTY_MAP);
836 // Update endpointsByNode
837 if (endpointsByNode.get(newLoc) == null) {
838 Set<EpKey> newEpsNode = new HashSet<EpKey>();
839 newEpsNode.add(newEpKey);
840 endpointsByNode.put(newLoc, newEpsNode);
842 Set<EpKey> newEpsNode = endpointsByNode.get(newLoc);
843 newEpsNode.add(newEpKey);
847 // Update endpointsByGroupByNode
848 // Update endpointsByGroup
849 for (EndpointGroupId newEpgId : newEpgIds) {
850 EgKey newEgKey = new EgKey(tenantId, newEpgId);
851 Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
854 Set<EpKey> geps = endpointsByGroup.get(newEgKey);
856 geps = new HashSet<>();
859 endpointsByGroup.put(newEgKey, geps);
862 LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
868 notifyEndpointUpdated(newEpKey);
870 notifyEndpointUpdated(oldEpKey);
872 // TODO alagalah NEXt: ensure right notification flags are set.
874 notifyNodeEndpointUpdated(oldLoc, oldEpKey);
876 notifyNodeEndpointUpdated(newLoc, newEpKey);
878 for (EndpointGroupId oldEpgId : oldEpgIds) {
879 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
880 notifyGroupEndpointUpdated(oldEgKey, oldEpKey);
883 for (EndpointGroupId newEpgId : newEpgIds) {
884 EgKey newEgKey = new EgKey(newEp.getTenant(), newEpgId);
885 notifyGroupEndpointUpdated(newEgKey, newEpKey);
891 // A wrapper class around node, nodeConnector info so we can pass a final
892 // object inside OnSuccess anonymous inner class
893 private static class NodeInfo {
894 NodeConnector nodeConnector;
901 private NodeInfo(NodeConnector nc, Node node) {
902 this.nodeConnector = nc;
906 private Node getNode() {
910 private NodeConnector getNodeConnector() {
911 return this.nodeConnector;
914 public void setNodeConnector(NodeConnector nodeConnector) {
915 this.nodeConnector = nodeConnector;
918 public void setNode(Node node) {