2 * Copyright (c) 2013 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.controller.hosttracker.internal;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Dictionary;
16 import java.util.EnumSet;
17 import java.util.HashSet;
18 import java.util.List;
20 import java.util.Map.Entry;
22 import java.util.Timer;
23 import java.util.TimerTask;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.CopyOnWriteArraySet;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.Future;
32 import org.apache.felix.dm.Component;
33 import org.eclipse.osgi.framework.console.CommandInterpreter;
34 import org.eclipse.osgi.framework.console.CommandProvider;
35 import org.opendaylight.controller.clustering.services.CacheConfigException;
36 import org.opendaylight.controller.clustering.services.CacheExistException;
37 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
38 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
39 import org.opendaylight.controller.clustering.services.IClusterServices;
40 import org.opendaylight.controller.hosttracker.HostIdFactory;
41 import org.opendaylight.controller.hosttracker.IHostId;
42 import org.opendaylight.controller.hosttracker.IHostTrackerShell;
43 import org.opendaylight.controller.hosttracker.IPHostId;
44 import org.opendaylight.controller.hosttracker.IPMacHostId;
45 import org.opendaylight.controller.hosttracker.IfHostListener;
46 import org.opendaylight.controller.hosttracker.IfIptoHost;
47 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
48 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
49 import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
50 import org.opendaylight.controller.sal.core.ConstructionException;
51 import org.opendaylight.controller.sal.core.Edge;
52 import org.opendaylight.controller.sal.core.Host;
53 import org.opendaylight.controller.sal.core.Node;
54 import org.opendaylight.controller.sal.core.NodeConnector;
55 import org.opendaylight.controller.sal.core.Property;
56 import org.opendaylight.controller.sal.core.State;
57 import org.opendaylight.controller.sal.core.Tier;
58 import org.opendaylight.controller.sal.core.UpdateType;
59 import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
60 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
61 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
62 import org.opendaylight.controller.sal.utils.GlobalConstants;
63 import org.opendaylight.controller.sal.utils.HexEncode;
64 import org.opendaylight.controller.sal.utils.NetUtils;
65 import org.opendaylight.controller.sal.utils.NodeCreator;
66 import org.opendaylight.controller.sal.utils.Status;
67 import org.opendaylight.controller.sal.utils.StatusCode;
68 import org.opendaylight.controller.switchmanager.IInventoryListener;
69 import org.opendaylight.controller.switchmanager.ISwitchManager;
70 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
71 import org.opendaylight.controller.switchmanager.Subnet;
72 import org.opendaylight.controller.topologymanager.ITopologyManager;
73 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
74 import org.osgi.framework.BundleContext;
75 import org.osgi.framework.FrameworkUtil;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
80 * @file HostTracker.java This class tracks the location of IP Hosts as to which
81 * Switch, Port, VLAN, they are connected to, as well as their MAC
82 * address. This is done dynamically as well as statically. The dynamic
83 * mechanism consists of listening to ARP messages as well sending ARP
84 * requests. Static mechanism consists of Northbound APIs to add or remove
85 * the hosts from the local database. ARP aging is also implemented to age
86 * out dynamically learned hosts. Interface methods are provided for other
87 * applications to 1. Query the local database for a single host 2. Get a
88 * list of all hosts 3. Get notification if a host is learned/added or
89 * removed the database
94 * HostTracker db key scheme implementation support. Support has been added for
95 * IP only or IP + MAC scheme as of now. User can use either of the schemes
96 * based on the configuration done in config.ini file. By default IP only key
97 * scheme is choosen. The attribute to be set in config.ini is
98 * hosttracker.keyscheme. It could have a value of 0 or 1 as of now. 0 is for IP
99 * only scheme. 1 is for IP + MAC scheme.
104 public class HostTracker implements IfIptoHost, IfHostListener, IHostTrackerShell, ISwitchManagerAware, IInventoryListener,
105 ITopologyManagerAware, ICacheUpdateAware<IHostId, HostNodeConnector>, CommandProvider {
106 static final String ACTIVE_HOST_CACHE = "hosttracker.ActiveHosts";
107 static final String INACTIVE_HOST_CACHE = "hosttracker.InactiveHosts";
108 private static final Logger logger = LoggerFactory.getLogger(HostTracker.class);
109 protected final Set<IHostFinder> hostFinders = new CopyOnWriteArraySet<IHostFinder>();
110 protected ConcurrentMap<IHostId, HostNodeConnector> hostsDB;
112 * Following is a list of hosts which have been requested by NB APIs to be
113 * added, but either the switch or the port is not sup, so they will be
114 * added here until both come up
116 private ConcurrentMap<NodeConnector, HostNodeConnector> inactiveStaticHosts;
117 private final Set<IfNewHostNotify> newHostNotify = Collections.synchronizedSet(new HashSet<IfNewHostNotify>());
119 private ITopologyManager topologyManager;
120 protected IClusterContainerServices clusterContainerService = null;
121 protected ISwitchManager switchManager = null;
123 private Timer arpRefreshTimer;
124 private String containerName = null;
125 private ExecutorService executor;
126 protected boolean stopping;
127 private static boolean hostRefresh = true;
128 private static int hostRetryCount = 5;
129 private String keyScheme = null;
131 private static class ARPPending {
132 protected IHostId hostId;
133 protected short sent_count;
134 protected HostTrackerCallable hostTrackerCallable;
136 public IHostId getHostId() {
140 public short getSent_count() {
144 public HostTrackerCallable getHostTrackerCallable() {
145 return hostTrackerCallable;
148 public void setHostId(IHostId id) {
152 public void setSent_count(short count) {
153 this.sent_count = count;
156 public void setHostTrackerCallable(HostTrackerCallable callable) {
157 hostTrackerCallable = callable;
161 // This list contains the hosts for which ARP requests are being sent
163 ConcurrentMap<IHostId, ARPPending> ARPPendingList;
165 * This list below contains the hosts which were initially in ARPPendingList
166 * above, but ARP response didn't come from there hosts after multiple
167 * attempts over 8 seconds. The assumption is that the response didn't come
168 * back due to one of the following possibilities: 1. The L3 interface
169 * wasn't created for this host in the controller. This would cause
170 * arphandler not to know where to send the ARP 2. The host facing port is
171 * down 3. The IP host doesn't exist or is not responding to ARP requests
173 * Conditions 1 and 2 above can be recovered if ARP is sent when the
174 * relevant L3 interface is added or the port facing host comes up. Whenever
175 * L3 interface is added or host facing port comes up, ARP will be sent to
176 * hosts in this list.
178 * We can't recover from condition 3 above
180 ConcurrentMap<IHostId, ARPPending> failedARPReqList;
182 public HostTracker() {
185 private void startUp() {
186 nonClusterObjectCreate();
192 timer.schedule(new OutStandingARPHandler(), 4000, 4000);
193 executor = Executors.newFixedThreadPool(2);
194 /* ARP Refresh Timer to go off every 5 seconds to implement ARP aging */
195 arpRefreshTimer = new Timer();
196 arpRefreshTimer.schedule(new ARPRefreshHandler(), 5000, 5000);
197 keyScheme = HostIdFactory.getScheme();
198 logger.debug("startUp: Caches created, timers started");
201 private void allocateCache() {
202 if (this.clusterContainerService == null) {
203 logger.error("un-initialized clusterContainerService, can't create cache");
206 logger.debug("Creating Cache for HostTracker");
208 this.clusterContainerService.createCache(ACTIVE_HOST_CACHE,
209 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
210 this.clusterContainerService.createCache(INACTIVE_HOST_CACHE,
211 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
212 } catch (CacheConfigException cce) {
213 logger.error("Cache couldn't be created for HostTracker - check cache mode");
214 } catch (CacheExistException cce) {
215 logger.error("Cache for HostTracker already exists, destroy and recreate");
217 logger.debug("Cache successfully created for HostTracker");
220 @SuppressWarnings({ "unchecked" })
221 private void retrieveCache() {
222 if (this.clusterContainerService == null) {
223 logger.error("un-initialized clusterContainerService, can't retrieve cache");
226 logger.debug("Retrieving cache for HostTrackerAH");
227 hostsDB = (ConcurrentMap<IHostId, HostNodeConnector>) this.clusterContainerService.getCache(ACTIVE_HOST_CACHE);
228 if (hostsDB == null) {
229 logger.error("Cache couldn't be retrieved for HostTracker");
231 logger.debug("Cache was successfully retrieved for HostTracker");
232 logger.debug("Retrieving cache for HostTrackerIH");
233 inactiveStaticHosts = (ConcurrentMap<NodeConnector, HostNodeConnector>) this.clusterContainerService
234 .getCache(INACTIVE_HOST_CACHE);
235 if (inactiveStaticHosts == null) {
236 logger.error("Cache couldn't be retrieved for HostTrackerIH");
238 logger.debug("Cache was successfully retrieved for HostTrackerIH");
241 public void nonClusterObjectCreate() {
242 hostsDB = new ConcurrentHashMap<IHostId, HostNodeConnector>();
243 inactiveStaticHosts = new ConcurrentHashMap<NodeConnector, HostNodeConnector>();
244 ARPPendingList = new ConcurrentHashMap<IHostId, ARPPending>();
245 failedARPReqList = new ConcurrentHashMap<IHostId, ARPPending>();
248 public void shutDown() {
251 public void setnewHostNotify(IfNewHostNotify obj) {
252 this.newHostNotify.add(obj);
255 public void unsetnewHostNotify(IfNewHostNotify obj) {
256 this.newHostNotify.remove(obj);
259 public void setArpHandler(IHostFinder hostFinder) {
260 this.hostFinders.add(hostFinder);
263 public void unsetArpHandler(IHostFinder hostFinder) {
264 logger.debug("Arp Handler Service removed!");
265 this.hostFinders.remove(hostFinder);
268 public void setTopologyManager(ITopologyManager s) {
269 this.topologyManager = s;
272 public void unsetTopologyManager(ITopologyManager s) {
273 if (this.topologyManager == s) {
274 logger.debug("Topology Manager Service removed!");
275 this.topologyManager = null;
279 private boolean hostExists(HostNodeConnector host) {
280 IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress());
281 HostNodeConnector lhost = hostsDB.get(id);
282 return host.equals(lhost);
285 private HostNodeConnector getHostFromOnActiveDB(IHostId id) {
286 return hostsDB.get(id);
289 private Entry<NodeConnector, HostNodeConnector> getHostFromInactiveDB(IHostId id) {
290 for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
291 HostNodeConnector hnc = entry.getValue();
292 IHostId cmpId = HostIdFactory.create(hnc.getNetworkAddress(), hnc.getDataLayerAddress());
293 if (cmpId.equals(id)) {
294 logger.debug("getHostFromInactiveDB(): Inactive Host found for ID:{} ", decodeIPFromId(id));
298 logger.debug("getHostFromInactiveDB() Inactive Host Not found for ID: {}", decodeIPFromId(id));
302 private void removeHostFromInactiveDB(IHostId id) {
303 NodeConnector nodeConnector = null;
304 for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
305 HostNodeConnector hnc = entry.getValue();
306 IHostId cmpId = HostIdFactory.create(hnc.getNetworkAddress(), hnc.getDataLayerAddress());
307 if (cmpId.equals(id)) {
308 nodeConnector = entry.getKey();
312 if (nodeConnector != null) {
313 inactiveStaticHosts.remove(nodeConnector);
314 logger.debug("removeHostFromInactiveDB(): Host Removed for IP: {}", decodeIPFromId(id));
317 logger.debug("removeHostFromInactiveDB(): Host Not found for IP: {}", decodeIPFromId(id));
320 protected boolean hostMoved(HostNodeConnector host) {
321 IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress());
322 if (hostQuery(id) != null) {
329 public HostNodeConnector hostQuery(IHostId id) {
330 return hostsDB.get(id);
334 public Future<HostNodeConnector> discoverHost(IHostId id) {
335 if (executor == null) {
336 logger.debug("discoverHost: Null executor");
339 Callable<HostNodeConnector> worker = new HostTrackerCallable(this, id);
340 Future<HostNodeConnector> submit = executor.submit(worker);
345 public HostNodeConnector hostFind(IHostId id) {
347 * Sometimes at boot with containers configured in the startup we hit
348 * this path (from TIF) when hostFinder has not been set yet Caller
349 * already handles the null return
352 if (hostFinders.isEmpty()) {
353 logger.debug("No available host finders, exiting hostFind()");
357 HostNodeConnector host = hostQuery(id);
359 logger.debug("hostFind(): Host found for IP: {}", id);
363 /* Add this host to ARPPending List for any potential retries */
365 addToARPPendingList(id);
366 logger.debug("hostFind(): Host Not Found for IP: {}, Inititated Host Discovery ...", id);
368 /* host is not found, initiate a discovery */
369 for (IHostFinder hf : hostFinders) {
370 InetAddress addr = decodeIPFromId(id);
377 public Set<HostNodeConnector> getAllHosts() {
378 Set<HostNodeConnector> allHosts = new HashSet<HostNodeConnector>(hostsDB.values());
383 public Set<HostNodeConnector> getActiveStaticHosts() {
384 Set<HostNodeConnector> list = new HashSet<HostNodeConnector>();
385 for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
386 HostNodeConnector host = entry.getValue();
387 if (host.isStaticHost()) {
395 public Set<HostNodeConnector> getInactiveStaticHosts() {
396 Set<HostNodeConnector> list = new HashSet<HostNodeConnector>(inactiveStaticHosts.values());
400 private void addToARPPendingList(IHostId id) {
401 ARPPending arphost = new ARPPending();
403 arphost.setHostId(id);
404 arphost.setSent_count((short) 1);
405 ARPPendingList.put(id, arphost);
406 logger.debug("Host Added to ARPPending List, IP: {}", decodeIPFromId(id));
410 public void setCallableOnPendingARP(IHostId id, HostTrackerCallable callable) {
412 for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
413 arphost = entry.getValue();
414 if (arphost.getHostId().equals(id)) {
415 arphost.setHostTrackerCallable(callable);
420 private void processPendingARPReqs(IHostId id) {
423 if ((arphost = ARPPendingList.remove(id)) != null) {
424 // Remove the arphost from ARPPendingList as it has been learned now
425 logger.debug("Host Removed from ARPPending List, IP: {}", id);
426 HostTrackerCallable htCallable = arphost.getHostTrackerCallable();
427 if (htCallable != null) {
434 * It could have been a host from the FailedARPReqList
437 if (failedARPReqList.containsKey(id)) {
438 failedARPReqList.remove(id);
439 logger.debug("Host Removed from FailedARPReqList List, IP: {}", decodeIPFromId(id));
444 private void learnNewHost(HostNodeConnector host) {
445 IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress());
446 host.initArpSendCountDown();
447 HostNodeConnector rHost = hostsDB.putIfAbsent(id, host);
449 // Another host is already learned for this IP address, replace it
450 replaceHost(id, rHost, host);
452 logger.debug("New Host Learned: MAC: {} IP: {}", HexEncode.bytesToHexString(host
453 .getDataLayerAddressBytes()), host.getNetworkAddress().getHostAddress());
457 private void replaceHost(IHostId id, HostNodeConnector removedHost, HostNodeConnector newHost) {
458 // Ignore ARP messages from internal nodes
459 NodeConnector newHostNc = newHost.getnodeConnector();
460 boolean newHostIsInternal = topologyManager.isInternal(newHostNc);
461 if (newHostIsInternal) {
465 newHost.initArpSendCountDown();
467 if (hostsDB.replace(id, removedHost, newHost)) {
468 logger.debug("Host move occurred: Old Host IP:{}, New Host IP: {}", removedHost.getNetworkAddress()
469 .getHostAddress(), newHost.getNetworkAddress().getHostAddress());
470 logger.debug("Old Host MAC: {}, New Host MAC: {}",
471 HexEncode.bytesToHexString(removedHost.getDataLayerAddressBytes()),
472 HexEncode.bytesToHexString(newHost.getDataLayerAddressBytes()));
473 // Display the Old and New HostNodeConnectors also
474 logger.debug("Old {}, New {}", removedHost, newHost);
477 * Host replacement has failed, do the recovery
479 hostsDB.put(id, newHost);
480 logger.error("Host replacement failed. Overwrite the host. Replaced Host: {}, New Host: {}", removedHost,
483 notifyHostLearnedOrRemoved(removedHost, false);
484 notifyHostLearnedOrRemoved(newHost, true);
485 if (!newHost.isStaticHost()) {
486 processPendingARPReqs(id);
491 private void removeKnownHost(IHostId key) {
492 HostNodeConnector host = hostsDB.get(key);
494 logger.debug("Removing Host: IP:{}", host.getNetworkAddress().getHostAddress());
497 logger.error("removeKnownHost(): Host for IP address {} not found in hostsDB", decodeIPFromId(key));
501 private class NotifyHostThread extends Thread {
503 private final HostNodeConnector host;
505 public NotifyHostThread(HostNodeConnector h) {
511 HostNodeConnector removedHost = null;
512 InetAddress networkAddr = host.getNetworkAddress();
513 IHostId id = HostIdFactory.create(networkAddr, host.getDataLayerAddress());
514 /* Check for Host Move case */
515 if (hostMoved(host)) {
517 * Host has been moved from one location (switch,port, MAC, or
518 * VLAN) to another. Replace the existing host and its previous
519 * location parameters with new information, and notify the
520 * applications listening to host move.
523 removedHost = hostsDB.get(id);
524 if (removedHost != null) {
525 replaceHost(id, removedHost, host);
528 logger.error("Host to be removed not found in hostsDB");
535 /* check if there is an outstanding request for this host */
536 processPendingARPReqs(id);
537 notifyHostLearnedOrRemoved(host, true);
542 public void hostListener(HostNodeConnector host) {
543 logger.debug("Received for Host: IP {}, MAC {}, {}", host.getNetworkAddress().getHostAddress(),
544 HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host);
545 if (hostExists(host)) {
546 IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress());
547 HostNodeConnector existinghost = hostsDB.get(id);
548 existinghost.initArpSendCountDown();
551 hostsDB.put(id, existinghost);
552 logger.debug("hostListener returned without adding the host");
555 new NotifyHostThread(host).start();
558 // Notify whoever is interested that a new host was learned (dynamically or
560 private void notifyHostLearnedOrRemoved(HostNodeConnector host, boolean add) {
561 // Update listeners if any
562 if (newHostNotify != null) {
563 logger.debug("Notifying Applications for Host {} Being {}", host.getNetworkAddress().getHostAddress(),
564 add ? "Added" : "Deleted");
565 synchronized (this.newHostNotify) {
566 for (IfNewHostNotify ta : newHostNotify) {
569 ta.notifyHTClient(host);
571 ta.notifyHTClientHostRemoved(host);
573 } catch (Exception e) {
574 logger.error("Exception on new host notification", e);
579 logger.error("notifyHostLearnedOrRemoved(): New host notify is null");
582 // Topology update is for some reason outside of listeners registry
584 Node node = host.getnodeconnectorNode();
586 NodeConnector p = host.getnodeConnector();
588 DataLinkAddress dla = new EthernetAddress(host.getDataLayerAddressBytes());
589 h = new Host(dla, host.getNetworkAddress());
590 } catch (ConstructionException ce) {
595 if (topologyManager != null && p != null && h != null) {
596 logger.debug("Notifying Topology Manager for Host {} Being {}", h.getNetworkAddress().getHostAddress(),
597 add ? "Added" : "Deleted");
599 Tier tier = new Tier(1);
600 switchManager.setNodeProp(node, tier);
601 topologyManager.updateHostLink(p, h, UpdateType.ADDED, null);
603 // No need to reset the tiering if no other hosts are currently
605 // If this switch was discovered to be an access switch, it
606 // still is even if the host is down
607 Tier tier = new Tier(0);
608 switchManager.setNodeProp(node, tier);
609 topologyManager.updateHostLink(p, h, UpdateType.REMOVED, null);
615 * When a new Host is learnt by the hosttracker module, it places the
616 * directly connected Node in Tier-1 & using this function, updates the Tier
617 * value for all other Nodes in the network hierarchy.
619 * This is a recursive function and it takes care of updating the Tier value
620 * for all the connected and eligible Nodes.
623 * Node that represents one of the Vertex in the Topology Graph.
625 * The Tier on which n belongs
627 @SuppressWarnings("unused")
628 private void updateSwitchTiers(Node n, int currentTier) {
629 Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
630 if (ndlinks == null) {
631 logger.debug("updateSwitchTiers(): ndlinks null for Node: {}, Tier:{}", n, currentTier);
634 Set<Edge> links = ndlinks.get(n);
636 logger.debug("updateSwitchTiers(): links null for ndlinks:{}", ndlinks);
639 ArrayList<Node> needsVisiting = new ArrayList<Node>();
640 for (Edge lt : links) {
641 if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
642 // We don't want to work on Node that are not openflow
646 Node dstNode = lt.getHeadNodeConnector().getNode();
647 if (switchNeedsTieringUpdate(dstNode, currentTier + 1)) {
648 Tier t = new Tier(currentTier + 1);
649 switchManager.setNodeProp(dstNode, t);
650 needsVisiting.add(dstNode);
655 * Due to the nature of the problem, having a separate loop for nodes
656 * that needs visiting provides a decent walk optimization.
658 for (Node node : needsVisiting) {
659 updateSwitchTiers(node, currentTier + 1);
664 * Internal convenience routine to check the eligibility of a Switch for a
665 * Tier update. Any Node with Tier=0 or a Tier value that is greater than
666 * the new Tier Value is eligible for the update.
669 * Node for which the Tier update eligibility is checked
672 * @return <code>true</code> if the Node is eligible for Tier Update
673 * <code>false</code> otherwise
676 private boolean switchNeedsTieringUpdate(Node n, int tier) {
678 logger.error("switchNeedsTieringUpdate(): Null node for tier: {}", tier);
682 * Node could have gone down
684 if (!switchManager.getNodes().contains(n)) {
687 // This is the case where Tier was never set for this node
688 Tier t = (Tier) switchManager.getNodeProp(n, Tier.TierPropName);
692 if (t.getValue() == 0) {
694 } else if (t.getValue() > tier) {
701 * Internal convenience routine to clear all the Tier values to 0. This
702 * cleanup is performed during cases such as Topology Change where the
703 * existing Tier values might become incorrect
705 @SuppressWarnings("unused")
706 private void clearTiers() {
707 Set<Node> nodes = null;
708 if (switchManager == null) {
709 logger.error("clearTiers(): Null switchManager");
712 nodes = switchManager.getNodes();
714 for (Node n : nodes) {
715 Tier t = new Tier(0);
716 switchManager.setNodeProp(n, t);
721 * Internal convenience routine to print the hierarchies of switches.
723 @SuppressWarnings("unused")
724 private void logHierarchies(ArrayList<ArrayList<String>> hierarchies) {
725 String hierarchyString = null;
727 for (ArrayList<String> hierarchy : hierarchies) {
728 StringBuffer buf = new StringBuffer();
729 buf.append("Hierarchy#").append(num).append(" : ");
730 for (String switchName : hierarchy) {
731 buf.append(switchName).append("/");
733 logger.debug("{} -> {}", getContainerName(), buf);
739 * getHostNetworkHierarchy is the Back-end routine for the North-Bound API
740 * that returns the Network Hierarchy for a given Host. This API is
741 * typically used by applications like Hadoop for Rack Awareness
745 * IP-Address of the host/node.
746 * @return Network Hierarchies represented by an Array of Array (of
747 * Switch-Ids as String).
750 public List<List<String>> getHostNetworkHierarchy(IHostId id) {
751 HostNodeConnector host = hostQuery(id);
756 List<List<String>> hierarchies = new ArrayList<List<String>>();
757 ArrayList<String> currHierarchy = new ArrayList<String>();
758 hierarchies.add(currHierarchy);
760 Node node = host.getnodeconnectorNode();
761 updateCurrentHierarchy(node, currHierarchy, hierarchies);
766 * dpidToHostNameHack is a hack function for Cisco Live Hadoop Demo. Mininet
767 * is used as the network for Hadoop Demos & in order to give a meaningful
768 * rack-awareness switch names, the DPID is organized in ASCII Characters
769 * and retrieved as string.
773 * @return Ascii String represented by the DPID.
775 private String dpidToHostNameHack(long dpid) {
776 String hex = Long.toHexString(dpid);
778 StringBuffer sb = new StringBuffer();
780 for (int i = 0; i < hex.length(); i++) {
781 result = (int) ((dpid >> (i * 8)) & 0xff);
788 sb.append(String.format("%c", result));
790 return sb.reverse().toString();
794 * A convenient recursive routine to obtain the Hierarchy of Switches.
797 * Current Node in the Recursive routine.
798 * @param currHierarchy
799 * Array of Nodes that make this hierarchy on which the Current
801 * @param fullHierarchy
802 * Array of multiple Hierarchies that represent a given host.
804 @SuppressWarnings("unchecked")
805 private void updateCurrentHierarchy(Node node, ArrayList<String> currHierarchy, List<List<String>> fullHierarchy) {
806 currHierarchy.add(dpidToHostNameHack((Long) node.getID()));
807 // Shallow copy as required
808 ArrayList<String> currHierarchyClone = (ArrayList<String>) currHierarchy.clone();
810 Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
811 if (ndlinks == null) {
812 logger.debug("updateCurrentHierarchy(): topologyManager returned null ndlinks for node: {}", node);
815 Node n = NodeCreator.createOFNode((Long) node.getID());
816 Set<Edge> links = ndlinks.get(n);
818 logger.debug("updateCurrentHierarchy(): Null links for ndlinks");
821 for (Edge lt : links) {
822 if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
823 // We don't want to work on Node that are not openflow
827 Node dstNode = lt.getHeadNodeConnector().getNode();
829 Tier nodeTier = (Tier) switchManager.getNodeProp(node, Tier.TierPropName);
831 * If the host is directly attached to the src node, then the node
832 * should have been assigned the "Access" tier in
833 * notifyHostLearnedOrRemoved. If not, it would be assigned
834 * "Unknown" tier. Thus the tier of host attached node cannot be
835 * null. If the src node here, is the next node in the hierarchy of
836 * the nodes, then its tier cannot be null
839 Tier dstNodeTier = (Tier) switchManager.getNodeProp(dstNode, Tier.TierPropName);
841 * Skip if the tier of the destination node is null
843 if (dstNodeTier == null) {
846 if (dstNodeTier.getValue() > nodeTier.getValue()) {
847 ArrayList<String> buildHierarchy = currHierarchy;
848 if (currHierarchy.size() > currHierarchyClone.size()) {
849 // Shallow copy as required
850 buildHierarchy = (ArrayList<String>) currHierarchyClone.clone();
851 fullHierarchy.add(buildHierarchy);
853 updateCurrentHierarchy(dstNode, buildHierarchy, fullHierarchy);
858 private void debugEdgeUpdate(Edge e, UpdateType type, Set<Property> props) {
860 Short srcPort = null;
862 Short dstPort = null;
863 boolean added = false;
864 String srcType = null;
865 String dstType = null;
867 if (e == null || type == null) {
868 logger.error("Edge or Update type are null!");
871 srcType = e.getTailNodeConnector().getType();
872 dstType = e.getHeadNodeConnector().getType();
874 if (srcType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
875 logger.debug("Skip updates for {}", e);
879 if (!srcType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
880 logger.debug("For now we cannot handle updates for non-openflow nodes");
884 if (dstType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
885 logger.debug("Skip updates for {}", e);
889 if (!dstType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
890 logger.debug("For now we cannot handle updates for non-openflow nodes");
894 // At this point we know we got an openflow update, so
895 // lets fill everything accordingly.
896 srcNid = (Long) e.getTailNodeConnector().getNode().getID();
897 srcPort = (Short) e.getTailNodeConnector().getID();
898 dstNid = (Long) e.getHeadNodeConnector().getNode().getID();
899 dstPort = (Short) e.getHeadNodeConnector().getID();
901 // Now lets update the added flag
912 logger.debug("HostTracker Topology linkUpdate handling src:{}[port {}] dst:{}[port {}] added: {}",
913 new Object[] { srcNid, srcPort, dstNid, dstPort, added });
917 public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
918 if (logger.isDebugEnabled()) {
919 for (TopoEdgeUpdate topoEdgeUpdate : topoedgeupdateList) {
920 Edge e = topoEdgeUpdate.getEdge();
921 Set<Property> p = topoEdgeUpdate.getProperty();
922 UpdateType type = topoEdgeUpdate.getUpdateType();
924 debugEdgeUpdate(e, type, p);
930 public void subnetNotify(Subnet sub, boolean add) {
931 logger.debug("Received subnet notification: {} add={}", sub, add);
933 for (Entry<IHostId, ARPPending> entry : failedARPReqList.entrySet()) {
935 arphost = entry.getValue();
936 if (hostFinders.isEmpty()) {
937 logger.debug("ARPHandler Services are not available on subnet addition");
940 logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", decodeIPFromId(arphost.getHostId()));
941 for (IHostFinder hf : hostFinders) {
942 hf.find(decodeIPFromId(arphost.getHostId()));
949 * This thread runs every 4 seconds
952 class OutStandingARPHandler extends TimerTask {
960 for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
961 arphost = entry.getValue();
963 if (hostsDB.containsKey(arphost.getHostId())) {
964 // this host is already learned, shouldn't be in
966 // Remove it and continue
967 logger.warn("Learned Host {} found in ARPPendingList", decodeIPFromId(arphost.getHostId()));
968 ARPPendingList.remove(entry.getKey());
971 if (arphost.getSent_count() < hostRetryCount) {
973 * No reply has been received of first ARP Req, send the
974 * next one. Before sending the ARP, check if ARPHandler
975 * is available or not
977 if (hostFinders.isEmpty()) {
978 logger.warn("ARPHandler Services are not available for Outstanding ARPs");
981 for (IHostFinder hf : hostFinders) {
982 hf.find(decodeIPFromId(arphost.getHostId()));
984 arphost.sent_count++;
985 logger.debug("ARP Sent from ARPPending List, IP: {}", decodeIPFromId(arphost.getHostId()));
986 } else if (arphost.getSent_count() >= hostRetryCount) {
988 * ARP requests have been sent without receiving a
989 * reply, remove this from the pending list
991 ARPPendingList.remove(entry.getKey());
993 "ARP reply not received after multiple attempts, removing from Pending List IP: {}",
994 decodeIPFromId(arphost.getHostId()));
996 * Add this host to a different list which will be
997 * processed on link up events
999 logger.debug("Adding the host to FailedARPReqList IP: {}", decodeIPFromId(arphost.getHostId()));
1000 failedARPReqList.put(entry.getKey(), arphost);
1003 logger.error("Inavlid arp_sent count for entry: {}", entry);
1006 } catch (IllegalStateException e) {
1007 logger.debug("IllegalStateException Received by OutStandingARPHandler from: {}", e.getMessage());
1012 private class ARPRefreshHandler extends TimerTask {
1015 if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
1023 * The host probe procedure is turned off
1027 if (hostsDB == null) {
1028 /* hostsDB is not allocated yet */
1029 logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
1033 for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
1034 HostNodeConnector host = entry.getValue();
1035 if (host.isStaticHost()) {
1036 /* this host was learned via API3, don't age it out */
1040 short arp_cntdown = host.getArpSendCountDown();
1042 if (arp_cntdown > hostRetryCount) {
1043 host.setArpSendCountDown(arp_cntdown);
1044 } else if (arp_cntdown <= 0) {
1046 * No ARP Reply received in last 2 minutes, remove this
1047 * host and inform applications
1049 removeKnownHost(entry.getKey());
1050 notifyHostLearnedOrRemoved(host, false);
1051 } else if (arp_cntdown <= hostRetryCount) {
1053 * Use the services of arphandler to check if host is
1056 if (logger.isTraceEnabled()) {
1058 "ARP Probing ({}) for {}({})",
1059 new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
1060 HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
1062 host.setArpSendCountDown(arp_cntdown);
1063 if (hostFinders.isEmpty()) {
1065 * If hostfinder is not available, then can't send
1066 * the probe. However, continue the age out the
1067 * hosts since we don't know if the host is indeed
1070 logger.trace("ARPHandler is not avaialable, can't send the probe");
1073 for (IHostFinder hf : hostFinders) {
1078 } catch (IllegalStateException e) {
1079 logger.debug("IllegalStateException Received by ARPRefreshHandler from: {}", e.getMessage());
1085 * Inform the controller IP to MAC binding of a host and its connectivity to
1086 * an openflow switch in terms of Node, port, and VLAN.
1088 * @param networkAddr
1089 * IP address of the host
1091 * Address MAC address of the host
1093 * NodeConnector to which host is connected
1095 * Port of the switch to which host is connected
1097 * Vlan of which this host is member of
1099 * @return Status The status object as described in {@code Status}
1100 * indicating the result of this action.
1103 protected Status addStaticHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1104 if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1105 return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1109 return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1111 HostNodeConnector host = null;
1113 host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1114 IHostId id = HostIdFactory.create(networkAddr, new EthernetAddress(dataLayerAddress));
1115 if (hostExists(host)) {
1116 // This host is already learned either via ARP or through a
1117 // northbound request
1118 HostNodeConnector transHost = hostsDB.get(networkAddr);
1119 transHost.setStaticHost(true);
1120 return new Status(StatusCode.SUCCESS);
1123 if (hostsDB.get(id) != null) {
1124 // There is already a host with this IP address (but behind
1125 // a different (switch, port, vlan) tuple. Return an error
1126 return new Status(StatusCode.CONFLICT, "Host with this IP already exists.");
1128 host.setStaticHost(true);
1130 * Check if the nc is an ISL port
1132 if (topologyManager != null) {
1133 if (topologyManager.isInternal(nc)) {
1134 return new Status(StatusCode.BADREQUEST, "Cannot add host on ISL port");
1138 * Before adding host, Check if the switch and the port have already
1141 if (switchManager.isNodeConnectorEnabled(nc)) {
1143 processPendingARPReqs(id);
1144 notifyHostLearnedOrRemoved(host, true);
1146 inactiveStaticHosts.put(nc, host);
1147 logger.debug("Switch or switchport is not up, adding host {} to inactive list",
1148 networkAddr.getHostName());
1150 return new Status(StatusCode.SUCCESS);
1151 } catch (ConstructionException e) {
1152 logger.error("", e);
1153 return new Status(StatusCode.INTERNALERROR, "Host could not be created");
1159 * Update the controller IP to MAC binding of a host and its connectivity to
1160 * an openflow switch in terms of switch id, switch port, and VLAN.
1162 * @param networkAddr
1163 * IP address of the host
1165 * Address MAC address of the host
1167 * NodeConnector to which host is connected
1169 * Port of the switch to which host is connected
1171 * Vlan of which this host is member of
1173 * @return Status The status object as described in {@code Status}
1174 * indicating the result of this action.
1176 public Status updateHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1177 HostNodeConnector tobeUpdatedHost;
1178 HostNodeConnector host = null;
1180 if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1181 return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1185 return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1189 host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1190 if (hostExists(host)) {
1191 return new Status(StatusCode.BADREQUEST, "Host already exists");
1194 IHostId id = HostIdFactory.create(networkAddr, new EthernetAddress(dataLayerAddress));
1196 if ((tobeUpdatedHost = hostsDB.get(networkAddr)) != null) {
1197 if (hostsDB.replace(id, tobeUpdatedHost, host)) {
1198 logger.debug("Host replaced from hostsDB. Old host: {} New Host: {}", tobeUpdatedHost, host);
1199 notifyHostLearnedOrRemoved(tobeUpdatedHost, false);
1200 notifyHostLearnedOrRemoved(host, true);
1201 return new Status(StatusCode.SUCCESS);
1203 logger.error("Static host replacement failed from hostsDB, Replaced Host: {}, New Host: {}",
1204 tobeUpdatedHost, host);
1205 return new Status(StatusCode.INTERNALERROR,
1206 "Host Replacement Failed due to presence of another host with same IP");
1210 // Check if the host exists in inactive hosts database
1211 if ((tobeUpdatedHost = inactiveStaticHosts.get(nc)) != null) {
1212 if (inactiveStaticHosts.replace(nc, tobeUpdatedHost, host)) {
1213 logger.debug("Host replaced from inactive hostsDB. Old host: {} New Host: {}", tobeUpdatedHost,
1215 return new Status(StatusCode.SUCCESS);
1217 logger.error("Static host replacement failed, Replaced Host: {}, New Host: {}", tobeUpdatedHost,
1219 return new Status(StatusCode.INTERNALERROR,
1220 "Host Replacement Failed due to presence of another host with same IP");
1224 // Host doesn't exist
1225 return new Status(StatusCode.BADREQUEST, "Host doesn't exists, can't update");
1226 } catch (ConstructionException e) {
1227 logger.error("", e);
1228 return new Status(StatusCode.INTERNALERROR, "host object creation failure");
1233 * Remove from the controller IP to MAC binding of a host and its
1234 * connectivity to an openflow switch
1236 * @param networkAddr
1237 * IP address of the host
1239 * @return boolean true if the host was removed successfully, false
1243 public Status removeStaticHostReq(InetAddress networkAddress, DataLinkAddress mac) {
1244 // Check if host is in active hosts database
1245 IHostId id = HostIdFactory.create(networkAddress, mac);
1246 HostNodeConnector host = getHostFromOnActiveDB(id);
1249 if (!host.isStaticHost()) {
1250 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1252 // Remove and notify
1253 notifyHostLearnedOrRemoved(host, false);
1254 removeKnownHost(id);
1255 return new Status(StatusCode.SUCCESS, null);
1258 // Check if host is in inactive hosts database
1259 Entry<NodeConnector, HostNodeConnector> entry = getHostFromInactiveDB(id);
1260 if (entry != null) {
1261 host = entry.getValue();
1263 if (!host.isStaticHost()) {
1264 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1266 this.removeHostFromInactiveDB(id);
1267 return new Status(StatusCode.SUCCESS, null);
1270 // Host is neither in active nor inactive hosts database
1271 return new Status(StatusCode.NOTFOUND, "Host does not exist");
1275 public void modeChangeNotify(Node node, boolean proactive) {
1276 logger.debug("Set Switch {} Mode to {}", node.getID(), proactive);
1280 public void notifyNode(Node node, UpdateType type, Map<String, Property> propMap) {
1287 logger.debug("Received removed node {}", node);
1288 for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
1289 HostNodeConnector host = entry.getValue();
1290 if (host.getnodeconnectorNode().equals(node)) {
1291 logger.debug("Node: {} is down, remove from Hosts_DB", node);
1292 removeKnownHost(entry.getKey());
1293 notifyHostLearnedOrRemoved(host, false);
1303 public void notifyNodeConnector(NodeConnector nodeConnector, UpdateType type, Map<String, Property> propMap) {
1304 if (nodeConnector == null) {
1316 State state = (State) propMap.get(State.StatePropName);
1317 if ((state != null) && (state.getValue() == State.EDGE_UP)) {
1326 handleNodeConnectorStatusUp(nodeConnector);
1328 handleNodeConnectorStatusDown(nodeConnector);
1333 public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan) {
1335 InetAddress ip = InetAddress.getByName(networkAddress);
1337 if (vlan != null && !vlan.isEmpty()) {
1338 vl = Short.decode(vlan);
1339 if (vl < 1 || vl > 4095) {
1340 return new Status(StatusCode.BADREQUEST, "Host vlan out of range [1 - 4095]");
1344 return addStaticHostReq(ip, HexEncode.bytesFromHexString(dataLayerAddress), nc, vl);
1346 } catch (UnknownHostException e) {
1347 logger.debug("Invalid host IP specified when adding static host", e);
1348 return new Status(StatusCode.BADREQUEST, "Invalid Host IP Address");
1349 } catch (NumberFormatException nfe) {
1350 logger.debug("Invalid host vlan or MAC specified when adding static host", nfe);
1351 return new Status(StatusCode.BADREQUEST, "Invalid Host vLan/MAC");
1356 public Status removeStaticHost(String networkAddress) {
1358 if ((keyScheme != null) && (!keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) {
1359 return new Status(StatusCode.NOTALLOWED, "Host DB Key scheme used is not IP only scheme.");
1361 InetAddress address = InetAddress.getByName(networkAddress);
1362 return removeStaticHostReq(address, null);
1363 } catch (UnknownHostException e) {
1364 logger.debug("Invalid IP Address when trying to remove host", e);
1365 return new Status(StatusCode.BADREQUEST, "Invalid IP Address when trying to remove host");
1370 public Status removeStaticHostUsingIPAndMac(String networkAddress, String macAddress) {
1372 if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) {
1373 return new Status(StatusCode.NOTALLOWED, "Host DB Key scheme used is not IP only scheme.");
1375 InetAddress address = InetAddress.getByName(networkAddress);
1376 DataLinkAddress mac = new EthernetAddress(HexEncode.bytesFromHexString(macAddress));
1377 return removeStaticHostReq(address, mac);
1378 } catch (UnknownHostException e) {
1379 logger.debug("Invalid IP Address when trying to remove host", e);
1380 return new Status(StatusCode.BADREQUEST, "Invalid IP Address when trying to remove host");
1381 } catch (ConstructionException e) {
1382 // TODO Auto-generated catch block
1383 e.printStackTrace();
1384 return new Status(StatusCode.BADREQUEST, "Invalid Input parameters have been passed.");
1388 private InetAddress decodeIPFromId(IHostId id) {
1389 if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) {
1390 IPHostId ipId = (IPHostId) id;
1391 return (ipId.getIpAddress());
1392 } else if ((keyScheme != null) && (keyScheme.equals(HostIdFactory.IP_MAC_KEY_SCHEME))) {
1393 IPMacHostId ipMacId = (IPMacHostId) id;
1394 return (ipMacId.getIpAddress());
1399 private DataLinkAddress decodeMacFromId(IHostId id) {
1400 if ((keyScheme != null) && (!keyScheme.equals(HostIdFactory.DEFAULT_IP_KEY_SCHEME))) {
1401 IPMacHostId ipMacId = (IPMacHostId) id;
1402 return (ipMacId.getMacAddr());
1408 private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
1410 HostNodeConnector host = null;
1412 logger.trace("handleNodeConnectorStatusUp {}", nodeConnector);
1414 for (Entry<IHostId, ARPPending> entry : failedARPReqList.entrySet()) {
1415 arphost = entry.getValue();
1416 logger.trace("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostId());
1417 if (hostFinders.isEmpty()) {
1418 logger.warn("ARPHandler is not available at interface up");
1419 logger.warn("Since this event is missed, host(s) connected to interface {} may not be discovered",
1424 // Send a broadcast ARP only on the interface which just came up.
1425 // Use hostFinder's "probe" method
1427 byte[] dataLayerAddress = NetUtils.getBroadcastMACAddr();
1428 host = new HostNodeConnector(dataLayerAddress, decodeIPFromId(arphost.getHostId()), nodeConnector,
1430 for (IHostFinder hf : hostFinders) {
1433 } catch (ConstructionException e) {
1434 logger.debug("HostNodeConnector couldn't be created for Host: {}, NodeConnector: {}",
1435 arphost.getHostId(), nodeConnector);
1436 logger.error("", e);
1440 host = inactiveStaticHosts.get(nodeConnector);
1442 inactiveStaticHosts.remove(nodeConnector);
1444 IHostId id = HostIdFactory.create(host.getNetworkAddress(), host.getDataLayerAddress());
1445 processPendingARPReqs(id);
1446 notifyHostLearnedOrRemoved(host, true);
1450 private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
1451 logger.trace("handleNodeConnectorStatusDown {}", nodeConnector);
1453 for (Entry<IHostId, HostNodeConnector> entry : hostsDB.entrySet()) {
1454 HostNodeConnector host = entry.getValue();
1455 if (host.getnodeConnector().equals(nodeConnector)) {
1456 logger.debug(" NodeConnector: {} is down, remove from Hosts_DB", nodeConnector);
1457 removeKnownHost(entry.getKey());
1458 notifyHostLearnedOrRemoved(host, false);
1463 void setClusterContainerService(IClusterContainerServices s) {
1464 logger.debug("Cluster Service set");
1465 this.clusterContainerService = s;
1468 void unsetClusterContainerService(IClusterContainerServices s) {
1469 if (this.clusterContainerService == s) {
1470 logger.debug("Cluster Service removed!");
1471 this.clusterContainerService = null;
1475 void setSwitchManager(ISwitchManager s) {
1476 logger.debug("SwitchManager set");
1477 this.switchManager = s;
1480 void unsetSwitchManager(ISwitchManager s) {
1481 if (this.switchManager == s) {
1482 logger.debug("SwitchManager removed!");
1483 this.switchManager = null;
1487 public String getContainerName() {
1488 if (containerName == null) {
1489 return GlobalConstants.DEFAULT.toString();
1491 return containerName;
1495 * Function called by the dependency manager when all the required
1496 * dependencies are satisfied
1499 void init(Component c) {
1500 Dictionary<?, ?> props = c.getServiceProperties();
1501 if (props != null) {
1502 this.containerName = (String) props.get("containerName");
1503 logger.debug("Running containerName: {}", this.containerName);
1505 // In the Global instance case the containerName is empty
1506 this.containerName = "";
1510 logger.debug("key Scheme in hosttracker is {}", keyScheme);
1514 * Function called by the dependency manager when at least one dependency
1515 * become unsatisfied or when the component is shutting down because for
1516 * example bundle is being stopped.
1523 * Function called by dependency manager after "init ()" is called and after
1524 * the services provided by the class are registered in the service registry
1528 registerWithOSGIConsole();
1532 * Function called by the dependency manager before the services exported by
1533 * the component are unregistered, this will be followed by a "destroy ()"
1542 arpRefreshTimer.cancel();
1544 executor.shutdownNow();
1548 public void edgeOverUtilized(Edge edge) {
1553 public void edgeUtilBackToNormal(Edge edge) {
1558 public void entryCreated(IHostId key, String cacheName, boolean originLocal) {
1562 processPendingARPReqs(key);
1566 public void entryUpdated(IHostId key, HostNodeConnector new_value, String cacheName, boolean originLocal) {
1570 public void entryDeleted(IHostId key, String cacheName, boolean originLocal) {
1573 private void registerWithOSGIConsole() {
1574 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
1575 bundleContext.registerService(CommandProvider.class.getName(), this, null);
1579 public String getHelp() {
1583 public void _dumpPendingARPReqList(CommandInterpreter ci) {
1585 for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
1586 arphost = entry.getValue();
1587 ci.println(arphost.getHostId().toString());
1591 public void _dumpFailedARPReqList(CommandInterpreter ci) {
1593 for (Entry<IHostId, ARPPending> entry : failedARPReqList.entrySet()) {
1594 arphost = entry.getValue();
1595 ci.println(arphost.getHostId().toString());
1600 public HostNodeConnector hostFind(InetAddress addr) {
1601 IHostId id = HostIdFactory.create(addr, null);
1602 return (hostFind(id));
1606 public HostNodeConnector hostQuery(InetAddress addr) {
1607 IHostId id = HostIdFactory.create(addr, null);
1608 return (hostQuery(id));
1612 public Future<HostNodeConnector> discoverHost(InetAddress addr) {
1613 IHostId id = HostIdFactory.create(addr, null);
1614 return discoverHost(id);
1618 public List<List<String>> getHostNetworkHierarchy(InetAddress addr) {
1619 IHostId id = HostIdFactory.create(addr, null);
1620 return getHostNetworkHierarchy(id);
1624 public List<String> dumpPendingArpReqList() {
1626 List<String> arpReq = new ArrayList<String>();
1627 for (Entry<IHostId, ARPPending> entry : ARPPendingList.entrySet()) {
1628 arpReq.add(entry.getValue().getHostId().toString());
1634 public List<String> dumpFailedArpReqList() {
1636 List<String> arpReq = new ArrayList<String>();
1637 for (Entry<IHostId, ARPPending> entry : failedARPReqList.entrySet()) {
1638 arpReq.add(entry.getValue().getHostId().toString());