0f07ff60af44433fbd11ad784b57c75e691f4cdf
[controller.git] / opendaylight / hosttracker / implementation / src / main / java / org / opendaylight / controller / hosttracker / internal / HostTracker.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.hosttracker.internal;
10
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;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
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.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30
31 import org.apache.felix.dm.Component;
32 import org.opendaylight.controller.clustering.services.CacheConfigException;
33 import org.opendaylight.controller.clustering.services.CacheExistException;
34 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
35 import org.opendaylight.controller.clustering.services.IClusterServices;
36 import org.opendaylight.controller.hosttracker.IfHostListener;
37 import org.opendaylight.controller.hosttracker.IfIptoHost;
38 import org.opendaylight.controller.hosttracker.IfNewHostNotify;
39 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
40 import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
41 import org.opendaylight.controller.sal.core.ConstructionException;
42 import org.opendaylight.controller.sal.core.Edge;
43 import org.opendaylight.controller.sal.core.Host;
44 import org.opendaylight.controller.sal.core.Node;
45 import org.opendaylight.controller.sal.core.NodeConnector;
46 import org.opendaylight.controller.sal.core.Property;
47 import org.opendaylight.controller.sal.core.State;
48 import org.opendaylight.controller.sal.core.Tier;
49 import org.opendaylight.controller.sal.core.UpdateType;
50 import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
51 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
52 import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
53 import org.opendaylight.controller.sal.utils.GlobalConstants;
54 import org.opendaylight.controller.sal.utils.HexEncode;
55 import org.opendaylight.controller.sal.utils.NetUtils;
56 import org.opendaylight.controller.sal.utils.NodeCreator;
57 import org.opendaylight.controller.sal.utils.Status;
58 import org.opendaylight.controller.sal.utils.StatusCode;
59 import org.opendaylight.controller.switchmanager.IInventoryListener;
60 import org.opendaylight.controller.switchmanager.ISwitchManager;
61 import org.opendaylight.controller.switchmanager.ISwitchManagerAware;
62 import org.opendaylight.controller.switchmanager.Subnet;
63 import org.opendaylight.controller.topologymanager.ITopologyManager;
64 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 /**
69  * @file HostTracker.java This class tracks the location of IP Hosts as to which
70  *       Switch, Port, VLAN, they are connected to, as well as their MAC
71  *       address. This is done dynamically as well as statically. The dynamic
72  *       mechanism consists of listening to ARP messages as well sending ARP
73  *       requests. Static mechanism consists of Northbound APIs to add or remove
74  *       the hosts from the local database. ARP aging is also implemented to age
75  *       out dynamically learned hosts. Interface methods are provided for other
76  *       applications to 1. Query the local database for a single host 2. Get a
77  *       list of all hosts 3. Get notification if a host is learned/added or
78  *       removed the database
79  */
80
81 public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAware, IInventoryListener,
82         ITopologyManagerAware {
83     private static final Logger logger = LoggerFactory.getLogger(HostTracker.class);
84     private IHostFinder hostFinder;
85     private ConcurrentMap<InetAddress, HostNodeConnector> hostsDB;
86     /*
87      * Following is a list of hosts which have been requested by NB APIs to be
88      * added, but either the switch or the port is not sup, so they will be
89      * added here until both come up
90      */
91     private ConcurrentMap<NodeConnector, HostNodeConnector> inactiveStaticHosts;
92     private final Set<IfNewHostNotify> newHostNotify = Collections.synchronizedSet(new HashSet<IfNewHostNotify>());
93
94     private ITopologyManager topologyManager;
95     private IClusterContainerServices clusterContainerService = null;
96     private ISwitchManager switchManager = null;
97     private Timer timer;
98     private Timer arpRefreshTimer;
99     private String containerName = null;
100     private ExecutorService executor;
101     private static class ARPPending {
102         protected InetAddress hostIP;
103         protected short sent_count;
104         protected HostTrackerCallable hostTrackerCallable;
105
106         public InetAddress getHostIP() {
107             return hostIP;
108         }
109
110         public short getSent_count() {
111             return sent_count;
112         }
113
114         public HostTrackerCallable getHostTrackerCallable() {
115             return hostTrackerCallable;
116         }
117
118         public void setHostIP(InetAddress networkAddr) {
119             this.hostIP = networkAddr;
120         }
121
122         public void setSent_count(short count) {
123             this.sent_count = count;
124         }
125
126         public void setHostTrackerCallable(HostTrackerCallable callable) {
127             hostTrackerCallable = callable;
128         }
129     }
130
131     // This list contains the hosts for which ARP requests are being sent
132     // periodically
133     private final List<ARPPending> ARPPendingList = new ArrayList<HostTracker.ARPPending>();
134     /*
135      * This list below contains the hosts which were initially in ARPPendingList
136      * above, but ARP response didn't come from there hosts after multiple
137      * attempts over 8 seconds. The assumption is that the response didn't come
138      * back due to one of the following possibilities: 1. The L3 interface
139      * wasn't created for this host in the controller. This would cause
140      * arphandler not to know where to send the ARP 2. The host facing port is
141      * down 3. The IP host doesn't exist or is not responding to ARP requests
142      *
143      * Conditions 1 and 2 above can be recovered if ARP is sent when the
144      * relevant L3 interface is added or the port facing host comes up. Whenever
145      * L3 interface is added or host facing port comes up, ARP will be sent to
146      * hosts in this list.
147      *
148      * We can't recover from condition 3 above
149      */
150     private final List<ARPPending> failedARPReqList = new ArrayList<HostTracker.ARPPending>();
151
152     public HostTracker() {
153     }
154
155     private void startUp() {
156         allocateCache();
157         retrieveCache();
158
159         timer = new Timer();
160         timer.schedule(new OutStandingARPHandler(), 4000, 4000);
161         executor = Executors.newFixedThreadPool(2);
162         /* ARP Refresh Timer to go off every 5 seconds to implement ARP aging */
163         arpRefreshTimer = new Timer();
164         arpRefreshTimer.schedule(new ARPRefreshHandler(), 5000, 5000);
165         logger.debug("startUp: Caches created, timers started");
166     }
167
168     @SuppressWarnings("deprecation")
169     private void allocateCache() {
170         if (this.clusterContainerService == null) {
171             logger.error("un-initialized clusterContainerService, can't create cache");
172             return;
173         }
174         logger.debug("Creating Cache for HostTracker");
175         try {
176             this.clusterContainerService.createCache("hostTrackerAH",
177                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
178             this.clusterContainerService.createCache("hostTrackerIH",
179                     EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
180         } catch (CacheConfigException cce) {
181             logger.error("Cache couldn't be created for HostTracker -  check cache mode");
182         } catch (CacheExistException cce) {
183             logger.error("Cache for HostTracker already exists, destroy and recreate");
184         }
185         logger.debug("Cache successfully created for HostTracker");
186     }
187
188     @SuppressWarnings({ "unchecked", "deprecation" })
189     private void retrieveCache() {
190         if (this.clusterContainerService == null) {
191             logger.error("un-initialized clusterContainerService, can't retrieve cache");
192             return;
193         }
194         logger.debug("Retrieving cache for HostTrackerAH");
195         hostsDB = (ConcurrentMap<InetAddress, HostNodeConnector>) this.clusterContainerService
196                 .getCache("hostTrackerAH");
197         if (hostsDB == null) {
198             logger.error("Cache couldn't be retrieved for HostTracker");
199         }
200         logger.debug("Cache was successfully retrieved for HostTracker");
201         logger.debug("Retrieving cache for HostTrackerIH");
202         inactiveStaticHosts = (ConcurrentMap<NodeConnector, HostNodeConnector>) this.clusterContainerService
203                 .getCache("hostTrackerIH");
204         if (inactiveStaticHosts == null) {
205             logger.error("Cache couldn't be retrieved for HostTrackerIH");
206         }
207         logger.debug("Cache was successfully retrieved for HostTrackerIH");
208     }
209
210     public void nonClusterObjectCreate() {
211         hostsDB = new ConcurrentHashMap<InetAddress, HostNodeConnector>();
212         inactiveStaticHosts = new ConcurrentHashMap<NodeConnector, HostNodeConnector>();
213     }
214
215
216     public void shutDown() {
217     }
218
219     public void setnewHostNotify(IfNewHostNotify obj) {
220         this.newHostNotify.add(obj);
221     }
222
223     public void unsetnewHostNotify(IfNewHostNotify obj) {
224         this.newHostNotify.remove(obj);
225     }
226
227     public void setArpHandler(IHostFinder hostFinder) {
228         this.hostFinder = hostFinder;
229     }
230
231     public void unsetArpHandler(IHostFinder hostFinder) {
232         if (this.hostFinder == hostFinder) {
233             logger.debug("Arp Handler Service removed!");
234             this.hostFinder = null;
235         }
236     }
237
238     public void setTopologyManager(ITopologyManager s) {
239         this.topologyManager = s;
240     }
241
242     public void unsetTopologyManager(ITopologyManager s) {
243         if (this.topologyManager == s) {
244             logger.debug("Topology Manager Service removed!");
245             this.topologyManager = null;
246         }
247     }
248
249     private boolean hostExists(HostNodeConnector host) {
250         HostNodeConnector lhost = hostsDB.get(host.getNetworkAddress());
251         return host.equals(lhost);
252     }
253
254     private HostNodeConnector getHostFromOnActiveDB(InetAddress networkAddress) {
255         return hostsDB.get(networkAddress);
256     }
257
258     private Entry<NodeConnector, HostNodeConnector> getHostFromInactiveDB(InetAddress networkAddress) {
259         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
260             if (entry.getValue().equalsByIP(networkAddress)) {
261                 logger.debug("getHostFromInactiveDB(): Inactive Host found for IP:{} ", networkAddress.getHostAddress());
262                 return entry;
263             }
264         }
265         logger.debug("getHostFromInactiveDB() Inactive Host Not found for IP: {}", networkAddress.getHostAddress());
266         return null;
267     }
268
269     private void removeHostFromInactiveDB(InetAddress networkAddress) {
270         NodeConnector nodeConnector = null;
271         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
272             if (entry.getValue().equalsByIP(networkAddress)) {
273                 nodeConnector = entry.getKey();
274                 break;
275             }
276         }
277         if (nodeConnector != null) {
278             inactiveStaticHosts.remove(nodeConnector);
279             logger.debug("removeHostFromInactiveDB(): Host Removed for IP: {}", networkAddress.getHostAddress());
280             return;
281         }
282         logger.debug("removeHostFromInactiveDB(): Host Not found for IP: {}", networkAddress.getHostAddress());
283     }
284
285     protected boolean hostMoved(HostNodeConnector host) {
286         if (hostQuery(host.getNetworkAddress()) != null) {
287             return true;
288         }
289         return false;
290     }
291
292     @Override
293     public HostNodeConnector hostQuery(InetAddress networkAddress) {
294         return hostsDB.get(networkAddress);
295     }
296
297     @Override
298     public Future<HostNodeConnector> discoverHost(InetAddress networkAddress) {
299         if (executor == null) {
300             logger.error("discoverHost: Null executor");
301             return null;
302         }
303         Callable<HostNodeConnector> worker = new HostTrackerCallable(this, networkAddress);
304         Future<HostNodeConnector> submit = executor.submit(worker);
305         return submit;
306     }
307
308     @Override
309     public HostNodeConnector hostFind(InetAddress networkAddress) {
310         /*
311          * Sometimes at boot with containers configured in the startup we hit
312          * this path (from TIF) when hostFinder has not been set yet Caller
313          * already handles the null return
314          */
315
316         if (hostFinder == null) {
317             logger.debug("Exiting hostFind, null hostFinder");
318             return null;
319         }
320
321         HostNodeConnector host = hostQuery(networkAddress);
322         if (host != null) {
323             logger.debug("hostFind(): Host found for IP: {}", networkAddress.getHostAddress());
324             return host;
325         }
326
327         /* Add this host to ARPPending List for any potential retries */
328
329         AddtoARPPendingList(networkAddress);
330         logger.debug("hostFind(): Host Not Found for IP: {}, Inititated Host Discovery ...",
331                 networkAddress.getHostAddress());
332
333         /* host is not found, initiate a discovery */
334
335         hostFinder.find(networkAddress);
336         return null;
337     }
338
339     @Override
340     public Set<HostNodeConnector> getAllHosts() {
341         Set<HostNodeConnector> allHosts = new HashSet<HostNodeConnector>();
342         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
343             HostNodeConnector host = entry.getValue();
344             allHosts.add(host);
345         }
346         logger.debug("Exiting getAllHosts, Found {} Hosts", allHosts.size());
347         return allHosts;
348     }
349
350     @Override
351     public Set<HostNodeConnector> getActiveStaticHosts() {
352         Set<HostNodeConnector> list = new HashSet<HostNodeConnector>();
353         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
354             HostNodeConnector host = entry.getValue();
355             if (host.isStaticHost()) {
356                 list.add(host);
357             }
358         }
359         logger.debug("getActiveStaticHosts(): Found {} Hosts", list.size());
360         return list;
361     }
362
363     @Override
364     public Set<HostNodeConnector> getInactiveStaticHosts() {
365         Set<HostNodeConnector> list = new HashSet<HostNodeConnector>();
366         for (Entry<NodeConnector, HostNodeConnector> entry : inactiveStaticHosts.entrySet()) {
367             list.add(entry.getValue());
368         }
369         logger.debug("getInactiveStaticHosts(): Found {} Hosts", list.size());
370         return list;
371     }
372
373     private void AddtoARPPendingList(InetAddress networkAddr) {
374         ARPPending arphost = new ARPPending();
375
376         arphost.setHostIP(networkAddr);
377         arphost.setSent_count((short) 1);
378         ARPPendingList.add(arphost);
379         logger.debug("Host Added to ARPPending List, IP: {}", networkAddr);
380     }
381
382     private void removePendingARPFromList(int index) {
383         if (index >= ARPPendingList.size()) {
384             logger.warn("removePendingARPFromList(): index greater than the List. Size:{}, Index:{}",
385                     ARPPendingList.size(), index);
386             return;
387         }
388         ARPPending arphost = ARPPendingList.remove(index);
389         HostTrackerCallable htCallable = arphost.getHostTrackerCallable();
390         if (htCallable != null)
391             htCallable.wakeup();
392     }
393
394     public void setCallableOnPendingARP(InetAddress networkAddr, HostTrackerCallable callable) {
395         ARPPending arphost;
396         for (int i = 0; i < ARPPendingList.size(); i++) {
397             arphost = ARPPendingList.get(i);
398             if (arphost.getHostIP().equals(networkAddr)) {
399                 arphost.setHostTrackerCallable(callable);
400             }
401         }
402     }
403
404     private void ProcPendingARPReqs(InetAddress networkAddr) {
405         ARPPending arphost;
406
407         for (int i = 0; i < ARPPendingList.size(); i++) {
408             arphost = ARPPendingList.get(i);
409             if (arphost.getHostIP().equals(networkAddr)) {
410                 /*
411                  * An ARP was sent for this host. The address is learned, remove
412                  * the request
413                  */
414                 removePendingARPFromList(i);
415                 logger.debug("Host Removed from ARPPending List, IP: {}", networkAddr);
416                 return;
417             }
418         }
419
420         /*
421          * It could have been a host from the FailedARPReqList
422          */
423
424         for (int i = 0; i < failedARPReqList.size(); i++) {
425             arphost = failedARPReqList.get(i);
426             if (arphost.getHostIP().equals(networkAddr)) {
427                 /*
428                  * An ARP was sent for this host. The address is learned, remove
429                  * the request
430                  */
431                 failedARPReqList.remove(i);
432                 logger.debug("Host Removed from FailedARPReqList List, IP: {}", networkAddr);
433                 return;
434             }
435         }
436     }
437
438     // Learn a new Host
439     private void learnNewHost(HostNodeConnector host) {
440         host.initArpSendCountDown();
441         HostNodeConnector rHost = hostsDB.putIfAbsent(host.getNetworkAddress(), host);
442         if (rHost != null) {
443             // Another host is already learned for this IP address, replace it
444             replaceHost(host.getNetworkAddress(), rHost, host);
445         } else {
446             logger.debug("New Host Learned: MAC: {}  IP: {}", HexEncode.bytesToHexString(host
447                     .getDataLayerAddressBytes()), host.getNetworkAddress().getHostAddress());
448         }
449     }
450
451     private void replaceHost(InetAddress networkAddr, HostNodeConnector removedHost, HostNodeConnector newHost) {
452         newHost.initArpSendCountDown();
453         if (hostsDB.replace(networkAddr, removedHost, newHost)) {
454             logger.debug("Host move occurred: Old Host IP:{}, New Host IP: {}", removedHost.getNetworkAddress()
455                     .getHostAddress(), newHost.getNetworkAddress().getHostAddress());
456             logger.debug("Old Host MAC: {}, New Host MAC: {}",
457                     HexEncode.bytesToHexString(removedHost.getDataLayerAddressBytes()),
458                     HexEncode.bytesToHexString(newHost.getDataLayerAddressBytes()));
459             // Display the Old and New HostNodeConnectors also
460             logger.debug("Old {}, New {}", removedHost, newHost);
461         } else {
462             /*
463              * Host replacement has failed, do the recovery
464              */
465             hostsDB.put(networkAddr, newHost);
466             logger.error("Host replacement failed. Overwrite the host. Repalced Host: {}, New Host: {}", removedHost,
467                     newHost);
468         }
469         notifyHostLearnedOrRemoved(removedHost, false);
470         notifyHostLearnedOrRemoved(newHost, true);
471         if (!newHost.isStaticHost()) {
472             ProcPendingARPReqs(networkAddr);
473         }
474     }
475
476     // Remove known Host
477     private void removeKnownHost(InetAddress key) {
478         HostNodeConnector host = hostsDB.get(key);
479         if (host != null) {
480             logger.debug("Removing Host: IP:{}", host.getNetworkAddress().getHostAddress());
481             hostsDB.remove(key);
482         } else {
483             logger.error("removeKnownHost(): Host for IP address {} not found in hostsDB", key.getHostAddress());
484         }
485     }
486
487     private class NotifyHostThread extends Thread {
488
489         private final HostNodeConnector host;
490
491         public NotifyHostThread(HostNodeConnector h) {
492             this.host = h;
493         }
494
495         @Override
496         public void run() {
497             HostNodeConnector removedHost = null;
498             InetAddress networkAddr = host.getNetworkAddress();
499
500             /* Check for Host Move case */
501             if (hostMoved(host)) {
502                 /*
503                  * Host has been moved from one location (switch,port, MAC, or
504                  * VLAN) to another. Replace the existing host and its previous
505                  * location parameters with new information, and notify the
506                  * applications listening to host move.
507                  */
508                 removedHost = hostsDB.get(networkAddr);
509                 if (removedHost != null) {
510                     replaceHost(networkAddr, removedHost, host);
511                     return;
512                 } else {
513                     logger.error("Host to be removed not found in hostsDB. Host {}", removedHost);
514                 }
515             }
516
517             if (removedHost == null) {
518                 // It is a new host
519                 learnNewHost(host);
520             }
521
522             /* check if there is an outstanding request for this host */
523             ProcPendingARPReqs(networkAddr);
524             notifyHostLearnedOrRemoved(host, true);
525         }
526     }
527
528     @Override
529     public void hostListener(HostNodeConnector host) {
530
531         logger.debug("ARP received for Host: IP {}, MAC {}, {}", host.getNetworkAddress().getHostAddress(),
532                 HexEncode.bytesToHexString(host.getDataLayerAddressBytes()), host);
533         if (hostExists(host)) {
534             HostNodeConnector existinghost = hostsDB.get(host.getNetworkAddress());
535             existinghost.initArpSendCountDown();
536             return;
537         }
538         new NotifyHostThread(host).start();
539     }
540
541     // Notify whoever is interested that a new host was learned (dynamically or
542     // statically)
543     private void notifyHostLearnedOrRemoved(HostNodeConnector host, boolean add) {
544         // Update listeners if any
545         if (newHostNotify != null) {
546             logger.debug("Notifying Applications for Host {} Being {}", host.getNetworkAddress().getHostAddress(),
547                     add ? "Added" : "Deleted");
548             synchronized (this.newHostNotify) {
549                 for (IfNewHostNotify ta : newHostNotify) {
550                     try {
551                         if (add) {
552                             ta.notifyHTClient(host);
553                         } else {
554                             ta.notifyHTClientHostRemoved(host);
555                         }
556                     } catch (Exception e) {
557                         logger.error("Exception on callback", e);
558                     }
559                 }
560             }
561         } else {
562             logger.error("notifyHostLearnedOrRemoved(): New host notify is null");
563         }
564
565         // Topology update is for some reason outside of listeners registry
566         // logic
567         Node node = host.getnodeconnectorNode();
568         Host h = null;
569         NodeConnector p = host.getnodeConnector();
570         try {
571             DataLinkAddress dla = new EthernetAddress(host.getDataLayerAddressBytes());
572             h = new Host(dla, host.getNetworkAddress());
573         } catch (ConstructionException ce) {
574             p = null;
575             h = null;
576         }
577
578         if (topologyManager != null && p != null && h != null) {
579             logger.debug("Notifying Topology Manager for Host {} Being {}", h.getNetworkAddress().getHostAddress(),
580                     add ? "Added" : "Deleted");
581             if (add == true) {
582                 Tier tier = new Tier(1);
583                 switchManager.setNodeProp(node, tier);
584                 topologyManager.updateHostLink(p, h, UpdateType.ADDED, null);
585             } else {
586                 // No need to reset the tiering if no other hosts are currently
587                 // connected
588                 // If this switch was discovered to be an access switch, it
589                 // still is even if the host is down
590                 Tier tier = new Tier(0);
591                 switchManager.setNodeProp(node, tier);
592                 topologyManager.updateHostLink(p, h, UpdateType.REMOVED, null);
593             }
594         }
595     }
596
597     /**
598      * When a new Host is learnt by the hosttracker module, it places the
599      * directly connected Node in Tier-1 & using this function, updates the Tier
600      * value for all other Nodes in the network hierarchy.
601      *
602      * This is a recursive function and it takes care of updating the Tier value
603      * for all the connected and eligible Nodes.
604      *
605      * @param n
606      *            Node that represents one of the Vertex in the Topology Graph.
607      * @param currentTier
608      *            The Tier on which n belongs
609      */
610     private void updateSwitchTiers(Node n, int currentTier) {
611         Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
612         if (ndlinks == null) {
613             logger.debug("updateSwitchTiers(): ndlinks null for Node: {}, Tier:{}", n, currentTier);
614             return;
615         }
616         Set<Edge> links = ndlinks.get(n);
617         if (links == null) {
618             logger.debug("updateSwitchTiers(): links null for ndlinks:{}", ndlinks);
619             return;
620         }
621         ArrayList<Node> needsVisiting = new ArrayList<Node>();
622         for (Edge lt : links) {
623             if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
624                 // We don't want to work on Node that are not openflow
625                 // for now
626                 continue;
627             }
628             Node dstNode = lt.getHeadNodeConnector().getNode();
629             if (switchNeedsTieringUpdate(dstNode, currentTier + 1)) {
630                 Tier t = new Tier(currentTier + 1);
631                 switchManager.setNodeProp(dstNode, t);
632                 needsVisiting.add(dstNode);
633             }
634         }
635
636         /*
637          * Due to the nature of the problem, having a separate loop for nodes
638          * that needs visiting provides a decent walk optimization.
639          */
640         for (Node node : needsVisiting) {
641             updateSwitchTiers(node, currentTier + 1);
642         }
643     }
644
645     /**
646      * Internal convenience routine to check the eligibility of a Switch for a
647      * Tier update. Any Node with Tier=0 or a Tier value that is greater than
648      * the new Tier Value is eligible for the update.
649      *
650      * @param n
651      *            Node for which the Tier update eligibility is checked
652      * @param tier
653      *            new Tier Value
654      * @return <code>true</code> if the Node is eligible for Tier Update
655      *         <code>false</code> otherwise
656      */
657
658     private boolean switchNeedsTieringUpdate(Node n, int tier) {
659         if (n == null) {
660             logger.error("switchNeedsTieringUpdate(): Null node for tier: {}", tier);
661             return false;
662         }
663         /*
664          * Node could have gone down
665          */
666         if (!switchManager.getNodes().contains(n)) {
667             return false;
668         }
669         // This is the case where Tier was never set for this node
670         Tier t = (Tier) switchManager.getNodeProp(n, Tier.TierPropName);
671         if (t == null)
672             return true;
673         if (t.getValue() == 0)
674             return true;
675         else if (t.getValue() > tier)
676             return true;
677         return false;
678     }
679
680     /**
681      * Internal convenience routine to clear all the Tier values to 0. This
682      * cleanup is performed during cases such as Topology Change where the
683      * existing Tier values might become incorrect
684      */
685     private void clearTiers() {
686         Set<Node> nodes = null;
687         if (switchManager == null) {
688             logger.error("clearTiers(): Null switchManager");
689             return;
690         }
691         nodes = switchManager.getNodes();
692
693         for (Node n : nodes) {
694             Tier t = new Tier(0);
695             switchManager.setNodeProp(n, t);
696         }
697     }
698
699     /**
700      * Internal convenience routine to print the hierarchies of switches.
701      */
702     @SuppressWarnings("unused")
703     private void logHierarchies(ArrayList<ArrayList<String>> hierarchies) {
704         String hierarchyString = null;
705         int num = 1;
706         for (ArrayList<String> hierarchy : hierarchies) {
707             StringBuffer buf = new StringBuffer();
708             buf.append("Hierarchy#" + num + " : ");
709             for (String switchName : hierarchy) {
710                 buf.append(switchName + "/");
711             }
712             logger.debug("{} -> {}", getContainerName(), buf);
713             num++;
714         }
715     }
716
717     /**
718      * getHostNetworkHierarchy is the Back-end routine for the North-Bound API
719      * that returns the Network Hierarchy for a given Host. This API is
720      * typically used by applications like Hadoop for Rack Awareness
721      * functionality.
722      *
723      * @param hostAddress
724      *            IP-Address of the host/node.
725      * @return Network Hierarchies represented by an Array of Array (of
726      *         Switch-Ids as String).
727      */
728     @Override
729     public List<List<String>> getHostNetworkHierarchy(InetAddress hostAddress) {
730         HostNodeConnector host = hostQuery(hostAddress);
731         if (host == null)
732             return null;
733
734         List<List<String>> hierarchies = new ArrayList<List<String>>();
735         ArrayList<String> currHierarchy = new ArrayList<String>();
736         hierarchies.add(currHierarchy);
737
738         Node node = host.getnodeconnectorNode();
739         updateCurrentHierarchy(node, currHierarchy, hierarchies);
740         return hierarchies;
741     }
742
743     /**
744      * dpidToHostNameHack is a hack function for Cisco Live Hadoop Demo. Mininet
745      * is used as the network for Hadoop Demos & in order to give a meaningful
746      * rack-awareness switch names, the DPID is organized in ASCII Characters
747      * and retrieved as string.
748      *
749      * @param dpid
750      *            Switch DataPath Id
751      * @return Ascii String represented by the DPID.
752      */
753     private String dpidToHostNameHack(long dpid) {
754         String hex = Long.toHexString(dpid);
755
756         StringBuffer sb = new StringBuffer();
757         int result = 0;
758         for (int i = 0; i < hex.length(); i++) {
759             result = (int) ((dpid >> (i * 8)) & 0xff);
760             if (result == 0)
761                 continue;
762             if (result < 0x30)
763                 result += 0x40;
764             sb.append(String.format("%c", result));
765         }
766         return sb.reverse().toString();
767     }
768
769     /**
770      * A convenient recursive routine to obtain the Hierarchy of Switches.
771      *
772      * @param node
773      *            Current Node in the Recursive routine.
774      * @param currHierarchy
775      *            Array of Nodes that make this hierarchy on which the Current
776      *            Switch belong
777      * @param fullHierarchy
778      *            Array of multiple Hierarchies that represent a given host.
779      */
780     @SuppressWarnings("unchecked")
781     private void updateCurrentHierarchy(Node node, ArrayList<String> currHierarchy, List<List<String>> fullHierarchy) {
782         // currHierarchy.add(String.format("%x", currSw.getId()));
783         currHierarchy.add(dpidToHostNameHack((Long) node.getID()));
784         ArrayList<String> currHierarchyClone = (ArrayList<String>) currHierarchy.clone(); // Shallow
785                                                                                           // copy
786                                                                                           // as
787                                                                                           // required
788
789         Map<Node, Set<Edge>> ndlinks = topologyManager.getNodeEdges();
790         if (ndlinks == null) {
791             logger.debug("updateCurrentHierarchy(): topologyManager returned null ndlinks for node: {}", node);
792             return;
793         }
794         Node n = NodeCreator.createOFNode((Long) node.getID());
795         Set<Edge> links = ndlinks.get(n);
796         if (links == null) {
797             logger.debug("updateCurrentHierarchy(): Null links for ndlinks");
798             return;
799         }
800         for (Edge lt : links) {
801             if (!lt.getHeadNodeConnector().getType().equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
802                 // We don't want to work on Node that are not openflow
803                 // for now
804                 continue;
805             }
806             Node dstNode = lt.getHeadNodeConnector().getNode();
807
808             Tier nodeTier = (Tier) switchManager.getNodeProp(node, Tier.TierPropName);
809             Tier dstNodeTier = (Tier) switchManager.getNodeProp(dstNode, Tier.TierPropName);
810             if (dstNodeTier.getValue() > nodeTier.getValue()) {
811                 ArrayList<String> buildHierarchy = currHierarchy;
812                 if (currHierarchy.size() > currHierarchyClone.size()) {
813                     buildHierarchy = (ArrayList<String>) currHierarchyClone.clone(); // Shallow
814                                                                                      // copy
815                                                                                      // as
816                                                                                      // required
817                     fullHierarchy.add(buildHierarchy);
818                 }
819                 updateCurrentHierarchy(dstNode, buildHierarchy, fullHierarchy);
820             }
821         }
822     }
823
824     private void debugEdgeUpdate(Edge e, UpdateType type, Set<Property> props) {
825         Long srcNid = null;
826         Short srcPort = null;
827         Long dstNid = null;
828         Short dstPort = null;
829         boolean added = false;
830         String srcType = null;
831         String dstType = null;
832
833         if (e == null || type == null) {
834             logger.error("Edge or Update type are null!");
835             return;
836         } else {
837             srcType = e.getTailNodeConnector().getType();
838             dstType = e.getHeadNodeConnector().getType();
839
840             if (srcType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
841                 logger.debug("Skip updates for {}", e);
842                 return;
843             }
844
845             if (!srcType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
846                 logger.debug("For now we cannot handle updates for non-openflow nodes");
847                 return;
848             }
849
850             if (dstType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
851                 logger.debug("Skip updates for {}", e);
852                 return;
853             }
854
855             if (!dstType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
856                 logger.debug("For now we cannot handle updates for non-openflow nodes");
857                 return;
858             }
859
860             // At this point we know we got an openflow update, so
861             // lets fill everything accordingly.
862             srcNid = (Long) e.getTailNodeConnector().getNode().getID();
863             srcPort = (Short) e.getTailNodeConnector().getID();
864             dstNid = (Long) e.getHeadNodeConnector().getNode().getID();
865             dstPort = (Short) e.getHeadNodeConnector().getID();
866
867             // Now lets update the added flag
868             switch (type) {
869             case ADDED:
870             case CHANGED:
871                 added = true;
872                 break;
873             case REMOVED:
874                 added = false;
875             }
876         }
877
878         logger.debug("HostTracker Topology linkUpdate handling src:{}[port {}] dst:{}[port {}] added: {}",
879                 new Object[] { srcNid, srcPort, dstNid, dstPort, added });
880     }
881
882     @Override
883     public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
884         if (logger.isDebugEnabled()) {
885             for (TopoEdgeUpdate topoEdgeUpdate : topoedgeupdateList) {
886                 Edge e = topoEdgeUpdate.getEdge();
887                 Set<Property> p = topoEdgeUpdate.getProperty();
888                 UpdateType type = topoEdgeUpdate.getUpdateType();
889
890                 debugEdgeUpdate(e, type, p);
891             }
892         }
893     }
894
895     @Override
896     public void subnetNotify(Subnet sub, boolean add) {
897         logger.debug("Received subnet notification: {}  add={}", sub, add);
898         if (add) {
899             for (int i = 0; i < failedARPReqList.size(); i++) {
900                 ARPPending arphost;
901                 arphost = failedARPReqList.get(i);
902                 if (hostFinder == null) {
903                     logger.warn("ARPHandler Services are not available on subnet addition");
904                     continue;
905                 }
906                logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
907                hostFinder.find(arphost.getHostIP());
908             }
909         }
910     }
911
912     class OutStandingARPHandler extends TimerTask {
913         @Override
914         public void run() {
915             ARPPending arphost;
916             /* This routine runs every 4 seconds */
917             for (int i = 0; i < ARPPendingList.size(); i++) {
918                 arphost = ARPPendingList.get(i);
919                 if (arphost.getSent_count() < switchManager.getHostRetryCount()) {
920                     /*
921                      * No reply has been received of first ARP Req, send the
922                      * next one. Before sending the ARP, check if ARPHandler
923                      * is available or not
924                      */
925                     if (hostFinder == null) {
926                         logger.warn("ARPHandler Services are not available for Outstanding ARPs");
927                         continue;
928                     }
929                     hostFinder.find(arphost.getHostIP());
930                     arphost.sent_count++;
931                     logger.debug("ARP Sent from ARPPending List, IP: {}", arphost.getHostIP().getHostAddress());
932                 } else if (arphost.getSent_count() >= switchManager.getHostRetryCount()) {
933                     /*
934                      * ARP requests have been sent without receiving a
935                      * reply, remove this from the pending list
936                      */
937                     removePendingARPFromList(i);
938                     logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}",
939                             arphost.getHostIP().getHostAddress());
940                     /*
941                      * Add this host to a different list which will be processed
942                      * on link up events
943                      */
944                     logger.debug("Adding the host to FailedARPReqList IP: {}", arphost.getHostIP().getHostAddress());
945                     failedARPReqList.add(arphost);
946
947                 } else {
948                     logger.error("Inavlid arp_sent count for entry at index: {}", i);
949                 }
950             }
951         }
952     }
953
954     private class ARPRefreshHandler extends TimerTask {
955         @Override
956         @SuppressWarnings("deprecation")
957         public void run() {
958             if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
959                 return;
960             }
961             if ((switchManager != null) && !switchManager.isHostRefreshEnabled()) {
962                 /*
963                  * The host probe procedure was disabled by CLI
964                  */
965                 return;
966             }
967             if (hostsDB == null) {
968                 /* hostsDB is not allocated yet */
969                 logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
970                 return;
971             }
972             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
973                 HostNodeConnector host = entry.getValue();
974                 if (host.isStaticHost()) {
975                     /* this host was learned via API3, don't age it out */
976                     continue;
977                 }
978
979                 short arp_cntdown = host.getArpSendCountDown();
980                 arp_cntdown--;
981                 if (arp_cntdown > switchManager.getHostRetryCount()) {
982                     host.setArpSendCountDown(arp_cntdown);
983                 } else if (arp_cntdown <= 0) {
984                     /*
985                      * No ARP Reply received in last 2 minutes, remove this host
986                      * and inform applications
987                      */
988                     removeKnownHost(entry.getKey());
989                     notifyHostLearnedOrRemoved(host, false);
990                 } else if (arp_cntdown <= switchManager.getHostRetryCount()) {
991                     /*
992                      * Use the services of arphandler to check if host is still
993                      * there
994                      */
995                     if (logger.isTraceEnabled()) {
996                         logger.trace(
997                                 "ARP Probing ({}) for {}({})",
998                                 new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
999                                         HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
1000                     }
1001                     host.setArpSendCountDown(arp_cntdown);
1002                     if (hostFinder == null) {
1003                         /*
1004                          * If hostfinder is not available, then can't send the
1005                          * probe. However, continue the age out the hosts since
1006                          * we don't know if the host is indeed out there or not.
1007                          */
1008                         logger.warn("ARPHandler is not avaialable, can't send the probe");
1009                         continue;
1010                     }
1011                     hostFinder.probe(host);
1012                 }
1013             }
1014         }
1015     }
1016
1017     /**
1018      * Inform the controller IP to MAC binding of a host and its connectivity to
1019      * an openflow switch in terms of Node, port, and VLAN.
1020      *
1021      * @param networkAddr
1022      *            IP address of the host
1023      * @param dataLayer
1024      *            Address MAC address of the host
1025      * @param nc
1026      *            NodeConnector to which host is connected
1027      * @param port
1028      *            Port of the switch to which host is connected
1029      * @param vlan
1030      *            Vlan of which this host is member of
1031      *
1032      * @return Status The status object as described in {@code Status}
1033      *         indicating the result of this action.
1034      */
1035
1036     public Status addStaticHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1037         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1038             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1039         }
1040
1041         if (nc == null) {
1042             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1043         }
1044         HostNodeConnector host = null;
1045         try {
1046             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1047             if (hostExists(host)) {
1048                 // This host is already learned either via ARP or through a
1049                 // northbound request
1050                 HostNodeConnector transHost = hostsDB.get(networkAddr);
1051                 transHost.setStaticHost(true);
1052                 return new Status(StatusCode.SUCCESS, null);
1053             }
1054
1055             if (hostsDB.get(networkAddr) != null) {
1056                 // There is already a host with this IP address (but behind
1057                 // a different (switch, port, vlan) tuple. Return an error
1058                 return new Status(StatusCode.CONFLICT, "Existing IP, Use PUT to update");
1059             }
1060             host.setStaticHost(true);
1061             /*
1062              * Check if the nc is an ISL port
1063              */
1064             if (topologyManager != null) {
1065                 if (topologyManager.isInternal(nc)) {
1066                     return new Status(StatusCode.BADREQUEST, "Cannot add host on ISL port");
1067                 }
1068             }
1069             /*
1070              * Before adding host, Check if the switch and the port have already
1071              * come up
1072              */
1073             if (switchManager.isNodeConnectorEnabled(nc)) {
1074                 learnNewHost(host);
1075                 notifyHostLearnedOrRemoved(host, true);
1076             } else {
1077                 inactiveStaticHosts.put(nc, host);
1078                 logger.debug("Switch or switchport is not up, adding host {} to inactive list",
1079                         networkAddr.getHostName());
1080             }
1081             return new Status(StatusCode.SUCCESS, null);
1082         } catch (ConstructionException e) {
1083             logger.error("", e);
1084             return new Status(StatusCode.INTERNALERROR, "Host could not be created");
1085         }
1086
1087     }
1088
1089     /**
1090      * Update the controller IP to MAC binding of a host and its connectivity to
1091      * an openflow switch in terms of switch id, switch port, and VLAN.
1092      *
1093      * @param networkAddr
1094      *            IP address of the host
1095      * @param dataLayer
1096      *            Address MAC address of the host
1097      * @param nc
1098      *            NodeConnector to which host is connected
1099      * @param port
1100      *            Port of the switch to which host is connected
1101      * @param vlan
1102      *            Vlan of which this host is member of
1103      *
1104      * @return Status The status object as described in {@code Status}
1105      *         indicating the result of this action.
1106      */
1107     public Status updateHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1108         HostNodeConnector tobeUpdatedHost;
1109         HostNodeConnector host = null;
1110
1111         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1112             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1113         }
1114
1115         if (nc == null) {
1116             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1117         }
1118
1119         try {
1120             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1121             if (hostExists(host)) {
1122                 return new Status(StatusCode.BADREQUEST, "Host already exists");
1123             }
1124
1125             if ((tobeUpdatedHost = hostsDB.get(networkAddr)) != null) {
1126                 if (hostsDB.replace(networkAddr, tobeUpdatedHost, host)) {
1127                     logger.debug("Host replaced from hostsDB. Old host: {} New Host: {}", tobeUpdatedHost, host);
1128                     notifyHostLearnedOrRemoved(tobeUpdatedHost, false);
1129                     notifyHostLearnedOrRemoved(host, true);
1130                     return new Status(StatusCode.SUCCESS);
1131                 } else {
1132                     logger.error("Static host replacement failed from hostsDB, Replaced Host: {}, New Host: {}",
1133                             tobeUpdatedHost, host);
1134                     return new Status(StatusCode.INTERNALERROR,
1135                             "Host Replacement Failed due to presence of another host with same IP");
1136                 }
1137             }
1138
1139             // Check if the host exists in inactive hosts database
1140             if ((tobeUpdatedHost = inactiveStaticHosts.get(nc)) != null) {
1141                 if (inactiveStaticHosts.replace(nc, tobeUpdatedHost, host)) {
1142                     logger.debug("Host replaced from inactive hostsDB. Old host: {} New Host: {}", tobeUpdatedHost,
1143                             host);
1144                     return new Status(StatusCode.SUCCESS);
1145                 } else {
1146                     logger.error("Static host replacement failed, Replaced Host: {}, New Host: {}", tobeUpdatedHost,
1147                             host);
1148                     return new Status(StatusCode.INTERNALERROR,
1149                             "Host Replacement Failed due to presence of another host with same IP");
1150                 }
1151             }
1152
1153             // Host doesn't exist
1154             return new Status(StatusCode.BADREQUEST, "Host doesn't exists, can't update");
1155         } catch (ConstructionException e) {
1156             logger.error("", e);
1157             return new Status(StatusCode.INTERNALERROR, "host object creation failure");
1158         }
1159     }
1160
1161     /**
1162      * Remove from the controller IP to MAC binding of a host and its
1163      * connectivity to an openflow switch
1164      *
1165      * @param networkAddr
1166      *            IP address of the host
1167      *
1168      * @return boolean true if the host was removed successfully, false
1169      *         otherwise
1170      */
1171
1172     public Status removeStaticHostReq(InetAddress networkAddress) {
1173         // Check if host is in active hosts database
1174         HostNodeConnector host = getHostFromOnActiveDB(networkAddress);
1175         if (host != null) {
1176             // Validation check
1177             if (!host.isStaticHost()) {
1178                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1179             }
1180             // Remove and notify
1181             notifyHostLearnedOrRemoved(host, false);
1182             removeKnownHost(networkAddress);
1183             return new Status(StatusCode.SUCCESS, null);
1184         }
1185
1186         // Check if host is in inactive hosts database
1187         Entry<NodeConnector, HostNodeConnector> entry = getHostFromInactiveDB(networkAddress);
1188         if (entry != null) {
1189             host = entry.getValue();
1190             // Validation check
1191             if (!host.isStaticHost()) {
1192                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1193             }
1194             this.removeHostFromInactiveDB(networkAddress);
1195             return new Status(StatusCode.SUCCESS, null);
1196         }
1197
1198         // Host is neither in active nor inactive hosts database
1199         return new Status(StatusCode.NOTFOUND, "Host does not exist");
1200     }
1201
1202     @Override
1203     public void modeChangeNotify(Node node, boolean proactive) {
1204         logger.debug("Set Switch {} Mode to {}", node.getID(), proactive);
1205     }
1206
1207     @Override
1208     public void notifyNode(Node node, UpdateType type, Map<String, Property> propMap) {
1209         if (node == null)
1210             return;
1211
1212         switch (type) {
1213         case REMOVED:
1214             logger.debug("Received removed node {}", node);
1215             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1216                 HostNodeConnector host = entry.getValue();
1217                 if (host.getnodeconnectorNode().equals(node)) {
1218                     logger.debug("Node: {} is down, remove from Hosts_DB", node);
1219                     removeKnownHost(entry.getKey());
1220                     notifyHostLearnedOrRemoved(host, false);
1221                 }
1222             }
1223             break;
1224         default:
1225             break;
1226         }
1227     }
1228
1229     @Override
1230     public void notifyNodeConnector(NodeConnector nodeConnector, UpdateType type, Map<String, Property> propMap) {
1231         if (nodeConnector == null)
1232             return;
1233
1234         boolean up = false;
1235         switch (type) {
1236         case ADDED:
1237             up = true;
1238             break;
1239         case REMOVED:
1240             break;
1241         case CHANGED:
1242             State state = (State) propMap.get(State.StatePropName);
1243             if ((state != null) && (state.getValue() == State.EDGE_UP)) {
1244                 up = true;
1245             }
1246             break;
1247         default:
1248             return;
1249         }
1250
1251         if (up) {
1252             handleNodeConnectorStatusUp(nodeConnector);
1253         } else {
1254             handleNodeConnectorStatusDown(nodeConnector);
1255         }
1256     }
1257
1258     @Override
1259     public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan) {
1260         try {
1261             InetAddress ip = InetAddress.getByName(networkAddress);
1262             if (nc == null) {
1263                 return new Status(StatusCode.BADREQUEST, "Invalid NodeId");
1264             }
1265             return addStaticHostReq(ip, HexEncode.bytesFromHexString(dataLayerAddress), nc, Short.valueOf(vlan));
1266         } catch (UnknownHostException e) {
1267             logger.error("", e);
1268             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1269         }
1270     }
1271
1272     @Override
1273     public Status removeStaticHost(String networkAddress) {
1274         InetAddress address;
1275         try {
1276             address = InetAddress.getByName(networkAddress);
1277             return removeStaticHostReq(address);
1278         } catch (UnknownHostException e) {
1279             logger.error("", e);
1280             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1281         }
1282     }
1283
1284     private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
1285         ARPPending arphost;
1286
1287         logger.debug("handleNodeConnectorStatusUp {}", nodeConnector);
1288
1289         for (int i = 0; i < failedARPReqList.size(); i++) {
1290             arphost = failedARPReqList.get(i);
1291             logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
1292             if (hostFinder == null) {
1293                 logger.warn("ARPHandler is not available at interface  up");
1294                 logger.warn("Since this event is missed, host(s) connected to interface {} may not be discovered",
1295                         nodeConnector);
1296                 continue;
1297             }
1298             hostFinder.find(arphost.getHostIP());
1299         }
1300         HostNodeConnector host = inactiveStaticHosts.get(nodeConnector);
1301         if (host != null) {
1302             inactiveStaticHosts.remove(nodeConnector);
1303             learnNewHost(host);
1304             notifyHostLearnedOrRemoved(host, true);
1305         }
1306     }
1307
1308     private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
1309         logger.debug("handleNodeConnectorStatusDown {}", nodeConnector);
1310
1311         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1312             HostNodeConnector host = entry.getValue();
1313             if (host.getnodeConnector().equals(nodeConnector)) {
1314                 logger.debug(" NodeConnector: {} is down, remove from Hosts_DB", nodeConnector);
1315                 removeKnownHost(entry.getKey());
1316                 notifyHostLearnedOrRemoved(host, false);
1317             }
1318         }
1319     }
1320
1321     void setClusterContainerService(IClusterContainerServices s) {
1322         logger.debug("Cluster Service set");
1323         this.clusterContainerService = s;
1324     }
1325
1326     void unsetClusterContainerService(IClusterContainerServices s) {
1327         if (this.clusterContainerService == s) {
1328             logger.debug("Cluster Service removed!");
1329             this.clusterContainerService = null;
1330         }
1331     }
1332
1333     void setSwitchManager(ISwitchManager s) {
1334         logger.debug("SwitchManager set");
1335         this.switchManager = s;
1336     }
1337
1338     void unsetSwitchManager(ISwitchManager s) {
1339         if (this.switchManager == s) {
1340             logger.debug("SwitchManager removed!");
1341             this.switchManager = null;
1342         }
1343     }
1344
1345     public String getContainerName() {
1346         if (containerName == null)
1347             return GlobalConstants.DEFAULT.toString();
1348         return containerName;
1349     }
1350
1351     /**
1352      * Function called by the dependency manager when all the required
1353      * dependencies are satisfied
1354      *
1355      */
1356     void init(Component c) {
1357         Dictionary<?, ?> props = c.getServiceProperties();
1358         if (props != null) {
1359             this.containerName = (String) props.get("containerName");
1360             logger.debug("Running containerName: {}", this.containerName);
1361         } else {
1362             // In the Global instance case the containerName is empty
1363             this.containerName = "";
1364         }
1365         startUp();
1366     }
1367
1368     /**
1369      * Function called by the dependency manager when at least one dependency
1370      * become unsatisfied or when the component is shutting down because for
1371      * example bundle is being stopped.
1372      *
1373      */
1374     void destroy() {
1375     }
1376
1377     /**
1378      * Function called by dependency manager after "init ()" is called and after
1379      * the services provided by the class are registered in the service registry
1380      *
1381      */
1382     void start() {
1383     }
1384
1385     /**
1386      * Function called by the dependency manager before the services exported by
1387      * the component are unregistered, this will be followed by a "destroy ()"
1388      * calls
1389      *
1390      */
1391     void stop(){
1392     }
1393
1394     void stopping() {
1395         arpRefreshTimer.cancel();
1396         timer.cancel();
1397         executor.shutdown();
1398     }
1399
1400     @Override
1401     public void edgeOverUtilized(Edge edge) {
1402         // TODO Auto-generated method stub
1403
1404     }
1405
1406     @Override
1407     public void edgeUtilBackToNormal(Edge edge) {
1408         // TODO Auto-generated method stub
1409
1410     }
1411
1412 }