HA - ARPHandler Event sync 11/811/2
authorYevgeny Khodorkovsky <ykhodork@cisco.com>
Fri, 2 Aug 2013 23:38:14 +0000 (16:38 -0700)
committerYevgeny Khodorkovsky <ykhodork@cisco.com>
Tue, 6 Aug 2013 23:59:35 +0000 (16:59 -0700)
- Replay ARP request/reply events across the cluster using cluster
  allocated cache. Then the appropriate controller handles sending the
  ARP.
- Add isUnicastMAC() to NetUtils

Change-Id: I2d2b60348341710ffbd3ffc749ff52869b9c0b3f
Signed-off-by: Yevgeny Khodorkovsky <ykhodork@cisco.com>
12 files changed:
opendaylight/arphandler/pom.xml
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPEvent.java [new file with mode: 0644]
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java [new file with mode: 0644]
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java [new file with mode: 0644]
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/Activator.java
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java
opendaylight/hosttracker/implementation/pom.xml
opendaylight/hosttracker/implementation/src/main/java/org/opendaylight/controller/hosttracker/internal/HostTracker.java
opendaylight/hosttracker/integrationtest/src/test/java/org/opendaylight/controller/hosttracker/internal/HostTrackerIT.java
opendaylight/northbound/integrationtest/pom.xml
opendaylight/northbound/integrationtest/src/test/java/org/opendaylight/controller/northbound/integrationtest/NorthboundIT.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/NetUtils.java

index 069ad8d4a3d4e13adbd9df3509dbb7d3a80a3239..68b9c55830dc330a19454fa95533bd2992971be1 100644 (file)
         <configuration>
           <instructions>
             <Import-Package>
+              org.opendaylight.controller.connectionmanager,
               org.opendaylight.controller.sal.core,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.sal.packet,
               org.opendaylight.controller.switchmanager,
               org.opendaylight.controller.topologymanager,
+              org.opendaylight.controller.clustering.services,
               org.opendaylight.controller.hosttracker,
               org.opendaylight.controller.hosttracker.hostAware,
               org.apache.felix.dm,
               org.osgi.service.component,
               org.slf4j
             </Import-Package>
+            <Export-Package>
+              org.opendaylight.controller.arphandler
+            </Export-Package>
             <Bundle-Activator>
               org.opendaylight.controller.arphandler.internal.Activator
             </Bundle-Activator>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>switchmanager</artifactId>
       <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>connectionmanager</artifactId>
+      <version>0.1.0-SNAPSHOT</version>
     </dependency>
      <dependency>
       <groupId>org.opendaylight.controller</groupId>
diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPEvent.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPEvent.java
new file mode 100644 (file)
index 0000000..fb92e8d
--- /dev/null
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.arphandler;
+
+import java.io.Serializable;
+import java.net.InetAddress;
+/*
+ * ARP Event base class
+ */
+public abstract class ARPEvent implements Serializable{
+
+    private static final long serialVersionUID = 1L;
+    private final InetAddress tIP;
+
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = prime + ((tIP == null) ? 0 : tIP.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ARPEvent)) {
+            return false;
+        }
+        ARPEvent other = (ARPEvent) obj;
+        if (tIP == null) {
+            if (other.tIP != null) {
+                return false;
+            }
+        } else if (!tIP.equals(other.tIP)) {
+            return false;
+        }
+        return true;
+    }
+
+    public ARPEvent(InetAddress ip) {
+        this.tIP = ip;
+    }
+
+    public InetAddress getTargetIP() {
+        return tIP;
+    }
+}
diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPReply.java
new file mode 100644 (file)
index 0000000..4ca3e42
--- /dev/null
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.arphandler;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+import org.opendaylight.controller.sal.core.NodeConnector;
+/*
+ * ARP Reply event wrapper
+ */
+public class ARPReply extends ARPEvent {
+
+    private final NodeConnector port;
+    private final byte[] tMac;
+    private final byte[] sMac;
+    private final InetAddress sIP;
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((sIP == null) ? 0 : sIP.hashCode());
+        result = prime * result + Arrays.hashCode(sMac);
+        result = prime * result + Arrays.hashCode(tMac);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ARPReply)) {
+            return false;
+        }
+        ARPReply other = (ARPReply) obj;
+        if (sIP == null) {
+            if (other.sIP != null) {
+                return false;
+            }
+        } else if (!sIP.equals(other.sIP)) {
+            return false;
+        }
+        if (!Arrays.equals(sMac, other.sMac)) {
+            return false;
+        }
+        if (!Arrays.equals(tMac, other.tMac)) {
+            return false;
+        }
+        return true;
+    }
+
+    public ARPReply(NodeConnector port, InetAddress sIP, byte[] sMAC, InetAddress tIP, byte[] tMAC) {
+        super(tIP);
+        this.tMac = tMAC;
+        this.sIP = sIP;
+        this.sMac = sMAC;
+        this.port = port;
+    }
+
+    public ARPReply(InetAddress tIP, byte[] tMAC) {
+        super(tIP);
+        this.tMac = tMAC;
+        this.sIP = null;
+        this.sMac = null;
+        this.port = null;
+    }
+
+    public byte[] getTargetMac() {
+        return tMac;
+    }
+
+    public byte[] getSourceMac() {
+        return sMac;
+    }
+
+    public InetAddress getSourceIP() {
+        return sIP;
+    }
+
+    public NodeConnector getPort() {
+        return port;
+    }
+}
diff --git a/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java b/opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/ARPRequest.java
new file mode 100644 (file)
index 0000000..7f88a25
--- /dev/null
@@ -0,0 +1,85 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.arphandler;
+
+import java.net.InetAddress;
+
+import org.opendaylight.controller.arphandler.ARPEvent;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.switchmanager.Subnet;
+/*
+ * ARP Request event wrapper Consists of IP and Subnet (and a
+ * HostNodeConnector if is unicast) For unicast request, construct with a
+ * specified host
+ */
+public class ARPRequest extends ARPEvent {
+    private final Subnet subnet;
+    private final HostNodeConnector host;
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((host == null) ? 0 : host.hashCode());
+        result = prime * result + ((subnet == null) ? 0 : subnet.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ARPRequest)) {
+            return false;
+        }
+        ARPRequest other = (ARPRequest) obj;
+        if (host == null) {
+            if (other.host != null) {
+                return false;
+            }
+        } else if (!host.equals(other.host)) {
+            return false;
+        }
+        if (subnet == null) {
+            if (other.subnet != null) {
+                return false;
+            }
+        } else if (!subnet.equals(other.subnet)) {
+            return false;
+        }
+        return true;
+    }
+
+    // broadcast
+    public ARPRequest(InetAddress ip, Subnet subnet) {
+        super(ip);
+        this.subnet = subnet;
+        this.host = null;
+    }
+
+    // unicast
+    public ARPRequest(HostNodeConnector host, Subnet subnet) {
+        super(host.getNetworkAddress());
+        this.host = host;
+        this.subnet = subnet;
+    }
+
+    public Subnet getSubnet() {
+        return subnet;
+    }
+
+    public HostNodeConnector getHost() {
+        return host;
+    }
+}
index 705ffbfa632d94237ee8c55d4f8eec753969d935..248623cce8326e93288498d9af9ec15d92b100a2 100644 (file)
@@ -9,20 +9,25 @@
 
 package org.opendaylight.controller.arphandler.internal;
 
-import java.util.Hashtable;
 import java.util.Dictionary;
-import org.apache.felix.dm.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
 
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.connectionmanager.IConnectionManager;
 import org.opendaylight.controller.hosttracker.IfHostListener;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
 import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
-import org.opendaylight.controller.sal.packet.IListenDataPacket;
 import org.opendaylight.controller.sal.packet.IDataPacketService;
+import org.opendaylight.controller.sal.packet.IListenDataPacket;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 import org.opendaylight.controller.topologymanager.ITopologyManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class Activator extends ComponentActivatorAbstractBase {
     protected static final Logger logger = LoggerFactory
@@ -77,10 +82,22 @@ public class Activator extends ComponentActivatorAbstractBase {
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(ArpHandler.class)) {
             // export the service
-            Dictionary<String, String> props = new Hashtable<String, String>();
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
             props.put("salListenerName", "arphandler");
-            c.setInterface(new String[] { IHostFinder.class.getName(),
-                    IListenDataPacket.class.getName() }, props);
+            Set<String> propSet = new HashSet<String>();
+            propSet.add(ArpHandler.ARP_EVENT_CACHE_NAME);
+            props.put("cachenames", propSet);
+
+            c.setInterface(new String[] {
+                    IHostFinder.class.getName(),
+                    IListenDataPacket.class.getName(),
+                    ICacheUpdateAware.class.getName()}, props);
+
+            // We need connection mgr to distribute packet out across the cluster
+            c.add(createServiceDependency().setService(
+                    IConnectionManager.class).setCallbacks("setConnectionManager",
+                    "unsetConnectionManager").setRequired(true));
+
 
             c.add(createContainerServiceDependency(containerName).setService(
                     ISwitchManager.class).setCallbacks("setSwitchManager",
@@ -90,11 +107,16 @@ public class Activator extends ComponentActivatorAbstractBase {
                     ITopologyManager.class).setCallbacks("setTopologyManager",
                     "unsetTopologyMananger").setRequired(true));
 
-           c.add(createContainerServiceDependency(containerName).setService(
+            c.add(createContainerServiceDependency(containerName).setService(
                     IDataPacketService.class).setCallbacks(
                     "setDataPacketService", "unsetDataPacketService")
                     .setRequired(true));
 
+            c.add(createContainerServiceDependency(containerName).setService(
+                   IClusterContainerServices.class).setCallbacks(
+                   "setClusterContainerService", "unsetClusterContainerService")
+                   .setRequired(true));
+
             // the Host Listener is optional
             c.add(createContainerServiceDependency(containerName).setService(
                     IfHostListener.class).setCallbacks("setHostListener",
index 811c7aca8370525d13bcabd2ef46d898bcc4a88f..0ff1cd9bd6a542dc8694b09933bfe2c1835d3bbd 100644 (file)
@@ -16,13 +16,24 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.opendaylight.controller.arphandler.ARPEvent;
+import org.opendaylight.controller.arphandler.ARPReply;
+import org.opendaylight.controller.arphandler.ARPRequest;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.connectionmanager.IConnectionManager;
 import org.opendaylight.controller.hosttracker.IfHostListener;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
@@ -31,7 +42,6 @@ import org.opendaylight.controller.sal.core.ConstructionException;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.BitBufferHelper;
 import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.IDataPacketService;
 import org.opendaylight.controller.sal.packet.IListenDataPacket;
@@ -48,28 +58,58 @@ import org.opendaylight.controller.topologymanager.ITopologyManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ArpHandler implements IHostFinder, IListenDataPacket {
-    private static final Logger logger = LoggerFactory
-            .getLogger(ArpHandler.class);
-    private IfIptoHost hostTracker = null;
-    private ISwitchManager switchManager = null;
+public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateAware<ARPEvent, Boolean> {
+    private static final Logger log = LoggerFactory.getLogger(ArpHandler.class);
+    static final String ARP_EVENT_CACHE_NAME = "arphandler.arpRequestReplyEvent";
+    private IfIptoHost hostTracker;
+    private ISwitchManager switchManager;
     private ITopologyManager topologyManager;
-    private IDataPacketService dataPacketService = null;
-    private Set<IfHostListener> hostListener = Collections
-            .synchronizedSet(new HashSet<IfHostListener>());
+    private IDataPacketService dataPacketService;
+    private IClusterContainerServices clusterContainerService;
+    private IConnectionManager connectionManager;
+    private Set<IfHostListener> hostListeners = new CopyOnWriteArraySet<IfHostListener>();
     private ConcurrentMap<InetAddress, Set<HostNodeConnector>> arpRequestors;
     private ConcurrentMap<InetAddress, Short> countDownTimers;
     private Timer periodicTimer;
+    /*
+     * A cluster allocated cache. Used for synchronizing ARP request/reply
+     * events across all cluster controllers. To raise an event, we put() a specific
+     * event object (as key) and all nodes handle it in the entryUpdated callback.
+     *
+     * In case of ARPReply, we put true value to send replies to any requestors
+     * by calling generateAndSendReply
+     */
+    private ConcurrentMap<ARPEvent, Boolean> arpRequestReplyEvent;
+
+    void setConnectionManager(IConnectionManager cm){
+        this.connectionManager = cm;
+    }
+
+    void unsetConnectionManager(IConnectionManager cm){
+        if (this.connectionManager == cm){
+            connectionManager = null;
+        }
+    }
+
+    void setClusterContainerService(IClusterContainerServices s){
+        this.clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (this.clusterContainerService == s) {
+            this.clusterContainerService = null;
+        }
+    }
 
     void setHostListener(IfHostListener s) {
-        if (this.hostListener != null) {
-            this.hostListener.add(s);
+        if (this.hostListeners != null) {
+            this.hostListeners.add(s);
         }
     }
 
     void unsetHostListener(IfHostListener s) {
-        if (this.hostListener != null) {
-            this.hostListener.remove(s);
+        if (this.hostListeners != null) {
+            this.hostListeners.remove(s);
         }
     }
 
@@ -83,17 +123,13 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         }
     }
 
-    public IfIptoHost getHostTracker() {
-        return hostTracker;
-    }
-
     public void setHostTracker(IfIptoHost hostTracker) {
-        logger.debug("Setting HostTracker");
+        log.debug("Setting HostTracker");
         this.hostTracker = hostTracker;
     }
 
     public void unsetHostTracker(IfIptoHost s) {
-        logger.debug("UNSetting HostTracker");
+        log.debug("UNSetting HostTracker");
         if (this.hostTracker == s) {
             this.hostTracker = null;
         }
@@ -114,17 +150,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         byte[] senderIP = sIP.getAddress();
         byte[] targetIP = tIP.getAddress();
         ARP arp = new ARP();
-        arp.setHardwareType(ARP.HW_TYPE_ETHERNET).setProtocolType(
-                EtherTypes.IPv4.shortValue())
-                .setHardwareAddressLength((byte) 6).setProtocolAddressLength(
-                        (byte) 4).setOpCode(ARP.REPLY)
-                .setSenderHardwareAddress(sMAC).setSenderProtocolAddress(
-                        senderIP).setTargetHardwareAddress(tMAC)
-                .setTargetProtocolAddress(targetIP);
+        arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
+            .setProtocolType(EtherTypes.IPv4.shortValue())
+            .setHardwareAddressLength((byte) 6)
+            .setProtocolAddressLength((byte) 4)
+            .setOpCode(ARP.REPLY)
+            .setSenderHardwareAddress(sMAC)
+            .setSenderProtocolAddress(senderIP)
+            .setTargetHardwareAddress(tMAC)
+            .setTargetProtocolAddress(targetIP);
 
         Ethernet ethernet = new Ethernet();
-        ethernet.setSourceMACAddress(sMAC).setDestinationMACAddress(tMAC)
-                .setEtherType(EtherTypes.ARP.shortValue()).setPayload(arp);
+        ethernet.setSourceMACAddress(sMAC)
+            .setDestinationMACAddress(tMAC)
+            .setEtherType(EtherTypes.ARP.shortValue())
+            .setPayload(arp);
 
         RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet);
         destPkt.setOutgoingNodeConnector(p);
@@ -132,114 +172,79 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         this.dataPacketService.transmitDataPacket(destPkt);
     }
 
-    private boolean isBroadcastMAC(byte[] mac) {
-        if (BitBufferHelper.toNumber(mac) == 0xffffffffffffL) { //TODO: implement this in our Ethernet
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isUnicastMAC(byte[] mac) {
-        if ((BitBufferHelper.toNumber(mac) & 0x010000000000L) == 0) {
-            return true;
-        }
-        return false;
-    }
-
     protected void handleARPPacket(Ethernet eHeader, ARP pkt, NodeConnector p) {
-        if (pkt.getOpCode() == 0x1) {
-            logger.debug("Received ARP REQUEST Packet from NodeConnector: {}",
-                         p);
-        } else {
-            logger.debug("Received ARP REPLY Packet from NodeConnector: {}",
-                         p);
-        }
-        InetAddress targetIP = null;
-        try {
-            targetIP = InetAddress.getByAddress(pkt.getTargetProtocolAddress());
-        } catch (UnknownHostException e1) {
-            return;
-        }
-        InetAddress sourceIP = null;
-        try {
-            sourceIP = InetAddress.getByAddress(pkt.getSenderProtocolAddress());
-        } catch (UnknownHostException e1) {
-            return;
-        }
-        byte[] targetMAC = eHeader.getDestinationMACAddress();
-        byte[] sourceMAC = eHeader.getSourceMACAddress();
 
+        byte[] sourceMAC = eHeader.getSourceMACAddress();
+        byte[] targetMAC = eHeader.getDestinationMACAddress();
         /*
          * Sanity Check; drop ARP packets originated by the controller itself.
          * This is to avoid continuous flooding
          */
         if (Arrays.equals(sourceMAC, getControllerMAC())) {
-            if (logger.isDebugEnabled()) {
-              logger.debug(
-                    "Receive the self originated packet (srcMAC {}) --> DROP",
-                    HexEncode.bytesToHexString(sourceMAC));
+            if (log.isDebugEnabled()) {
+                log.debug("Receive a self originated ARP pkt (srcMAC {}) --> DROP",
+                        HexEncode.bytesToHexString(sourceMAC));
             }
             return;
         }
 
+        InetAddress targetIP, sourceIP;
+        try {
+            targetIP = InetAddress.getByAddress(pkt.getTargetProtocolAddress());
+            sourceIP = InetAddress.getByAddress(pkt.getSenderProtocolAddress());
+        } catch (UnknownHostException e1) {
+            log.debug("Invalid host in ARP packet: {}", e1.getMessage());
+            return;
+        }
+
         Subnet subnet = null;
         if (switchManager != null) {
             subnet = switchManager.getSubnetByNetworkAddress(sourceIP);
         }
         if (subnet == null) {
-            logger.debug("can't find subnet matching {}, drop packet",sourceIP);
+            log.debug("ARPHandler: can't find subnet matching {}, drop packet", sourceIP);
             return;
         }
-        logger.debug("Found {} matching {}", subnet, sourceIP);
-        /*
-         * Make sure that the host is a legitimate member of this subnet
-         */
+
+        // Make sure that the host is a legitimate member of this subnet
         if (!subnet.hasNodeConnector(p)) {
-            logger.debug("{} showing up on {} does not belong to {}",
+            log.debug("{} showing up on {} does not belong to {}",
                     new Object[] { sourceIP, p, subnet });
             return;
         }
 
         HostNodeConnector requestor = null;
-        if (isUnicastMAC(sourceMAC)) {
-            // TODO For not this is only OPENFLOW but we need to fix this
-            if (p.getType().equals(
-                    NodeConnector.NodeConnectorIDType.OPENFLOW)) {
-                try {
-                    requestor = new HostNodeConnector(sourceMAC, sourceIP, p, subnet
-                            .getVlan());
-                } catch (ConstructionException e) {
-                    return;
-                }
-                /*
-                 * Learn host from the received ARP REQ/REPLY, inform
-                 * Host Tracker
-                 */
-                logger.debug("Inform Host tracker of new host {}", requestor.getNetworkAddress());
-                synchronized (this.hostListener) {
-                    for (IfHostListener listener : this.hostListener) {
-                        listener.hostListener(requestor);
-                    }
-                }
+        if (NetUtils.isUnicastMACAddr(sourceMAC) && p.getNode() != null) {
+            try {
+                requestor = new HostNodeConnector(sourceMAC, sourceIP, p, subnet.getVlan());
+            } catch (ConstructionException e) {
+                log.debug("Received ARP packet with invalid MAC: {}", sourceMAC);
+                return;
+            }
+            /*
+             * Learn host from the received ARP REQ/REPLY, inform Host Tracker
+             */
+            log.trace("Inform Host tracker of new host {}", requestor.getNetworkAddress());
+            for (IfHostListener listener : this.hostListeners) {
+                listener.hostListener(requestor);
             }
-        }
-        /*
-         * Gratuitous ARP. If there are hosts (in arpRequestors) waiting for the
-         * ARP reply for this sourceIP, it's time to generate the reply and it
-         * to these hosts
-         */
-        if (sourceIP.equals(targetIP)) {
-            generateAndSendReply(sourceIP, sourceMAC);
-            return;
         }
 
         /*
-         * ARP Reply. If there are hosts (in arpRequesttors) waiting for the ARP
-         * reply for this sourceIP, it's time to generate the reply and it to
-         * these hosts
+         * OpCode != request -> ARP Reply. If there are hosts (in
+         * arpRequestors) waiting for the ARP reply for this sourceIP, it's
+         * time to generate the reply and send it to these hosts.
+         *
+         * If sourceIP==targetIP, it is a Gratuitous ARP. If there are hosts (in
+         * arpRequestors) waiting for the ARP reply for this sourceIP, it's time
+         * to generate the reply and send it to these hosts
          */
-        if (pkt.getOpCode() != ARP.REQUEST) {
-            generateAndSendReply(sourceIP, sourceMAC);
+
+        if (pkt.getOpCode() != ARP.REQUEST || sourceIP.equals(targetIP)) {
+            // Raise a reply event so that any waiting requestors will be sent a reply
+            // the true value indicates we should generate replies to requestors across the cluster
+            log.trace("Received ARP reply packet from {}, reply to all requestors.", sourceIP);
+            arpRequestReplyEvent.put(new ARPReply(sourceIP, sourceMAC), true);
             return;
         }
 
@@ -251,55 +256,71 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
          * the IP address defined in the subnet as source address
          */
         /*
-         * Send ARP reply if target IP is gateway IP
+         * If target IP is gateway IP, Send ARP reply
          */
         if ((targetIP.equals(subnet.getNetworkAddress()))
-                && (isBroadcastMAC(targetMAC) || Arrays.equals(targetMAC,
-                        getControllerMAC()))) {
-            sendARPReply(p, getControllerMAC(), targetIP, pkt
-                    .getSenderHardwareAddress(), sourceIP);
+                && (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(targetMAC, getControllerMAC()))) {
+            if (connectionManager.isLocal(p.getNode())){
+                if (log.isTraceEnabled()){
+                    log.trace("Received local ARP req. for default gateway. Replying with controller MAC: {}", getControllerMAC());
+                }
+                sendARPReply(p, getControllerMAC(), targetIP, pkt.getSenderHardwareAddress(), sourceIP);
+            } else {
+                log.trace("Received non-local ARP req. for default gateway. Raising reply event");
+                arpRequestReplyEvent.put(
+                        new ARPReply(p, targetIP, getControllerMAC(), sourceIP, pkt.getSenderHardwareAddress()), false);
+            }
             return;
         }
 
-        /*
-         * unknown host, initiate ARP request
-         */
+
         HostNodeConnector host = hostTracker.hostQuery(targetIP);
+        // unknown host, initiate ARP request
         if (host == null) {
             // add the requestor to the list so that we can replay the reply
             // when the host responds
             if (requestor != null) {
-                Set<HostNodeConnector> requestorSet = arpRequestors
-                        .get(targetIP);
-                if ((requestorSet == null) || requestorSet.isEmpty()) {
-                    requestorSet = new HashSet<HostNodeConnector>();
-                    countDownTimers.put(targetIP, (short) 2); // set max timeout
-                                                              // to 2sec
+                Set<HostNodeConnector> requestorSet = arpRequestors.get(targetIP);
+                if (requestorSet == null) {
+                    requestorSet = Collections.newSetFromMap(new ConcurrentHashMap<HostNodeConnector, Boolean>());
+                    arpRequestors.put(targetIP, requestorSet);
                 }
                 requestorSet.add(requestor);
-                arpRequestors.put(targetIP, requestorSet);
+                countDownTimers.put(targetIP, (short) 2); // reset timeout to 2sec
             }
-            sendBcastARPRequest(targetIP, subnet);
-            return;
-        }
-        /*
-         * Known target host, send ARP REPLY
-         * make sure that targetMAC matches the host's MAC if it is not broadcastMAC
-         */
-        if (isBroadcastMAC(targetMAC)
-                || Arrays.equals(host.getDataLayerAddressBytes(), targetMAC)) {
-            sendARPReply(p, host.getDataLayerAddressBytes(), host
-                    .getNetworkAddress(), pkt.getSenderHardwareAddress(),
-                    sourceIP);
-            return;
+            //Raise a bcast request event, all controllers need to send one
+            log.trace("Sending a bcast ARP request for {}", targetIP);
+            arpRequestReplyEvent.put(new ARPRequest(targetIP, subnet), false);
+
         } else {
             /*
-             * target target MAC has been changed. For now, discard it.
-             * TODO: We may need to send unicast ARP REQUEST on behalf of the
-             * target back to the sender to trigger the sender to
-             * update its table
+             * Target host known (across the cluster), send ARP REPLY make sure that targetMAC
+             * matches the host's MAC if it is not broadcastMAC
              */
-            return;
+            if (NetUtils.isBroadcastMACAddr(targetMAC) || Arrays.equals(host.getDataLayerAddressBytes(), targetMAC)) {
+                log.trace("Received ARP req. for known host {}, sending reply...", targetIP);
+                if (connectionManager.isLocal(p.getNode())) {
+                    sendARPReply(p,
+                            host.getDataLayerAddressBytes(),
+                            host.getNetworkAddress(),
+                            pkt.getSenderHardwareAddress(),
+                            sourceIP);
+                } else {
+                    arpRequestReplyEvent.put(new ARPReply(
+                            p,
+                            host.getNetworkAddress(),
+                            host.getDataLayerAddressBytes(),
+                            sourceIP,
+                            pkt.getSenderHardwareAddress()), false);
+                }
+            } else {
+                /*
+                 * Target MAC has been changed. For now, discard it.
+                 * TODO: We may need to send unicast ARP REQUEST on behalf of
+                 * the target back to the sender to trigger the sender to update
+                 * its table
+                 */
+            }
         }
     }
 
@@ -314,19 +335,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         if (subnet.isFlatLayer2()) {
             nodeConnectors = new HashSet<NodeConnector>();
             for (Node n : this.switchManager.getNodes()) {
-                nodeConnectors.addAll(this.switchManager
-                        .getUpNodeConnectors(n));
+                nodeConnectors.addAll(this.switchManager.getUpNodeConnectors(n));
             }
         } else {
             nodeConnectors = subnet.getNodeConnectors();
         }
+
         for (NodeConnector p : nodeConnectors) {
-            if (topologyManager.isInternal(p)) {
+
+            //fiter out any non-local or internal ports
+            if (! connectionManager.isLocal(p.getNode()) || topologyManager.isInternal(p)) {
                 continue;
             }
             ARP arp = new ARP();
             byte[] senderIP = subnet.getNetworkAddress().getAddress();
-            byte[] targetIPB = targetIP.getAddress();
+            byte[] targetIPByte = targetIP.getAddress();
             arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
                .setProtocolType(EtherTypes.IPv4.shortValue())
                .setHardwareAddressLength((byte) 6)
@@ -334,14 +357,13 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
                .setOpCode(ARP.REQUEST)
                .setSenderHardwareAddress(getControllerMAC())
                .setSenderProtocolAddress(senderIP)
-               .setTargetHardwareAddress(new byte[] { (byte) 0, (byte) 0,
-                                                     (byte) 0, (byte) 0,
-                                                     (byte) 0, (byte) 0 })
-               .setTargetProtocolAddress(targetIPB);
+               .setTargetHardwareAddress(
+                       new byte[] { (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 })
+               .setTargetProtocolAddress(targetIPByte);
 
             Ethernet ethernet = new Ethernet();
             ethernet.setSourceMACAddress(getControllerMAC())
-                    .setDestinationMACAddress(new byte[] { (byte) -1,
+                    .setDestinationMACAddress(new byte[] {(byte) -1,
                                                           (byte) -1,
                                                           (byte) -1,
                                                           (byte) -1,
@@ -365,19 +387,10 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
      * The sender MAC is the controller's MAC
      */
     protected void sendUcastARPRequest(HostNodeConnector host, Subnet subnet) {
-        //Long swID = host.getnodeconnectornodeId();
-        //Short portID = host.getnodeconnectorportId();
-        //Node n = NodeCreator.createOFNode(swID);
-        Node n = host.getnodeconnectorNode();
-        if (n == null) {
-            logger.error("cannot send UcastARP because cannot extract node "
-                    + "from HostNodeConnector: {}", host);
-            return;
-        }
+
         NodeConnector outPort = host.getnodeConnector();
         if (outPort == null) {
-            logger.error("cannot send UcastARP because cannot extract "
-                    + "outPort from HostNodeConnector: {}", host);
+            log.error("Failed sending UcastARP because cannot extract output port from Host: {}", host);
             return;
         }
 
@@ -385,18 +398,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         byte[] targetIP = host.getNetworkAddress().getAddress();
         byte[] targetMAC = host.getDataLayerAddressBytes();
         ARP arp = new ARP();
-        arp.setHardwareType(ARP.HW_TYPE_ETHERNET).setProtocolType(
-                EtherTypes.IPv4.shortValue())
-                .setHardwareAddressLength((byte) 6).setProtocolAddressLength(
-                        (byte) 4).setOpCode(ARP.REQUEST)
-                .setSenderHardwareAddress(getControllerMAC())
-                .setSenderProtocolAddress(senderIP).setTargetHardwareAddress(
-                        targetMAC).setTargetProtocolAddress(targetIP);
+        arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
+            .setProtocolType(EtherTypes.IPv4.shortValue())
+            .setHardwareAddressLength((byte) 6)
+            .setProtocolAddressLength((byte) 4)
+            .setOpCode(ARP.REQUEST)
+            .setSenderHardwareAddress(getControllerMAC())
+            .setSenderProtocolAddress(senderIP)
+            .setTargetHardwareAddress(targetMAC)
+            .setTargetProtocolAddress(targetIP);
 
         Ethernet ethernet = new Ethernet();
         ethernet.setSourceMACAddress(getControllerMAC())
-                .setDestinationMACAddress(targetMAC).setEtherType(
-                        EtherTypes.ARP.shortValue()).setPayload(arp);
+                .setDestinationMACAddress(targetMAC)
+                .setEtherType(EtherTypes.ARP.shortValue())
+                .setPayload(arp);
 
         RawPacket destPkt = this.dataPacketService.encodeDataPacket(ethernet);
         destPkt.setOutgoingNodeConnector(outPort);
@@ -405,27 +421,26 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
     }
 
     public void find(InetAddress networkAddress) {
-        logger.debug("Received find IP {}", networkAddress);
+        log.trace("Received find IP {}", networkAddress);
 
         Subnet subnet = null;
         if (switchManager != null) {
             subnet = switchManager.getSubnetByNetworkAddress(networkAddress);
         }
         if (subnet == null) {
-            logger.debug("can't find subnet matching IP {}", networkAddress);
+            log.debug("Can't find subnet matching IP {}", networkAddress);
             return;
         }
-        logger.debug("found subnet {}", subnet);
 
-        // send a broadcast ARP Request to this interface
-        sendBcastARPRequest(networkAddress, subnet);
+        // send a broadcast ARP Request to this IP
+        arpRequestReplyEvent.put(new ARPRequest(networkAddress, subnet), false);
     }
 
     /*
      * Probe the host by sending a unicast ARP Request to the host
      */
     public void probe(HostNodeConnector host) {
-        logger.debug("Received probe host {}", host);
+        log.trace("Received probe host {}", host);
 
         Subnet subnet = null;
         if (switchManager != null) {
@@ -433,11 +448,17 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
                     .getNetworkAddress());
         }
         if (subnet == null) {
-            logger.debug("can't find subnet matching {}", host
-                    .getNetworkAddress());
+            log.debug("can't find subnet matching {}", host.getNetworkAddress());
             return;
         }
-        sendUcastARPRequest(host, subnet);
+
+        if (connectionManager.isLocal(host.getnodeconnectorNode())){
+            log.trace("Send a ucast ARP req. to: {}", host);
+            sendUcastARPRequest(host, subnet);
+        } else {
+            log.trace("Raise a ucast ARP req. event to: {}", host);
+            arpRequestReplyEvent.put(new ARPRequest(host, subnet), false);
+        }
     }
 
     /*
@@ -446,12 +467,10 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
      * Need to discover it by sending a Broadcast ARP Request
      */
     protected void handlePuntedIPPacket(IPv4 pkt, NodeConnector p) {
-        InetAddress dIP = null;
-        try {
-            dIP = InetAddress.getByAddress(NetUtils.intToByteArray4(pkt
-                    .getDestinationAddress()));
-        } catch (UnknownHostException e1) {
-            return;
+
+        InetAddress dIP = NetUtils.getInetAddress(pkt.getDestinationAddress());
+        if (dIP == null) {
+           return;
         }
 
         Subnet subnet = null;
@@ -459,14 +478,14 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
             subnet = switchManager.getSubnetByNetworkAddress(dIP);
         }
         if (subnet == null) {
-            logger.debug("can't find subnet matching {}, drop packet", dIP);
+            log.debug("Can't find subnet matching {}, drop packet", dIP);
             return;
         }
-        logger.debug("Found {} matching {}", subnet, dIP);
+        log.trace("Punted IP pkt from {}, sending bcast ARP event...", dIP);
         /*
-         * unknown destination host, initiate ARP request
+         * unknown destination host, initiate bcast ARP request
          */
-        sendBcastARPRequest(dIP, subnet);
+        arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false);
         return;
     }
 
@@ -485,8 +504,50 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
     void init() {
         arpRequestors = new ConcurrentHashMap<InetAddress, Set<HostNodeConnector>>();
         countDownTimers = new ConcurrentHashMap<InetAddress, Short>();
+
+        allocateCaches();
+        retrieveCaches();
+    }
+
+    @SuppressWarnings({ "unchecked", "deprecation" })
+    private void retrieveCaches() {
+        ConcurrentMap<?,?> map;
+
+        if (this.clusterContainerService == null){
+            log.error("Cluster service unavailable, can't retieve ARPHandler caches!");
+            return;
+        }
+
+        map = clusterContainerService.getCache(ARP_EVENT_CACHE_NAME);
+        if (map != null){
+            this.arpRequestReplyEvent = (ConcurrentMap<ARPEvent, Boolean>) map;
+        } else {
+            log.error("Cache allocation failed for {}", ARP_EVENT_CACHE_NAME);
+        }
     }
 
+    @SuppressWarnings("deprecation")
+    private void allocateCaches() {
+        if (clusterContainerService == null){
+            nonClusterObjectCreate();
+            log.error("Clustering service unavailable. Allocated non-cluster caches for ARPHandler.");
+            return;
+        }
+
+        try{
+            clusterContainerService.createCache(ARP_EVENT_CACHE_NAME,
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException e){
+            log.error("ARPHandler cache configuration invalid!");
+        } catch (CacheExistException e){
+            log.debug("ARPHandler cache exists, skipped allocation.");
+        }
+
+    }
+
+    private void nonClusterObjectCreate(){
+        arpRequestReplyEvent = new ConcurrentHashMap<ARPEvent, Boolean>();
+    }
     /**
      * Function called by the dependency manager when at least one
      * dependency become unsatisfied or when the component is shutting
@@ -512,18 +573,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
      * followed by a "destroy ()" calls
      *
      */
-    void stop() {
+    void stop(){
+    }
+
+    void stopping() {
         cancelPeriodicTimer();
     }
 
     void setSwitchManager(ISwitchManager s) {
-        logger.debug("SwitchManager set");
+        log.debug("SwitchManager service set.");
         this.switchManager = s;
     }
 
     void unsetSwitchManager(ISwitchManager s) {
         if (this.switchManager == s) {
-            logger.debug("SwitchManager removed!");
+            log.debug("SwitchManager service UNset.");
             this.switchManager = null;
         }
     }
@@ -533,21 +597,17 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         if (inPkt == null) {
             return PacketResult.IGNORED;
         }
-        logger
-                .trace("Received a frame of size: {}",
-                        inPkt.getPacketData().length);
+        log.trace("Received a frame of size: {}", inPkt.getPacketData().length);
         Packet formattedPak = this.dataPacketService.decodeDataPacket(inPkt);
         if (formattedPak instanceof Ethernet) {
             Object nextPak = formattedPak.getPayload();
             if (nextPak instanceof IPv4) {
-                handlePuntedIPPacket((IPv4) nextPak, inPkt
-                        .getIncomingNodeConnector());
-                logger.trace("Handled IP packet");
-            }
-            if (nextPak instanceof ARP) {
+                log.trace("Handle IP packet: {}", formattedPak);
+                handlePuntedIPPacket((IPv4) nextPak, inPkt.getIncomingNodeConnector());
+            } else if (nextPak instanceof ARP) {
+                log.trace("Handle ARP packet: {}", formattedPak);
                 handleARPPacket((Ethernet) formattedPak, (ARP) nextPak, inPkt
                         .getIncomingNodeConnector());
-                logger.trace("Handled ARP packet");
             }
         }
         return PacketResult.IGNORED;
@@ -556,6 +616,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
     private void startPeriodicTimer() {
         this.periodicTimer = new Timer("ArpHandler Periodic Timer");
         this.periodicTimer.scheduleAtFixedRate(new TimerTask() {
+            @SuppressWarnings("deprecation")
             @Override
             public void run() {
                 Set<InetAddress> targetIPs = countDownTimers.keySet();
@@ -569,12 +630,21 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
                         countDownTimers.replace(t, tick);
                     }
                 }
-                for (InetAddress t : expiredTargets) {
-                    countDownTimers.remove(t);
-                    // remove the requestor(s) who have been waited for the ARP
+                for (InetAddress tIP : expiredTargets) {
+                    countDownTimers.remove(tIP);
+                    // Remove the requestor(s) who have been waiting for the ARP
                     // reply from this target for more than 1sec
-                    arpRequestors.remove(t);
-                    logger.debug("{} didn't respond to ARP request", t);
+                    arpRequestors.remove(tIP);
+                    log.debug("ARP reply was not received from {}", tIP);
+                }
+
+                // Clean up ARP event cache
+                try {
+                    if (clusterContainerService.amICoordinator() && ! arpRequestReplyEvent.isEmpty()){
+                        arpRequestReplyEvent.clear();
+                    }
+                } catch (Exception e){
+                    log.warn("ARPHandler: A cluster member failed to clear event cache.");
                 }
             }
         }, 0, 1000);
@@ -593,13 +663,63 @@ public class ArpHandler implements IHostFinder, IListenDataPacket {
         }
         countDownTimers.remove(sourceIP);
         for (HostNodeConnector host : hosts) {
-            logger.debug(
-                    "Sending ARP Reply with src {}/{}, target {}/{}",
-                    new Object[] { sourceMAC, sourceIP,
-                            host.getDataLayerAddressBytes(),
-                            host.getNetworkAddress() });
-            sendARPReply(host.getnodeConnector(), sourceMAC, sourceIP,
-                    host.getDataLayerAddressBytes(), host.getNetworkAddress());
+            log.trace("Sending ARP Reply with src {}/{}, target {}/{}",
+                    new Object[] { sourceMAC, sourceIP, host.getDataLayerAddressBytes(), host.getNetworkAddress() });
+
+            if (connectionManager.isLocal(host.getnodeconnectorNode())){
+                sendARPReply(host.getnodeConnector(),
+                        sourceMAC,
+                        sourceIP,
+                        host.getDataLayerAddressBytes(),
+                        host.getNetworkAddress());
+            } else {
+                arpRequestReplyEvent.put(
+                        new ARPReply(
+                            host.getnodeConnector(),
+                            sourceIP,
+                            sourceMAC,
+                            host.getNetworkAddress(),
+                            host.getDataLayerAddressBytes()), false);
+            }
+        }
+    }
+
+
+    @Override
+    public void entryUpdated(ARPEvent key, Boolean new_value, String cacheName, boolean originLocal) {
+        if (key instanceof ARPRequest) {
+            ARPRequest req = (ARPRequest) key;
+            // If broadcast request
+            if (req.getHost() == null) {
+                sendBcastARPRequest(req.getTargetIP(), req.getSubnet());
+
+            //If unicast and local, send reply
+            } else if (connectionManager.isLocal(req.getHost().getnodeconnectorNode())) {
+                sendUcastARPRequest(req.getHost(), req.getSubnet());
+            }
+        } else if (key instanceof ARPReply) {
+            ARPReply rep = (ARPReply) key;
+            // New reply received by controller, notify all awaiting requestors across the cluster
+            if (new_value) {
+                generateAndSendReply(rep.getTargetIP(), rep.getTargetMac());
+
+            // Otherwise, a specific reply. If local, send out.
+            } else if (connectionManager.isLocal(rep.getPort().getNode())) {
+                sendARPReply(rep.getPort(),
+                        rep.getSourceMac(),
+                        rep.getSourceIP(),
+                        rep.getTargetMac(),
+                        rep.getTargetIP());
+            }
         }
     }
+
+    @Override
+    public void entryCreated(ARPEvent key, String cacheName, boolean originLocal) {
+        // nothing to do
+    }
+    @Override
+    public void entryDeleted(ARPEvent key, String cacheName, boolean originLocal) {
+        // nothing to do
+    }
 }
index 5507e46035d1ffa18ce3f98da0fd84dc349af274..b5383842f065f916b3eccc8be522b28637ae1bf9 100644 (file)
     </plugins>
   </build>
   <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>connectionmanager</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>connectionmanager.implementation</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal.connection</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal.connection.implementation</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+      </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>topologymanager</artifactId>
index aa1c8592d9225f997d7906e7dbb3e679b5f0f270..0f07ff60af44433fbd11ad784b57c75e691f4cdf 100644 (file)
@@ -147,7 +147,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
      *
      * We can't recover from condition 3 above
      */
-    private final ArrayList<ARPPending> failedARPReqList = new ArrayList<HostTracker.ARPPending>();
+    private final List<ARPPending> failedARPReqList = new ArrayList<HostTracker.ARPPending>();
 
     public HostTracker() {
     }
@@ -821,7 +821,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
         }
     }
 
-    private void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
+    private void debugEdgeUpdate(Edge e, UpdateType type, Set<Property> props) {
         Long srcNid = null;
         Short srcPort = null;
         Long dstNid = null;
@@ -843,7 +843,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
             }
 
             if (!srcType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
-                logger.error("For now we cannot handle updates for " + "non-openflow nodes");
+                logger.debug("For now we cannot handle updates for non-openflow nodes");
                 return;
             }
 
@@ -853,7 +853,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
             }
 
             if (!dstType.equals(NodeConnector.NodeConnectorIDType.OPENFLOW)) {
-                logger.error("For now we cannot handle updates for " + "non-openflow nodes");
+                logger.debug("For now we cannot handle updates for non-openflow nodes");
                 return;
             }
 
@@ -881,11 +881,14 @@ public class HostTracker implements IfIptoHost, IfHostListener, ISwitchManagerAw
 
     @Override
     public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
-        for (int i = 0; i < topoedgeupdateList.size(); i++) {
-            Edge e = topoedgeupdateList.get(i).getEdge();
-            Set<Property> p = topoedgeupdateList.get(i).getProperty();
-            UpdateType type = topoedgeupdateList.get(i).getUpdateType();
-            edgeUpdate(e, type, p);
+        if (logger.isDebugEnabled()) {
+            for (TopoEdgeUpdate topoEdgeUpdate : topoedgeupdateList) {
+                Edge e = topoEdgeUpdate.getEdge();
+                Set<Property> p = topoEdgeUpdate.getProperty();
+                UpdateType type = topoEdgeUpdate.getUpdateType();
+
+                debugEdgeUpdate(e, type, p);
+            }
         }
     }
 
index 04219502f6eff56cc6f80d545dc38d5dca1e4d25..b5e66296c13591e44ec2c7193411322f07cba15e 100644 (file)
-/*\r
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.controller.hosttracker.internal;\r
-\r
-import java.net.InetAddress;\r
-import java.net.UnknownHostException;\r
-import java.util.ArrayList;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.Map.Entry;\r
-\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-import org.osgi.framework.ServiceReference;\r
-import org.osgi.framework.Bundle;\r
-import javax.inject.Inject;\r
-\r
-import org.eclipse.osgi.framework.console.CommandProvider;\r
-import org.junit.Assert;\r
-import org.junit.Test;\r
-import org.junit.Before;\r
-import org.junit.After;\r
-import org.junit.runner.RunWith;\r
-import org.opendaylight.controller.sal.core.Node;\r
-import org.opendaylight.controller.sal.core.NodeConnector;\r
-import org.opendaylight.controller.sal.core.UpdateType;\r
-import org.opendaylight.controller.sal.utils.NodeConnectorCreator;\r
-import org.opendaylight.controller.sal.utils.NodeCreator;\r
-import org.opendaylight.controller.sal.utils.Status;\r
-//import org.opendaylight.controller.hosttracker.*;\r
-import org.opendaylight.controller.hosttracker.IfIptoHost;\r
-import org.opendaylight.controller.hosttracker.IfHostListener;\r
-import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;\r
-import org.opendaylight.controller.switchmanager.IInventoryListener;\r
-import org.opendaylight.controller.switchmanager.ISwitchManager;\r
-import org.opendaylight.controller.switchmanager.ISwitchManagerAware;\r
-import org.opendaylight.controller.topologymanager.ITopologyManagerAware;\r
-\r
-import org.ops4j.pax.exam.junit.PaxExam;\r
-import org.ops4j.pax.exam.util.Filter;\r
-import org.osgi.framework.BundleContext;\r
-import static org.junit.Assert.*;\r
-import org.ops4j.pax.exam.junit.Configuration;\r
-import static org.ops4j.pax.exam.CoreOptions.*;\r
-\r
-import org.ops4j.pax.exam.Option;\r
-import org.ops4j.pax.exam.util.PathUtils;\r
-import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;\r
-import org.ops4j.pax.exam.spi.reactors.PerClass;\r
-\r
-@RunWith(PaxExam.class)\r
-public class HostTrackerIT {\r
-    private Logger log = LoggerFactory.getLogger(HostTrackerIT.class);\r
-    // get the OSGI bundle context\r
-    @Inject\r
-    private BundleContext bc;\r
-\r
-    private IfIptoHost hosttracker = null;\r
-    private ISwitchManagerAware switchManagerAware = null;\r
-    private IInventoryListener invtoryListener = null;\r
-    private IfHostListener hostListener = null;\r
-    private ITopologyManagerAware topologyManagerAware = null;\r
-\r
-    // Configure the OSGi container\r
-    @Configuration\r
-    public Option[] config() {\r
-        return options(\r
-                //\r
-                systemProperty("logback.configurationFile").value(\r
-                        "file:" + PathUtils.getBaseDir()\r
-                                + "/src/test/resources/logback.xml"),\r
-                // To start OSGi console for inspection remotely\r
-                systemProperty("osgi.console").value("2401"),\r
-                // Set the systemPackages (used by clustering)\r
-                systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),\r
-                // List framework bundles\r
-                mavenBundle("equinoxSDK381", "org.eclipse.equinox.console",\r
-                        "1.0.0.v20120522-1841"),\r
-                mavenBundle("equinoxSDK381", "org.eclipse.equinox.util",\r
-                        "1.0.400.v20120522-2049"),\r
-                mavenBundle("equinoxSDK381", "org.eclipse.osgi.services",\r
-                        "3.3.100.v20120522-1822"),\r
-                mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds",\r
-                        "1.4.0.v20120522-1841"),\r
-                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command",\r
-                        "0.8.0.v201108120515"),\r
-                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime",\r
-                        "0.8.0.v201108120515"),\r
-                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell",\r
-                        "0.8.0.v201110170705"),\r
-                // List logger bundles\r
-                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),\r
-                mavenBundle("org.slf4j", "log4j-over-slf4j")\r
-                        .versionAsInProject(),\r
-                mavenBundle("ch.qos.logback", "logback-core")\r
-                        .versionAsInProject(),\r
-                mavenBundle("ch.qos.logback", "logback-classic")\r
-                        .versionAsInProject(),\r
-\r
-                // List all the bundles on which the test case depends\r
-                mavenBundle("org.opendaylight.controller", "sal")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller", "sal.implementation")\r
-                        .versionAsInProject(),\r
-\r
-                // needed by statisticsmanager\r
-                mavenBundle("org.opendaylight.controller", "containermanager")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller",\r
-                        "containermanager.implementation").versionAsInProject(),\r
-\r
-                mavenBundle("org.opendaylight.controller",\r
-                        "clustering.services").versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller", "clustering.stub")\r
-                        .versionAsInProject(),\r
-\r
-                // needed by forwardingrulesmanager\r
-                mavenBundle("org.opendaylight.controller", "switchmanager")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller",\r
-                        "switchmanager.implementation").versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller", "configuration")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller",\r
-                        "configuration.implementation").versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller", "hosttracker")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller",\r
-                        "hosttracker.implementation").versionAsInProject(),\r
-\r
-                // needed by hosttracker\r
-                mavenBundle("org.opendaylight.controller", "topologymanager")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.opendaylight.controller", "arphandler")\r
-                        .versionAsInProject(),\r
-\r
-                mavenBundle("org.jboss.spec.javax.transaction",\r
-                        "jboss-transaction-api_1.1_spec").versionAsInProject(),\r
-                mavenBundle("org.apache.commons", "commons-lang3")\r
-                        .versionAsInProject(),\r
-                mavenBundle("org.apache.felix",\r
-                        "org.apache.felix.dependencymanager")\r
-                        .versionAsInProject(), junitBundles());\r
-    }\r
-\r
-    private String stateToString(int state) {\r
-        switch (state) {\r
-        case Bundle.ACTIVE:\r
-            return "ACTIVE";\r
-        case Bundle.INSTALLED:\r
-            return "INSTALLED";\r
-        case Bundle.RESOLVED:\r
-            return "RESOLVED";\r
-        case Bundle.UNINSTALLED:\r
-            return "UNINSTALLED";\r
-        default:\r
-            return "Not CONVERTED";\r
-        }\r
-    }\r
-\r
-    @Before\r
-    public void areWeReady() {\r
-        assertNotNull(bc);\r
-        boolean debugit = false;\r
-        Bundle b[] = bc.getBundles();\r
-        for (int i = 0; i < b.length; i++) {\r
-            int state = b[i].getState();\r
-            if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {\r
-                log.debug("Bundle:" + b[i].getSymbolicName() + " state:"\r
-                        + stateToString(state));\r
-                debugit = true;\r
-            }\r
-        }\r
-        if (debugit) {\r
-            log.debug("Do some debugging because some bundle is "\r
-                    + "unresolved");\r
-        }\r
-\r
-        // Assert if true, if false we are good to go!\r
-        assertFalse(debugit);\r
-\r
-        // Now lets create a hosttracker for testing purpose\r
-        ServiceReference s = bc.getServiceReference(IfIptoHost.class.getName());\r
-        if (s != null) {\r
-            this.hosttracker = (IfIptoHost) bc.getService(s);\r
-            this.switchManagerAware = (ISwitchManagerAware) this.hosttracker;\r
-            this.invtoryListener = (IInventoryListener) this.hosttracker;\r
-            this.hostListener = (IfHostListener) this.hosttracker;\r
-            this.topologyManagerAware = (ITopologyManagerAware) this.hosttracker;\r
-        }\r
-\r
-        // If StatisticsManager is null, cannot run tests.\r
-        assertNotNull(this.hosttracker);\r
-    }\r
-\r
-    @Test\r
-    public void testStaticHost() throws UnknownHostException {\r
-        String ip;\r
-\r
-        assertNotNull(this.hosttracker);\r
-\r
-        // create one node and two node connectors\r
-        Node node1 = NodeCreator.createOFNode(1L);\r
-        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 1, node1);\r
-        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 2, node1);\r
-\r
-        // test addStaticHost(), store into inactive host DB\r
-        Status st = this.hosttracker.addStaticHost("192.168.0.8",\r
-                "11:22:33:44:55:66", nc1_1, "0");\r
-        Assert.assertTrue(st.isSuccess());\r
-        st = this.hosttracker.addStaticHost("192.168.0.13",\r
-                "11:22:33:44:55:77", nc1_2, "0");\r
-        Assert.assertTrue(st.isSuccess());\r
-\r
-        // check inactive DB\r
-        Iterator<HostNodeConnector> hnci = this.hosttracker\r
-                .getInactiveStaticHosts().iterator();\r
-        while (hnci.hasNext()) {\r
-            ip = hnci.next().getNetworkAddressAsString();\r
-            Assert.assertTrue(ip.equals("192.168.0.8")\r
-                    || ip.equals("192.168.0.13"));\r
-        }\r
-\r
-        // check active host DB\r
-        hnci = this.hosttracker.getActiveStaticHosts().iterator();\r
-        Assert.assertFalse(hnci.hasNext());\r
-\r
-        // test removeStaticHost()\r
-        st = this.hosttracker.removeStaticHost("192.168.0.8");\r
-        Assert.assertTrue(st.isSuccess());\r
-\r
-        hnci = this.hosttracker.getInactiveStaticHosts().iterator();\r
-        while (hnci.hasNext()) {\r
-            ip = hnci.next().getNetworkAddressAsString();\r
-            Assert.assertTrue(ip.equals("192.168.0.13"));\r
-        }\r
-    }\r
-\r
-    @Test\r
-    public void testNotifyNodeConnector() throws UnknownHostException {\r
-        String ip;\r
-\r
-        assertNotNull(this.invtoryListener);\r
-\r
-        // create one node and two node connectors\r
-        Node node1 = NodeCreator.createOFNode(1L);\r
-        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 1, node1);\r
-        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 2, node1);\r
-\r
-        // test addStaticHost(), put into inactive host DB if not verifiable\r
-        Status st = this.hosttracker.addStaticHost("192.168.0.8",\r
-                "11:22:33:44:55:66", nc1_1, "0");\r
-        st = this.hosttracker.addStaticHost("192.168.0.13",\r
-                "11:22:33:44:55:77", nc1_2, "0");\r
-\r
-        this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null);\r
-\r
-        // check all host list\r
-        Iterator<HostNodeConnector> hnci = this.hosttracker.getAllHosts()\r
-                .iterator();\r
-        while (hnci.hasNext()) {\r
-            ip = hnci.next().getNetworkAddressAsString();\r
-            Assert.assertTrue(ip.equals("192.168.0.8"));\r
-        }\r
-\r
-        // check active host DB\r
-        hnci = this.hosttracker.getActiveStaticHosts().iterator();\r
-        while (hnci.hasNext()) {\r
-            ip = hnci.next().getNetworkAddressAsString();\r
-            Assert.assertTrue(ip.equals("192.168.0.8"));\r
-        }\r
-\r
-        // check inactive host DB\r
-        hnci = this.hosttracker.getInactiveStaticHosts().iterator();\r
-        while (hnci.hasNext()) {\r
-            ip = hnci.next().getNetworkAddressAsString();\r
-            Assert.assertTrue(ip.equals("192.168.0.13"));\r
-        }\r
-    }\r
-\r
-    @Test\r
-    public void testHostFind() throws UnknownHostException {\r
-\r
-        assertNotNull(this.invtoryListener);\r
-\r
-        // create one node and two node connectors\r
-        Node node1 = NodeCreator.createOFNode(1L);\r
-        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 1, node1);\r
-        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector(\r
-                (short) 2, node1);\r
-\r
-        // test addStaticHost(), put into inactive host DB if not verifiable\r
-        Status st = this.hosttracker.addStaticHost("192.168.0.8",\r
-                "11:22:33:44:55:66", nc1_1, "0");\r
-        st = this.hosttracker.addStaticHost("192.168.0.13",\r
-                "11:22:33:44:55:77", nc1_2, "0");\r
-\r
-        HostNodeConnector hnc_1 = this.hosttracker.hostFind(InetAddress\r
-                .getByName("192.168.0.8"));\r
-        assertNull(hnc_1);\r
-\r
-        this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null);\r
-\r
-        hnc_1 = this.hosttracker.hostFind(InetAddress.getByName("192.168.0.8"));\r
-        assertNotNull(hnc_1);\r
-\r
-    }\r
-\r
-}\r
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.hosttracker.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemPackages;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+
+import javax.inject.Inject;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.switchmanager.IInventoryListener;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.util.PathUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+//import org.opendaylight.controller.hosttracker.*;
+
+@RunWith(PaxExam.class)
+public class HostTrackerIT {
+    private Logger log = LoggerFactory.getLogger(HostTrackerIT.class);
+    // get the OSGI bundle context
+    @Inject
+    private BundleContext bc;
+
+    private IfIptoHost hosttracker = null;
+    private IInventoryListener invtoryListener = null;
+    // Configure the OSGi container
+    @Configuration
+    public Option[] config() {
+        return options(
+
+                //
+                systemProperty("logback.configurationFile").value(
+                        "file:" + PathUtils.getBaseDir() + "/src/test/resources/logback.xml"),
+                // To start OSGi console for inspection remotely
+                systemProperty("osgi.console").value("2401"),
+                // Set the systemPackages (used by clustering)
+                systemPackages("sun.reflect", "sun.reflect.misc", "sun.misc"),
+                // List framework bundles
+                mavenBundle("equinoxSDK381", "org.eclipse.equinox.console", "1.0.0.v20120522-1841"),
+                mavenBundle("equinoxSDK381", "org.eclipse.equinox.util", "1.0.400.v20120522-2049"),
+                mavenBundle("equinoxSDK381", "org.eclipse.osgi.services","3.3.100.v20120522-1822"),
+                mavenBundle("equinoxSDK381", "org.eclipse.equinox.ds", "1.4.0.v20120522-1841"),
+                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.command", "0.8.0.v201108120515"),
+                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.runtime", "0.8.0.v201108120515"),
+                mavenBundle("equinoxSDK381", "org.apache.felix.gogo.shell", "0.8.0.v201110170705"),
+                // List logger bundles
+                mavenBundle("org.slf4j", "slf4j-api").versionAsInProject(),
+                mavenBundle("org.slf4j", "log4j-over-slf4j").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-core").versionAsInProject(),
+                mavenBundle("ch.qos.logback", "logback-classic").versionAsInProject(),
+
+                // List all the bundles on which the test case depends
+                mavenBundle("org.opendaylight.controller", "sal").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "sal.implementation").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "sal.connection").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "sal.connection.implementation").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "connectionmanager").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "connectionmanager.implementation").versionAsInProject(),
+
+                // needed by statisticsmanager
+                mavenBundle("org.opendaylight.controller", "containermanager").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "containermanager.implementation").versionAsInProject(),
+
+                mavenBundle("org.opendaylight.controller", "clustering.services").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "clustering.stub").versionAsInProject(),
+
+                // needed by forwardingrulesmanager
+                mavenBundle("org.opendaylight.controller", "switchmanager").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "switchmanager.implementation").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "configuration").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "configuration.implementation").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "hosttracker").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "hosttracker.implementation").versionAsInProject(),
+
+                // needed by hosttracker
+                mavenBundle("org.opendaylight.controller", "topologymanager").versionAsInProject(),
+                mavenBundle("org.opendaylight.controller", "arphandler").versionAsInProject(),
+
+                mavenBundle("org.jboss.spec.javax.transaction", "jboss-transaction-api_1.1_spec").versionAsInProject(),
+                mavenBundle("org.apache.commons", "commons-lang3").versionAsInProject(),
+                mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(),
+                junitBundles());
+    }
+
+    private String stateToString(int state) {
+        switch (state) {
+        case Bundle.ACTIVE:
+            return "ACTIVE";
+        case Bundle.INSTALLED:
+            return "INSTALLED";
+        case Bundle.RESOLVED:
+            return "RESOLVED";
+        case Bundle.UNINSTALLED:
+            return "UNINSTALLED";
+        default:
+            return "Not CONVERTED";
+        }
+    }
+
+    @Before
+    public void areWeReady() {
+        assertNotNull(bc);
+        boolean debugit = false;
+        Bundle b[] = bc.getBundles();
+        for (int i = 0; i < b.length; i++) {
+            int state = b[i].getState();
+            if (state != Bundle.ACTIVE && state != Bundle.RESOLVED) {
+                log.debug("Bundle:" + b[i].getSymbolicName() + " state:" + stateToString(state));
+                debugit = true;
+            }
+        }
+        if (debugit) {
+            log.debug("Do some debugging because some bundle is " + "unresolved");
+        }
+
+        // Assert if true, if false we are good to go!
+        assertFalse(debugit);
+
+        // Now lets create a hosttracker for testing purpose
+        ServiceReference s = bc.getServiceReference(IfIptoHost.class.getName());
+        if (s != null) {
+            this.hosttracker = (IfIptoHost) bc.getService(s);
+            this.invtoryListener = (IInventoryListener) this.hosttracker;
+        }
+
+        // If StatisticsManager is null, cannot run tests.
+        assertNotNull(this.hosttracker);
+    }
+
+    @Test
+    public void testStaticHost() throws UnknownHostException {
+        String ip;
+
+        assertNotNull(this.hosttracker);
+
+        // create one node and two node connectors
+        Node node1 = NodeCreator.createOFNode(1L);
+        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector((short) 1, node1);
+        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector((short) 2, node1);
+
+        // test addStaticHost(), store into inactive host DB
+        Status st = this.hosttracker.addStaticHost("192.168.0.8", "11:22:33:44:55:66", nc1_1, "0");
+        Assert.assertTrue(st.isSuccess());
+        st = this.hosttracker.addStaticHost("192.168.0.13", "11:22:33:44:55:77", nc1_2, "0");
+        Assert.assertTrue(st.isSuccess());
+
+        // check inactive DB
+        Iterator<HostNodeConnector> hnci = this.hosttracker.getInactiveStaticHosts().iterator();
+        while (hnci.hasNext()) {
+            ip = hnci.next().getNetworkAddressAsString();
+            Assert.assertTrue(ip.equals("192.168.0.8") || ip.equals("192.168.0.13"));
+        }
+
+        // check active host DB
+        hnci = this.hosttracker.getActiveStaticHosts().iterator();
+        Assert.assertFalse(hnci.hasNext());
+
+        // test removeStaticHost()
+        st = this.hosttracker.removeStaticHost("192.168.0.8");
+        Assert.assertTrue(st.isSuccess());
+
+        hnci = this.hosttracker.getInactiveStaticHosts().iterator();
+        while (hnci.hasNext()) {
+            ip = hnci.next().getNetworkAddressAsString();
+            Assert.assertTrue(ip.equals("192.168.0.13"));
+        }
+    }
+
+    @Test
+    public void testNotifyNodeConnector() throws UnknownHostException {
+        String ip;
+
+        assertNotNull(this.invtoryListener);
+
+        // create one node and two node connectors
+        Node node1 = NodeCreator.createOFNode(1L);
+        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector((short) 1, node1);
+        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector((short) 2, node1);
+
+        // test addStaticHost(), put into inactive host DB if not verifiable
+        Status st = this.hosttracker.addStaticHost("192.168.0.8", "11:22:33:44:55:66", nc1_1, "0");
+        st = this.hosttracker.addStaticHost("192.168.0.13", "11:22:33:44:55:77", nc1_2, "0");
+
+        this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null);
+
+        // check all host list
+        Iterator<HostNodeConnector> hnci = this.hosttracker.getAllHosts().iterator();
+        while (hnci.hasNext()) {
+            ip = hnci.next().getNetworkAddressAsString();
+            Assert.assertTrue(ip.equals("192.168.0.8"));
+        }
+
+        // check active host DB
+        hnci = this.hosttracker.getActiveStaticHosts().iterator();
+        while (hnci.hasNext()) {
+            ip = hnci.next().getNetworkAddressAsString();
+            Assert.assertTrue(ip.equals("192.168.0.8"));
+        }
+
+        // check inactive host DB
+        hnci = this.hosttracker.getInactiveStaticHosts().iterator();
+        while (hnci.hasNext()) {
+            ip = hnci.next().getNetworkAddressAsString();
+            Assert.assertTrue(ip.equals("192.168.0.13"));
+        }
+    }
+
+    @Test
+    public void testHostFind() throws UnknownHostException {
+
+        assertNotNull(this.invtoryListener);
+
+        // create one node and two node connectors
+        Node node1 = NodeCreator.createOFNode(1L);
+        NodeConnector nc1_1 = NodeConnectorCreator.createOFNodeConnector((short) 1, node1);
+        NodeConnector nc1_2 = NodeConnectorCreator.createOFNodeConnector((short) 2, node1);
+
+        // test addStaticHost(), put into inactive host DB if not verifiable
+        Status st = this.hosttracker.addStaticHost("192.168.0.8", "11:22:33:44:55:66", nc1_1, "0");
+        st = this.hosttracker.addStaticHost("192.168.0.13", "11:22:33:44:55:77", nc1_2, "0");
+
+        HostNodeConnector hnc_1 = this.hosttracker.hostFind(InetAddress.getByName("192.168.0.8"));
+        assertNull(hnc_1);
+
+        this.invtoryListener.notifyNodeConnector(nc1_1, UpdateType.ADDED, null);
+
+        hnc_1 = this.hosttracker.hostFind(InetAddress.getByName("192.168.0.8"));
+        assertNotNull(hnc_1);
+
+    }
+
+}
index 5312f8b91f8f0ee2468ed6e3c5f8e3569a3ffba1..210001583ba296fd91242f138cbeebb1662a770b 100644 (file)
     </pluginRepository>
   </pluginRepositories>
   <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>connectionmanager</artifactId>
+      <version>0.1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>connectionmanager.implementation</artifactId>
+      <version>0.1.0-SNAPSHOT</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal</artifactId>
       <artifactId>sal.implementation</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal.connection</artifactId>
+      <version>0.1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal.connection.implementation</artifactId>
+      <version>0.1.0-SNAPSHOT</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>forwarding.staticrouting</artifactId>
index 4c3fa97864ff88744944fc669d9eeebc3be47ffd..dff17ff086f07d67282486a28e526f93725281d2 100644 (file)
@@ -1271,7 +1271,11 @@ public class NorthboundIT {
                 mavenBundle("org.opendaylight.controller", "security", "0.4.0-SNAPSHOT").noStart(),
                 mavenBundle("org.opendaylight.controller", "sal", "0.5.0-SNAPSHOT"),
                 mavenBundle("org.opendaylight.controller", "sal.implementation", "0.4.0-SNAPSHOT"),
+                mavenBundle("org.opendaylight.controller", "sal.connection", "0.1.0-SNAPSHOT"),
+                mavenBundle("org.opendaylight.controller", "sal.connection.implementation", "0.1.0-SNAPSHOT"),
                 mavenBundle("org.opendaylight.controller", "switchmanager", "0.5.0-SNAPSHOT"),
+                mavenBundle("org.opendaylight.controller", "connectionmanager", "0.1.0-SNAPSHOT"),
+                mavenBundle("org.opendaylight.controller", "connectionmanager.implementation", "0.1.0-SNAPSHOT"),
                 mavenBundle("org.opendaylight.controller", "switchmanager.implementation", "0.4.0-SNAPSHOT"),
                 mavenBundle("org.opendaylight.controller", "forwardingrulesmanager", "0.4.0-SNAPSHOT"),
                 mavenBundle("org.opendaylight.controller", "forwardingrulesmanager.implementation", "0.4.0-SNAPSHOT"),
index a3f21cff3eb50ad3d062b1c381a79abf35b81f2e..f81e7e3d03b0c4af14f5e539b45567725d80c43b 100644 (file)
@@ -322,6 +322,19 @@ public abstract class NetUtils {
 
         return false;
     }
+    /**
+     * Returns true if the MAC address is a unicast MAC address and false
+     * otherwise.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isUnicastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes) {
+            return (MACAddress[0] & 1) == 0;
+        }
+        return false;
+    }
 
     /**
      * Returns true if the MAC address is a multicast MAC address and false