Merge "Enhancement in switch configuration"
[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 ArrayList<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 edgeUpdate(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.error("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.error("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         for (int i = 0; i < topoedgeupdateList.size(); i++) {
885             Edge e = topoedgeupdateList.get(i).getEdge();
886             Set<Property> p = topoedgeupdateList.get(i).getProperty();
887             UpdateType type = topoedgeupdateList.get(i).getUpdateType();
888             edgeUpdate(e, type, p);
889         }
890     }
891
892     @Override
893     public void subnetNotify(Subnet sub, boolean add) {
894         logger.debug("Received subnet notification: {}  add={}", sub, add);
895         if (add) {
896             for (int i = 0; i < failedARPReqList.size(); i++) {
897                 ARPPending arphost;
898                 arphost = failedARPReqList.get(i);
899                 if (hostFinder == null) {
900                     logger.warn("ARPHandler Services are not available on subnet addition");
901                     continue;
902                 }
903                logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
904                hostFinder.find(arphost.getHostIP());
905             }
906         }
907     }
908
909     class OutStandingARPHandler extends TimerTask {
910         @Override
911         public void run() {
912             ARPPending arphost;
913             /* This routine runs every 4 seconds */
914             for (int i = 0; i < ARPPendingList.size(); i++) {
915                 arphost = ARPPendingList.get(i);
916                 if (arphost.getSent_count() < switchManager.getHostRetryCount()) {
917                     /*
918                      * No reply has been received of first ARP Req, send the
919                      * next one. Before sending the ARP, check if ARPHandler
920                      * is available or not
921                      */
922                     if (hostFinder == null) {
923                         logger.warn("ARPHandler Services are not available for Outstanding ARPs");
924                         continue;
925                     }
926                     hostFinder.find(arphost.getHostIP());
927                     arphost.sent_count++;
928                     logger.debug("ARP Sent from ARPPending List, IP: {}", arphost.getHostIP().getHostAddress());
929                 } else if (arphost.getSent_count() >= switchManager.getHostRetryCount()) {
930                     /*
931                      * ARP requests have been sent without receiving a
932                      * reply, remove this from the pending list
933                      */
934                     removePendingARPFromList(i);
935                     logger.debug("ARP reply not received after multiple attempts, removing from Pending List IP: {}",
936                             arphost.getHostIP().getHostAddress());
937                     /*
938                      * Add this host to a different list which will be processed
939                      * on link up events
940                      */
941                     logger.debug("Adding the host to FailedARPReqList IP: {}", arphost.getHostIP().getHostAddress());
942                     failedARPReqList.add(arphost);
943
944                 } else {
945                     logger.error("Inavlid arp_sent count for entry at index: {}", i);
946                 }
947             }
948         }
949     }
950
951     private class ARPRefreshHandler extends TimerTask {
952         @Override
953         @SuppressWarnings("deprecation")
954         public void run() {
955             if ((clusterContainerService != null) && !clusterContainerService.amICoordinator()) {
956                 return;
957             }
958             if ((switchManager != null) && !switchManager.isHostRefreshEnabled()) {
959                 /*
960                  * The host probe procedure was disabled by CLI
961                  */
962                 return;
963             }
964             if (hostsDB == null) {
965                 /* hostsDB is not allocated yet */
966                 logger.error("ARPRefreshHandler(): hostsDB is not allocated yet:");
967                 return;
968             }
969             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
970                 HostNodeConnector host = entry.getValue();
971                 if (host.isStaticHost()) {
972                     /* this host was learned via API3, don't age it out */
973                     continue;
974                 }
975
976                 short arp_cntdown = host.getArpSendCountDown();
977                 arp_cntdown--;
978                 if (arp_cntdown > switchManager.getHostRetryCount()) {
979                     host.setArpSendCountDown(arp_cntdown);
980                 } else if (arp_cntdown <= 0) {
981                     /*
982                      * No ARP Reply received in last 2 minutes, remove this host
983                      * and inform applications
984                      */
985                     removeKnownHost(entry.getKey());
986                     notifyHostLearnedOrRemoved(host, false);
987                 } else if (arp_cntdown <= switchManager.getHostRetryCount()) {
988                     /*
989                      * Use the services of arphandler to check if host is still
990                      * there
991                      */
992                     if (logger.isTraceEnabled()) {
993                         logger.trace(
994                                 "ARP Probing ({}) for {}({})",
995                                 new Object[] { arp_cntdown, host.getNetworkAddress().getHostAddress(),
996                                         HexEncode.bytesToHexString(host.getDataLayerAddressBytes()) });
997                     }
998                     host.setArpSendCountDown(arp_cntdown);
999                     if (hostFinder == null) {
1000                         /*
1001                          * If hostfinder is not available, then can't send the
1002                          * probe. However, continue the age out the hosts since
1003                          * we don't know if the host is indeed out there or not.
1004                          */
1005                         logger.warn("ARPHandler is not avaialable, can't send the probe");
1006                         continue;
1007                     }
1008                     hostFinder.probe(host);
1009                 }
1010             }
1011         }
1012     }
1013
1014     /**
1015      * Inform the controller IP to MAC binding of a host and its connectivity to
1016      * an openflow switch in terms of Node, port, and VLAN.
1017      *
1018      * @param networkAddr
1019      *            IP address of the host
1020      * @param dataLayer
1021      *            Address MAC address of the host
1022      * @param nc
1023      *            NodeConnector to which host is connected
1024      * @param port
1025      *            Port of the switch to which host is connected
1026      * @param vlan
1027      *            Vlan of which this host is member of
1028      *
1029      * @return Status The status object as described in {@code Status}
1030      *         indicating the result of this action.
1031      */
1032
1033     public Status addStaticHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1034         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1035             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1036         }
1037
1038         if (nc == null) {
1039             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1040         }
1041         HostNodeConnector host = null;
1042         try {
1043             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1044             if (hostExists(host)) {
1045                 // This host is already learned either via ARP or through a
1046                 // northbound request
1047                 HostNodeConnector transHost = hostsDB.get(networkAddr);
1048                 transHost.setStaticHost(true);
1049                 return new Status(StatusCode.SUCCESS, null);
1050             }
1051
1052             if (hostsDB.get(networkAddr) != null) {
1053                 // There is already a host with this IP address (but behind
1054                 // a different (switch, port, vlan) tuple. Return an error
1055                 return new Status(StatusCode.CONFLICT, "Existing IP, Use PUT to update");
1056             }
1057             host.setStaticHost(true);
1058             /*
1059              * Check if the nc is an ISL port
1060              */
1061             if (topologyManager != null) {
1062                 if (topologyManager.isInternal(nc)) {
1063                     return new Status(StatusCode.BADREQUEST, "Cannot add host on ISL port");
1064                 }
1065             }
1066             /*
1067              * Before adding host, Check if the switch and the port have already
1068              * come up
1069              */
1070             if (switchManager.isNodeConnectorEnabled(nc)) {
1071                 learnNewHost(host);
1072                 notifyHostLearnedOrRemoved(host, true);
1073             } else {
1074                 inactiveStaticHosts.put(nc, host);
1075                 logger.debug("Switch or switchport is not up, adding host {} to inactive list",
1076                         networkAddr.getHostName());
1077             }
1078             return new Status(StatusCode.SUCCESS, null);
1079         } catch (ConstructionException e) {
1080             logger.error("", e);
1081             return new Status(StatusCode.INTERNALERROR, "Host could not be created");
1082         }
1083
1084     }
1085
1086     /**
1087      * Update the controller IP to MAC binding of a host and its connectivity to
1088      * an openflow switch in terms of switch id, switch port, and VLAN.
1089      *
1090      * @param networkAddr
1091      *            IP address of the host
1092      * @param dataLayer
1093      *            Address MAC address of the host
1094      * @param nc
1095      *            NodeConnector to which host is connected
1096      * @param port
1097      *            Port of the switch to which host is connected
1098      * @param vlan
1099      *            Vlan of which this host is member of
1100      *
1101      * @return Status The status object as described in {@code Status}
1102      *         indicating the result of this action.
1103      */
1104     public Status updateHostReq(InetAddress networkAddr, byte[] dataLayerAddress, NodeConnector nc, short vlan) {
1105         HostNodeConnector tobeUpdatedHost;
1106         HostNodeConnector host = null;
1107
1108         if (dataLayerAddress.length != NetUtils.MACAddrLengthInBytes) {
1109             return new Status(StatusCode.BADREQUEST, "Invalid MAC address");
1110         }
1111
1112         if (nc == null) {
1113             return new Status(StatusCode.BADREQUEST, "Invalid NodeConnector");
1114         }
1115
1116         try {
1117             host = new HostNodeConnector(dataLayerAddress, networkAddr, nc, vlan);
1118             if (hostExists(host)) {
1119                 return new Status(StatusCode.BADREQUEST, "Host already exists");
1120             }
1121
1122             if ((tobeUpdatedHost = hostsDB.get(networkAddr)) != null) {
1123                 if (hostsDB.replace(networkAddr, tobeUpdatedHost, host)) {
1124                     logger.debug("Host replaced from hostsDB. Old host: {} New Host: {}", tobeUpdatedHost, host);
1125                     notifyHostLearnedOrRemoved(tobeUpdatedHost, false);
1126                     notifyHostLearnedOrRemoved(host, true);
1127                     return new Status(StatusCode.SUCCESS);
1128                 } else {
1129                     logger.error("Static host replacement failed from hostsDB, Replaced Host: {}, New Host: {}",
1130                             tobeUpdatedHost, host);
1131                     return new Status(StatusCode.INTERNALERROR,
1132                             "Host Replacement Failed due to presence of another host with same IP");
1133                 }
1134             }
1135
1136             // Check if the host exists in inactive hosts database
1137             if ((tobeUpdatedHost = inactiveStaticHosts.get(nc)) != null) {
1138                 if (inactiveStaticHosts.replace(nc, tobeUpdatedHost, host)) {
1139                     logger.debug("Host replaced from inactive hostsDB. Old host: {} New Host: {}", tobeUpdatedHost,
1140                             host);
1141                     return new Status(StatusCode.SUCCESS);
1142                 } else {
1143                     logger.error("Static host replacement failed, Replaced Host: {}, New Host: {}", tobeUpdatedHost,
1144                             host);
1145                     return new Status(StatusCode.INTERNALERROR,
1146                             "Host Replacement Failed due to presence of another host with same IP");
1147                 }
1148             }
1149
1150             // Host doesn't exist
1151             return new Status(StatusCode.BADREQUEST, "Host doesn't exists, can't update");
1152         } catch (ConstructionException e) {
1153             logger.error("", e);
1154             return new Status(StatusCode.INTERNALERROR, "host object creation failure");
1155         }
1156     }
1157
1158     /**
1159      * Remove from the controller IP to MAC binding of a host and its
1160      * connectivity to an openflow switch
1161      *
1162      * @param networkAddr
1163      *            IP address of the host
1164      *
1165      * @return boolean true if the host was removed successfully, false
1166      *         otherwise
1167      */
1168
1169     public Status removeStaticHostReq(InetAddress networkAddress) {
1170         // Check if host is in active hosts database
1171         HostNodeConnector host = getHostFromOnActiveDB(networkAddress);
1172         if (host != null) {
1173             // Validation check
1174             if (!host.isStaticHost()) {
1175                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1176             }
1177             // Remove and notify
1178             notifyHostLearnedOrRemoved(host, false);
1179             removeKnownHost(networkAddress);
1180             return new Status(StatusCode.SUCCESS, null);
1181         }
1182
1183         // Check if host is in inactive hosts database
1184         Entry<NodeConnector, HostNodeConnector> entry = getHostFromInactiveDB(networkAddress);
1185         if (entry != null) {
1186             host = entry.getValue();
1187             // Validation check
1188             if (!host.isStaticHost()) {
1189                 return new Status(StatusCode.FORBIDDEN, "Host " + networkAddress.getHostName() + " is not static");
1190             }
1191             this.removeHostFromInactiveDB(networkAddress);
1192             return new Status(StatusCode.SUCCESS, null);
1193         }
1194
1195         // Host is neither in active nor inactive hosts database
1196         return new Status(StatusCode.NOTFOUND, "Host does not exist");
1197     }
1198
1199     @Override
1200     public void modeChangeNotify(Node node, boolean proactive) {
1201         logger.debug("Set Switch {} Mode to {}", node.getID(), proactive);
1202     }
1203
1204     @Override
1205     public void notifyNode(Node node, UpdateType type, Map<String, Property> propMap) {
1206         if (node == null)
1207             return;
1208
1209         switch (type) {
1210         case REMOVED:
1211             logger.debug("Received removed node {}", node);
1212             for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1213                 HostNodeConnector host = entry.getValue();
1214                 if (host.getnodeconnectorNode().equals(node)) {
1215                     logger.debug("Node: {} is down, remove from Hosts_DB", node);
1216                     removeKnownHost(entry.getKey());
1217                     notifyHostLearnedOrRemoved(host, false);
1218                 }
1219             }
1220             break;
1221         default:
1222             break;
1223         }
1224     }
1225
1226     @Override
1227     public void notifyNodeConnector(NodeConnector nodeConnector, UpdateType type, Map<String, Property> propMap) {
1228         if (nodeConnector == null)
1229             return;
1230
1231         boolean up = false;
1232         switch (type) {
1233         case ADDED:
1234             up = true;
1235             break;
1236         case REMOVED:
1237             break;
1238         case CHANGED:
1239             State state = (State) propMap.get(State.StatePropName);
1240             if ((state != null) && (state.getValue() == State.EDGE_UP)) {
1241                 up = true;
1242             }
1243             break;
1244         default:
1245             return;
1246         }
1247
1248         if (up) {
1249             handleNodeConnectorStatusUp(nodeConnector);
1250         } else {
1251             handleNodeConnectorStatusDown(nodeConnector);
1252         }
1253     }
1254
1255     @Override
1256     public Status addStaticHost(String networkAddress, String dataLayerAddress, NodeConnector nc, String vlan) {
1257         try {
1258             InetAddress ip = InetAddress.getByName(networkAddress);
1259             if (nc == null) {
1260                 return new Status(StatusCode.BADREQUEST, "Invalid NodeId");
1261             }
1262             return addStaticHostReq(ip, HexEncode.bytesFromHexString(dataLayerAddress), nc, Short.valueOf(vlan));
1263         } catch (UnknownHostException e) {
1264             logger.error("", e);
1265             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1266         }
1267     }
1268
1269     @Override
1270     public Status removeStaticHost(String networkAddress) {
1271         InetAddress address;
1272         try {
1273             address = InetAddress.getByName(networkAddress);
1274             return removeStaticHostReq(address);
1275         } catch (UnknownHostException e) {
1276             logger.error("", e);
1277             return new Status(StatusCode.BADREQUEST, "Invalid Address");
1278         }
1279     }
1280
1281     private void handleNodeConnectorStatusUp(NodeConnector nodeConnector) {
1282         ARPPending arphost;
1283
1284         logger.debug("handleNodeConnectorStatusUp {}", nodeConnector);
1285
1286         for (int i = 0; i < failedARPReqList.size(); i++) {
1287             arphost = failedARPReqList.get(i);
1288             logger.debug("Sending the ARP from FailedARPReqList fors IP: {}", arphost.getHostIP().getHostAddress());
1289             if (hostFinder == null) {
1290                 logger.warn("ARPHandler is not available at interface  up");
1291                 logger.warn("Since this event is missed, host(s) connected to interface {} may not be discovered",
1292                         nodeConnector);
1293                 continue;
1294             }
1295             hostFinder.find(arphost.getHostIP());
1296         }
1297         HostNodeConnector host = inactiveStaticHosts.get(nodeConnector);
1298         if (host != null) {
1299             inactiveStaticHosts.remove(nodeConnector);
1300             learnNewHost(host);
1301             notifyHostLearnedOrRemoved(host, true);
1302         }
1303     }
1304
1305     private void handleNodeConnectorStatusDown(NodeConnector nodeConnector) {
1306         logger.debug("handleNodeConnectorStatusDown {}", nodeConnector);
1307
1308         for (Entry<InetAddress, HostNodeConnector> entry : hostsDB.entrySet()) {
1309             HostNodeConnector host = entry.getValue();
1310             if (host.getnodeConnector().equals(nodeConnector)) {
1311                 logger.debug(" NodeConnector: {} is down, remove from Hosts_DB", nodeConnector);
1312                 removeKnownHost(entry.getKey());
1313                 notifyHostLearnedOrRemoved(host, false);
1314             }
1315         }
1316     }
1317
1318     void setClusterContainerService(IClusterContainerServices s) {
1319         logger.debug("Cluster Service set");
1320         this.clusterContainerService = s;
1321     }
1322
1323     void unsetClusterContainerService(IClusterContainerServices s) {
1324         if (this.clusterContainerService == s) {
1325             logger.debug("Cluster Service removed!");
1326             this.clusterContainerService = null;
1327         }
1328     }
1329
1330     void setSwitchManager(ISwitchManager s) {
1331         logger.debug("SwitchManager set");
1332         this.switchManager = s;
1333     }
1334
1335     void unsetSwitchManager(ISwitchManager s) {
1336         if (this.switchManager == s) {
1337             logger.debug("SwitchManager removed!");
1338             this.switchManager = null;
1339         }
1340     }
1341
1342     public String getContainerName() {
1343         if (containerName == null)
1344             return GlobalConstants.DEFAULT.toString();
1345         return containerName;
1346     }
1347
1348     /**
1349      * Function called by the dependency manager when all the required
1350      * dependencies are satisfied
1351      *
1352      */
1353     void init(Component c) {
1354         Dictionary<?, ?> props = c.getServiceProperties();
1355         if (props != null) {
1356             this.containerName = (String) props.get("containerName");
1357             logger.debug("Running containerName: {}", this.containerName);
1358         } else {
1359             // In the Global instance case the containerName is empty
1360             this.containerName = "";
1361         }
1362         startUp();
1363     }
1364
1365     /**
1366      * Function called by the dependency manager when at least one dependency
1367      * become unsatisfied or when the component is shutting down because for
1368      * example bundle is being stopped.
1369      *
1370      */
1371     void destroy() {
1372     }
1373
1374     /**
1375      * Function called by dependency manager after "init ()" is called and after
1376      * the services provided by the class are registered in the service registry
1377      *
1378      */
1379     void start() {
1380     }
1381
1382     /**
1383      * Function called by the dependency manager before the services exported by
1384      * the component are unregistered, this will be followed by a "destroy ()"
1385      * calls
1386      *
1387      */
1388     void stop(){
1389     }
1390
1391     void stopping() {
1392         arpRefreshTimer.cancel();
1393         timer.cancel();
1394         executor.shutdown();
1395     }
1396
1397     @Override
1398     public void edgeOverUtilized(Edge edge) {
1399         // TODO Auto-generated method stub
1400
1401     }
1402
1403     @Override
1404     public void edgeUtilBackToNormal(Edge edge) {
1405         // TODO Auto-generated method stub
1406
1407     }
1408
1409 }