added HostProvider to SimpleHostManager

Change-Id: I13ff57fcd24ea7bd2c3f2544a3aad7d18ceda107
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/DefaultHostDescription.java b/core/api/src/main/java/org/onlab/onos/net/host/DefaultHostDescription.java
index ea68b53..a06a92e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/host/DefaultHostDescription.java
+++ b/core/api/src/main/java/org/onlab/onos/net/host/DefaultHostDescription.java
@@ -20,6 +20,14 @@
     private final Set<IPAddress> ips;
 
     public DefaultHostDescription(MACAddress mac, VLANID vlan,
+            HostLocation loc) {
+        this.mac = mac;
+        this.vlan = vlan;
+        this.location = loc;
+        this.ips = new HashSet<IPAddress>();
+    }
+
+    public DefaultHostDescription(MACAddress mac, VLANID vlan,
             HostLocation loc, Set<IPAddress> ips) {
         this.mac = mac;
         this.vlan = vlan;
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/host/impl/SimpleHostStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/host/impl/SimpleHostStore.java
index 2f9eb29..b7fc5ae 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/host/impl/SimpleHostStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/host/impl/SimpleHostStore.java
@@ -76,20 +76,23 @@
             HostDescription descr) {
         DefaultHost updated;
         HostEvent event;
-        if (host.location().equals(descr.location())) {
-            updated = new DefaultHost(providerId, host.id(),
-                    host.mac(),
-                    host.vlan(),
-                    host.location(),
-                    descr.ipAddresses());
-            event = new HostEvent(HOST_UPDATED, updated);
-        } else {
+        // Consider only actual location (not timestamp) change?
+        if (!(host.location().port().equals(descr.location().port()))) {
             updated = new DefaultHost(providerId, host.id(),
                     host.mac(),
                     host.vlan(),
                     descr.location(),
                     host.ipAddresses());
             event = new HostEvent(HOST_MOVED, updated);
+        } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
+            updated = new DefaultHost(providerId, host.id(),
+                    host.mac(),
+                    host.vlan(),
+                    descr.location(),
+                    descr.ipAddresses());
+            event = new HostEvent(HOST_UPDATED, updated);
+        } else {
+            return null;
         }
         synchronized (this) {
             hosts.put(host.id(), updated);
diff --git a/providers/of/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java b/providers/of/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
index e05bed9..6e5d600 100644
--- a/providers/of/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
+++ b/providers/of/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
@@ -1,19 +1,35 @@
 package org.onlab.onos.provider.of.host.impl;
 
+import java.util.Set;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Host;
+import org.onlab.onos.net.HostId;
+import org.onlab.onos.net.HostLocation;
+import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.host.DefaultHostDescription;
+import org.onlab.onos.net.host.HostDescription;
 import org.onlab.onos.net.host.HostProvider;
 import org.onlab.onos.net.host.HostProviderRegistry;
 import org.onlab.onos.net.host.HostProviderService;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.of.controller.OpenFlowController;
+import org.onlab.onos.of.controller.OpenFlowPacketContext;
+import org.onlab.onos.of.controller.PacketListener;
+import org.onlab.packet.ARP;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPAddress;
+import org.onlab.packet.VLANID;
 import org.slf4j.Logger;
 
+import com.google.common.collect.Sets;
+
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -33,6 +49,8 @@
 
     private HostProviderService providerService;
 
+    private final InternalHostProvider listener = new InternalHostProvider();
+
     /**
      * Creates an OpenFlow host provider.
      */
@@ -43,13 +61,17 @@
     @Activate
     public void activate() {
         providerService = providerRegistry.register(this);
+        controller.addPacketListener(0, listener);
+
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
         providerRegistry.unregister(this);
+        controller.removePacketListener(listener);
         providerService = null;
+
         log.info("Stopped");
     }
 
@@ -58,4 +80,32 @@
         log.info("Triggering probe on device {}", host);
     }
 
+    private class InternalHostProvider implements PacketListener {
+
+        @Override
+        public void handlePacket(OpenFlowPacketContext pktCtx) {
+            Ethernet eth = pktCtx.parsed();
+
+            // potentially a new or moved host
+            if (eth.getEtherType() == Ethernet.TYPE_ARP) {
+                VLANID vlan = VLANID.vlanId(eth.getVlanID());
+                HostId hid = HostId.hostId(
+                        eth.getSourceMAC(), vlan);
+                HostLocation hloc = new HostLocation(
+                        DeviceId.deviceId("of:" + Long.toHexString(pktCtx.dpid().value())),
+                        PortNumber.portNumber(pktCtx.inPort()),
+                        System.currentTimeMillis());
+                ARP arp = (ARP) eth.getPayload();
+                Set<IPAddress> ips = Sets.newHashSet(IPAddress.valueOf(arp.getSenderProtocolAddress()));
+                HostDescription hdescr = new DefaultHostDescription(
+                        eth.getSourceMAC(),
+                        vlan,
+                        hloc,
+                        ips);
+                providerService.hostDetected(hid, hdescr);
+
+            }
+        }
+
+    }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPAddress.java b/utils/misc/src/main/java/org/onlab/packet/IPAddress.java
index 4e898f4..5f4e174 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPAddress.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPAddress.java
@@ -103,32 +103,27 @@
             if (builder.length() > 0) {
                 builder.append(".");
             }
-            builder.append(String.format("%02d", b));
+            builder.append(String.format("%d", b));
         }
         return builder.toString();
     }
 
     @Override
     public int hashCode() {
-        return octets.hashCode();
+        return Arrays.hashCode(octets);
     }
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof IPAddress) {
 
+        if (obj instanceof IPAddress) {
             IPAddress other = (IPAddress) obj;
 
-            if (!(this.version.equals(other.version))) {
-                return false;
-            }
-            if (!(Arrays.equals(this.octets, other.octets))) {
-                return false;
+            if (this.version.equals(other.version)
+                    && (Arrays.equals(this.octets, other.octets))) {
+                return true;
             }
         }
-        return true;
+        return false;
     }
 }
diff --git a/utils/misc/src/main/java/org/onlab/packet/VLANID.java b/utils/misc/src/main/java/org/onlab/packet/VLANID.java
index 5b26d04..c978e52 100644
--- a/utils/misc/src/main/java/org/onlab/packet/VLANID.java
+++ b/utils/misc/src/main/java/org/onlab/packet/VLANID.java
@@ -6,20 +6,29 @@
 public class VLANID {
 
     private final short value;
-    private static final short NONE = 0;
+    // Based on convention used elsewhere? Check and change if needed
+    private static final short UNTAGGED = (short) 0xffff;
     // A VLAN ID is actually 12 bits of a VLAN tag.
     private static final short MAX_VLAN = 4095;
 
+    protected VLANID() {
+        this.value = UNTAGGED;
+    }
+
     protected VLANID(short value) {
         this.value = value;
     }
 
     public static VLANID vlanId() {
-        return new VLANID(NONE);
+        return new VLANID(UNTAGGED);
     }
 
     public static VLANID vlanId(short value) {
-        if (value >= MAX_VLAN) {
+        if (value == UNTAGGED) {
+            return new VLANID();
+        }
+
+        if (value > MAX_VLAN) {
             throw new IllegalArgumentException(
                     "value exceeds allowed maximum VLAN ID value (4095)");
         }