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.ImmutableList;
68 import com.google.common.collect.ImmutableSet;
69 import com.google.common.collect.Sets;
72 * Keep track of endpoints on the system. Maintain an index of endpoints and
73 * their locations for renderering. The endpoint manager will maintain
74 * appropriate indexes only for switches that are attached to the current
77 * In order to render the policy, we need to be able to efficiently enumerate
78 * all endpoints on a particular switch and also all the switches containing
79 * each particular endpoint group
83 public class EndpointManager implements AutoCloseable, DataChangeListener
85 private static final Logger LOG =
86 LoggerFactory.getLogger(EndpointManager.class);
87 private final static InstanceIdentifier<Nodes> nodesIid = InstanceIdentifier
88 .builder(Nodes.class).build();
89 private final static InstanceIdentifier<Node> nodeIid = InstanceIdentifier
90 .builder(Nodes.class).child(Node.class).build();
91 private ListenerRegistration<DataChangeListener> nodesReg;
93 private static final InstanceIdentifier<Endpoint> endpointsIid =
94 InstanceIdentifier.builder(Endpoints.class)
95 .child(Endpoint.class).build();
96 final ListenerRegistration<DataChangeListener> listenerReg;
98 private final ConcurrentHashMap<EpKey, Endpoint> endpoints =
99 new ConcurrentHashMap<>();
100 private final ConcurrentHashMap<NodeId, ConcurrentMap<EgKey, Set<EpKey>>> endpointsByGroupByNode =
101 new ConcurrentHashMap<>();
102 private final ConcurrentHashMap<NodeId, Set<EpKey>> endpointsByNode =
103 new ConcurrentHashMap<>();
105 private final ConcurrentHashMap<EgKey, Set<EpKey>> endpointsByGroup =
106 new ConcurrentHashMap<>();
108 private List<EndpointListener> listeners = new CopyOnWriteArrayList<>();
110 final private OfEndpointAug endpointRpcAug = new OfEndpointAug();
112 final private ScheduledExecutorService executor;
114 final private DataBroker dataProvider;
116 public EndpointManager(DataBroker dataProvider,
117 RpcProviderRegistry rpcRegistry,
118 ScheduledExecutorService executor,
119 SwitchManager switchManager) {
120 this.executor = executor;
121 this.dataProvider = dataProvider;
122 EndpointRpcRegistry.register(dataProvider, rpcRegistry, executor, endpointRpcAug);
123 if (dataProvider != null) {
124 listenerReg = dataProvider
125 .registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
128 DataChangeScope.ONE);
129 nodesReg = dataProvider.registerDataChangeListener(
130 LogicalDatastoreType.OPERATIONAL, nodeIid,
131 new NodesListener(), DataChangeScope.SUBTREE);
136 LOG.debug("Initialized OFOverlay endpoint manager");
144 * Add a {@link EndpointListener} to get notifications of switch events
147 * the {@link EndpointListener} to add
149 public void registerListener(EndpointListener listener) {
150 listeners.add(listener);
154 * Get a collection of endpoints attached to a particular switch
157 * the nodeId of the switch to get endpoints for
158 * @return a collection of {@link Endpoint} objects.
160 public synchronized Set<EgKey> getGroupsForNode(NodeId nodeId) {
161 Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
163 return Collections.emptySet();
164 return ImmutableSet.copyOf(nodeEps.keySet());
168 * Get the set of nodes
171 * the egKey of the endpointgroup to get nodes for
172 * @return a collection of {@link NodeId} objects.
174 public synchronized Set<NodeId> getNodesForGroup(final EgKey egKey) {
175 return ImmutableSet.copyOf(Sets.filter(endpointsByGroupByNode.keySet(),
176 new Predicate<NodeId>() {
178 public boolean apply(NodeId input) {
179 Map<EgKey, Set<EpKey>> nodeEps =
180 endpointsByGroupByNode.get(input);
181 return (nodeEps != null &&
182 nodeEps.containsKey(egKey));
189 * Get the endpoints in a particular group on a particular node
192 * the node ID to look up
194 * the group to look up
195 * @return the endpoints
197 public synchronized Collection<Endpoint> getEndpointsForNode(NodeId nodeId, EgKey eg) {
198 // TODO: alagalah Create method findEndpointsByNode() that uses
201 Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
203 return Collections.emptyList();
204 Collection<EpKey> ebn = nodeEps.get(eg);
206 return Collections.emptyList();
207 return ImmutableList.copyOf(Collections2.transform(ebn,indexTransform));
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<EpKey> ebn = endpointsByNode.get(nodeId);
223 return Collections.emptyList();
224 return ImmutableList.copyOf(Collections2.transform(ebn, indexTransform));
229 * Get the endpoint object for the given key
233 * @return the {@link Endpoint} corresponding to the key
235 public Endpoint getEndpoint(EpKey epKey) {
236 return endpoints.get(epKey);
240 * Set the learning mode to the specified value
242 * @param learningMode
243 * the learning mode to set
245 public void setLearningMode(LearningMode learningMode) {
250 * Get a collection of endpoints in a particular endpoint group
253 * the nodeId of the switch to get endpoints for
254 * @return a collection of {@link Endpoint} objects.
256 public synchronized Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
257 Collection<EpKey> ebg = endpointsByGroup.get(eg);
259 return Collections.emptyList();
260 return ImmutableList.copyOf(Collections2.transform(ebg, indexTransform));
264 * Get the effective list of conditions that apply to a particular endpoint.
265 * This could include additional conditions over the condition labels
266 * directly represented in the endpoint object
269 * the {@link Endpoint} to resolve
270 * @return the list of {@link ConditionName}
272 public List<ConditionName> getCondsForEndpoint(Endpoint endpoint) {
273 // TODO Be alagalah From Helium: consider group conditions as well. Also
275 // endpoint updated if the endpoint group conditions change
276 if (endpoint.getCondition() != null)
277 return endpoint.getCondition();
279 return Collections.emptyList();
282 // ************************
283 // Endpoint Augmentation
284 // ************************
285 private class OfEndpointAug implements EpRendererAugmentation {
288 public void buildEndpointAugmentation(EndpointBuilder eb,
289 RegisterEndpointInput input) {
290 // In order to support both the port-name and the data-path
291 // information, allow
292 // an EP to register without the augmentations, and resolve later.
293 OfOverlayContextBuilder ictx = checkAugmentation(input);
295 eb.addAugmentation(OfOverlayContext.class, ictx.build());
300 public void buildEndpointL3Augmentation(EndpointL3Builder eb,
301 RegisterEndpointInput input) {
305 public void buildL3PrefixEndpointAugmentation(EndpointL3PrefixBuilder eb, RegisterL3PrefixEndpointInput input) {
306 // TODO Auto-generated method stub
310 private OfOverlayContextBuilder checkAugmentation(RegisterEndpointInput input) {
311 OfOverlayContextInput ictx = input.getAugmentation(OfOverlayContextInput.class);
316 OfOverlayContextBuilder ictxBuilder = new OfOverlayContextBuilder(ictx);
317 if (ictx.getPortName() != null && ictx.getNodeId() != null && ictx.getNodeConnectorId() != null) {
322 * In the case where they've provided just the port name, go see if
323 * we can find the NodeId and NodeConnectorId from inventory.
325 if (ictx.getPortName() != null) {
326 NodeInfo augmentation = fetchAugmentation(ictx.getPortName().getValue());
327 if (augmentation != null) {
328 ictxBuilder.setNodeId(augmentation.getNode().getId());
329 ictxBuilder.setNodeConnectorId(augmentation.getNodeConnector().getId());
335 private NodeInfo fetchAugmentation(String portName) {
336 NodeInfo nodeInfo = null;
338 if (dataProvider != null) {
340 Optional<Nodes> result;
342 result = dataProvider
343 .newReadOnlyTransaction().read(
344 LogicalDatastoreType.OPERATIONAL, nodesIid).get();
345 if (result.isPresent()) {
346 Nodes nodes = result.get();
347 for (Node node : nodes.getNode()) {
348 if (node.getNodeConnector() != null) {
349 boolean found = false;
350 for (NodeConnector nc : node.getNodeConnector()) {
351 FlowCapableNodeConnector fcnc = nc
352 .getAugmentation(FlowCapableNodeConnector.class);
353 if (fcnc.getName().equals(portName)) {
354 nodeInfo = new NodeInfo();
355 nodeInfo.setNode(node);
356 nodeInfo.setNodeConnector(nc);
366 } catch (InterruptedException | ExecutionException e) {
367 LOG.error("Caught exception in fetchAugmentation portName", e);
380 public void close() throws Exception {
381 if (listenerReg != null)
383 EndpointRpcRegistry.unregister(endpointRpcAug);
386 // ******************
387 // DataChangeListener
388 // ******************
391 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
392 for (DataObject dao : change.getCreatedData().values()) {
393 if (dao instanceof Endpoint)
394 updateEndpoint(null, (Endpoint) dao);
396 for (InstanceIdentifier<?> iid : change.getRemovedPaths()) {
397 DataObject old = change.getOriginalData().get(iid);
398 if (old != null && old instanceof Endpoint)
399 updateEndpoint((Endpoint) old, null);
401 Map<InstanceIdentifier<?>, DataObject> d = change.getUpdatedData();
402 for (Entry<InstanceIdentifier<?>, DataObject> entry : d.entrySet()) {
403 if (!(entry.getValue() instanceof Endpoint))
405 DataObject old = change.getOriginalData().get(entry.getKey());
406 Endpoint oldEp = null;
407 if (old != null && old instanceof Endpoint)
408 oldEp = (Endpoint) old;
409 updateEndpoint(oldEp, (Endpoint) entry.getValue());
413 // TODO: alagalah Investigate using the internal project listener structure
414 // for this. ie Endpoint should listen to
415 // SwitchManager updates and update the EP maps accordingly (update
416 // Endpoint). Removal should include the overloaded
417 // method updateEndpoint(Node node)
418 private class NodesListener implements DataChangeListener {
420 public void onDataChanged(
421 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
422 for (DataObject dao : change.getCreatedData().values()) {
423 if (!(dao instanceof Node))
425 Node node = (Node) dao;
426 if (node.getNodeConnector() != null) {
427 updateEndpoint(node);
430 for (DataObject dao : change.getUpdatedData().values()) {
431 if (!(dao instanceof Node))
433 Node node = (Node) dao;
434 if (node.getNodeConnector() != null) {
435 updateEndpoint(node);
441 // TODO Li alagalah move this near to other updateEndpoint()
442 private void updateEndpoint(Node node) {
443 final InstanceIdentifier<Endpoints> endpointsIid = InstanceIdentifier.builder(Endpoints.class).build();
445 Optional<Endpoints> epResult;
447 for (NodeConnector nc : node.getNodeConnector()) {
448 FlowCapableNodeConnector fcnc = nc
449 .getAugmentation(FlowCapableNodeConnector.class);
451 epResult = dataProvider.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL, endpointsIid)
453 if (epResult.isPresent()) {
454 Endpoints endpoints = epResult.get();
455 if (endpoints.getEndpoint() != null) {
456 Boolean isEmpty = true;
457 for (Endpoint ep : endpoints.getEndpoint()) {
458 // 2. Search for portname
459 OfOverlayContext currentAugmentation = ep.getAugmentation(OfOverlayContext.class);
460 if (currentAugmentation.getPortName() != null && fcnc.getName() != null
461 && currentAugmentation.getPortName().getValue().equals(fcnc.getName())) {
463 NodeConnectorId nodeConnectorId;
466 nodeId = currentAugmentation.getNodeId();
467 nodeConnectorId = currentAugmentation.getNodeConnectorId();
468 name = currentAugmentation.getPortName();
469 } catch (Exception e) {
471 nodeConnectorId = null;
474 Boolean process = false;
475 if (nodeId == null && nodeConnectorId == null) {
476 LOG.debug("ep NodeID and NC ID Both null");
479 if (nodeId != null && nodeConnectorId != null) {
480 if (!(nodeConnectorId.getValue().equals(nc.getId().getValue()))) {
481 LOG.debug("ep NodeID and NC ID Both NOT null but epNCID !=nodeNCID");
486 WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
487 // 3. Update endpoint
488 EndpointBuilder epBuilder = new EndpointBuilder(ep);
489 OfOverlayContextBuilder ofOverlayAugmentation = new OfOverlayContextBuilder();
490 ofOverlayAugmentation.setNodeId(node.getId());
491 ofOverlayAugmentation.setNodeConnectorId(nc.getId());
492 ofOverlayAugmentation.setPortName(name);
493 epBuilder.addAugmentation(OfOverlayContext.class, ofOverlayAugmentation.build());
494 epBuilder.setL3Address(ep.getL3Address());
495 InstanceIdentifier<Endpoint> iidEp = InstanceIdentifier.builder(Endpoints.class)
496 .child(Endpoint.class, ep.getKey()).build();
497 tx.put(LogicalDatastoreType.OPERATIONAL, iidEp, epBuilder.build());
499 epKey = new EpKey(ep.getKey().getL2Context(), ep.getKey().getMacAddress());
500 notifyEndpointUpdated(epKey);
501 LOG.debug("Values:");
502 LOG.debug("node: Node ID:" + node.getId().getValue());
503 LOG.debug("node: NodeConnectorID: " + nc.getId().getValue());
504 if (nodeId != null && nodeConnectorId != null) {
505 LOG.debug("ep: nodeID:" + nodeId.getValue());
506 LOG.debug("ep: nodeConnectorID:" + nodeConnectorId.getValue());
514 } catch (InterruptedException | ExecutionException e) {
515 LOG.error("Exception in UpdateEndpoint", e);
524 private void notifyEndpointUpdated(EpKey epKey) {
525 for (EndpointListener l : listeners) {
526 l.endpointUpdated(epKey);
530 private void notifyNodeEndpointUpdated(NodeId nodeId, EpKey epKey) {
531 for (EndpointListener l : listeners) {
532 l.nodeEndpointUpdated(nodeId, epKey);
536 private void notifyGroupEndpointUpdated(EgKey egKey, EpKey epKey) {
537 for (EndpointListener l : listeners) {
538 l.groupEndpointUpdated(egKey, epKey);
542 private Function<EpKey, Endpoint> indexTransform =
543 new Function<EpKey, Endpoint>() {
545 public Endpoint apply(EpKey input) {
546 return endpoints.get(input);
550 private boolean validEp(Endpoint endpoint) {
551 return (endpoint != null && endpoint.getTenant() != null &&
552 (endpoint.getEndpointGroup() != null || endpoint.getEndpointGroups() != null) &&
553 endpoint.getL2Context() != null && endpoint.getMacAddress() != null);
556 private NodeId getLocation(Endpoint endpoint) {
557 if (!validEp(endpoint))
559 OfOverlayContext context =
560 endpoint.getAugmentation(OfOverlayContext.class);
562 return context.getNodeId();
567 private EpKey getEpKey(Endpoint endpoint) {
568 if (!validEp(endpoint))
570 return new EpKey(endpoint.getL2Context(), endpoint.getMacAddress());
573 public EgKey getEgKey(Endpoint endpoint) {
574 if (!validEp(endpoint))
576 return new EgKey(endpoint.getTenant(), endpoint.getEndpointGroup());
579 public Set<EgKey> getEgKeysForEndpoint(Endpoint ep) {
580 Set<EgKey> egKeys = new HashSet<EgKey>();
582 if (ep.getEndpointGroup() != null) {
583 egKeys.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
585 if (ep.getEndpointGroups() != null) {
586 for (EndpointGroupId epgId : ep.getEndpointGroups()) {
587 egKeys.add(new EgKey(ep.getTenant(), epgId));
593 private Set<EpKey> getEpNGSet(NodeId location, EgKey eg) {
594 ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(location);
596 map = new ConcurrentHashMap<>();
597 ConcurrentMap<EgKey, Set<EpKey>> old =
598 endpointsByGroupByNode.putIfAbsent(location, map);
602 return SetUtils.getNestedSet(eg, map);
605 private static final ConcurrentMap<EgKey, Set<EpKey>> EMPTY_MAP =
606 new ConcurrentHashMap<>();
608 private Set<EpKey> getEpGSet(EgKey eg) {
609 return SetUtils.getNestedSet(eg, endpointsByGroup);
613 * Update the endpoint indexes. Set newEp to null to remove.
615 protected synchronized void updateEndpoint(Endpoint oldEp, Endpoint newEp) {
616 // TODO Be alagalah From Helium only keep track of endpoints that are
618 // to switches that are actually connected to us
620 // TODO Li alagalah: This needs a major clean up and refactor. For now
622 NodeId oldLoc = getLocation(oldEp);
623 NodeId newLoc = getLocation(newEp);
624 // EgKey oldEgKey = getEgKey(oldEp);
625 EpKey oldEpKey = getEpKey(oldEp);
626 EpKey newEpKey = getEpKey(newEp);
628 boolean notifyOldLoc = false;
629 boolean notifyNewLoc = false;
630 boolean notifyOldEg = false;
631 boolean notifyNewEg = false;
633 // When newLoc and oldLoc are null there is nothing to do
634 if (newLoc == null && oldLoc == null) {
638 Set<EndpointGroupId> newEpgIds = new HashSet<EndpointGroupId>();
639 TenantId tenantId = null;
641 if (newEp.getEndpointGroups() != null) {
642 newEpgIds.addAll(newEp.getEndpointGroups());
644 if (newEp.getEndpointGroup() != null) {
645 newEpgIds.add(newEp.getEndpointGroup());
647 tenantId = newEp.getTenant();
650 Set<EndpointGroupId> oldEpgIds = new HashSet<EndpointGroupId>();
652 if (oldEp.getEndpointGroups() != null) {
653 oldEpgIds.addAll(oldEp.getEndpointGroups());
655 if (oldEp.getEndpointGroup() != null) {
656 oldEpgIds.add(oldEp.getEndpointGroup());
661 * maintainIndex(endpointsByNode,oldEp,newEp) Maintain following maps
662 * endpoints - <EpKey, Endpoint> endpointsByGroupByNode - <NodeId,
663 * ConcurrentMap<EgKey, Set<EpKey>>> endpointsByNode -
664 * <NodeId,Set<EpKey>> endpointsByGroup ConcurrentHashMap<EgKey,
668 // Maintain "endpoints" map
670 endpoints.put(newEpKey, newEp);
672 endpoints.remove(oldEpKey);
676 * New endpoint with location information
678 if (oldEp == null && newEp != null && newLoc != null) {
679 // Update endpointsByNode
680 if (endpointsByNode.get(newLoc) == null) {
681 // TODO: alagalah cleaner way with checking epsNode
683 Set<EpKey> epsNode = new HashSet<EpKey>();
684 epsNode.add(newEpKey);
685 endpointsByNode.put(newLoc, epsNode);
687 Set<EpKey> epsNode = endpointsByNode.get(newLoc);
688 epsNode.add(newEpKey);
690 // Update endpointsByGroupByNode and endpointsByGroup
691 for (EndpointGroupId newEpgId : newEpgIds) {
692 // endpointsByGroupByNode
693 EgKey newEgKey = new EgKey(tenantId, newEpgId);
694 Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
697 Set<EpKey> geps = endpointsByGroup.get(newEgKey);
699 geps = new HashSet<>();
702 endpointsByGroup.put(newEgKey, geps);
703 LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
714 if (oldEp != null && newEp == null) {
715 // Update endpointsByNode
716 Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
717 if (epsNode != null) {
718 epsNode.remove(oldEpKey);
719 if (epsNode.isEmpty())
720 endpointsByNode.remove(oldLoc);
722 // Update endpointsByGroupByNode
723 // Update endpointsByGroup
724 // Get map of EPGs and their Endpoints for Node
725 ConcurrentMap<EgKey, Set<EpKey>> map =
726 endpointsByGroupByNode.get(oldLoc);
727 // For each EPG in the removed endpoint...
728 for (EndpointGroupId oldEpgId : newEpgIds) {
729 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
730 // Get list of endpoints for EPG
731 Set<EpKey> eps = map.get(oldEgKey);
732 // Remove the endpoint from the map
734 eps.remove(oldEpKey);
736 map.remove(oldEgKey, Collections.emptySet());
739 Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
741 geps.remove(oldEpKey);
743 endpointsByGroup.remove(oldEgKey);
746 // If map is empty, no more EPGs on this node, remove node from
749 endpointsByGroupByNode.remove(oldLoc, EMPTY_MAP);
755 * Moved endpoint (from node to node or from NULL to node)
757 if ((oldEp != null && newEp != null && oldEpKey != null && newEpKey != null) &&
758 (oldEpKey.toString().equals(newEpKey.toString()))) {
759 // old and new Endpoints have same key. (same endpoint)
762 * Remove old endpoint if moved.
764 if (oldLoc != null && !(oldLoc.getValue().equals(newLoc.getValue()))) {
765 // This is an endpoint that has moved, remove from old node
766 Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
767 if (epsNode != null) {
768 epsNode.remove(oldEpKey);
769 if (epsNode.isEmpty())
770 endpointsByNode.remove(oldLoc);
772 // Update endpointsByGroupByNode
773 // Get map of EPGs and their Endpoints for Node
774 ConcurrentMap<EgKey, Set<EpKey>> map =
775 endpointsByGroupByNode.get(oldLoc);
776 // For each EPG in the removed endpoint...
777 for (EndpointGroupId oldEpgId : oldEpgIds) {
778 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
779 // Get list of endpoints for EPG
780 Set<EpKey> eps = map.get(oldEgKey);
781 // Remove the endpoint from the map
783 eps.remove(oldEpKey);
785 map.remove(oldEgKey, Collections.emptySet());
788 Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
791 geps.remove(oldEpKey);
793 endpointsByGroup.remove(oldEgKey);
796 // If map is empty, no more EPGs on this node, remove node
799 endpointsByGroupByNode.remove(oldLoc, EMPTY_MAP);
807 // Update endpointsByNode
808 if (endpointsByNode.get(newLoc) == null) {
809 Set<EpKey> newEpsNode = new HashSet<EpKey>();
810 newEpsNode.add(newEpKey);
811 endpointsByNode.put(newLoc, newEpsNode);
813 Set<EpKey> newEpsNode = endpointsByNode.get(newLoc);
814 newEpsNode.add(newEpKey);
818 // Update endpointsByGroupByNode
819 // Update endpointsByGroup
820 for (EndpointGroupId newEpgId : newEpgIds) {
821 EgKey newEgKey = new EgKey(tenantId, newEpgId);
822 Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
825 Set<EpKey> geps = endpointsByGroup.get(newEgKey);
827 geps = new HashSet<>();
830 endpointsByGroup.put(newEgKey, geps);
833 LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
839 notifyEndpointUpdated(newEpKey);
841 notifyEndpointUpdated(oldEpKey);
843 // TODO alagalah NEXt: ensure right notification flags are set.
845 notifyNodeEndpointUpdated(oldLoc, oldEpKey);
847 notifyNodeEndpointUpdated(newLoc, newEpKey);
849 for (EndpointGroupId oldEpgId : oldEpgIds) {
850 EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
851 notifyGroupEndpointUpdated(oldEgKey, oldEpKey);
854 for (EndpointGroupId newEpgId : newEpgIds) {
855 EgKey newEgKey = new EgKey(newEp.getTenant(), newEpgId);
856 notifyGroupEndpointUpdated(newEgKey, newEpKey);
860 // A wrapper class around node, nodeConnector info so we can pass a final
861 // object inside OnSuccess anonymous inner class
862 private static class NodeInfo {
863 NodeConnector nodeConnector;
870 private NodeInfo(NodeConnector nc, Node node) {
871 this.nodeConnector = nc;
875 private Node getNode() {
879 private NodeConnector getNodeConnector() {
880 return this.nodeConnector;
883 public void setNodeConnector(NodeConnector nodeConnector) {
884 this.nodeConnector = nodeConnector;
887 public void setNode(Node node) {