Fix for ONOS-5032 and ONOS-5034

Change-Id: Ib964252dd05754ce7069a7a82ccb1d1c29bfa978
diff --git a/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
index d337452..21e3a51 100644
--- a/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
@@ -24,6 +24,7 @@
 import org.onosproject.net.Host;
 import org.onosproject.net.host.HostService;
 import org.onosproject.utils.Comparators;
+import org.onlab.util.Tools;
 
 import java.util.Collections;
 import java.util.List;
@@ -38,7 +39,7 @@
 public class HostsListCommand extends AbstractShellCommand {
 
     private static final String FMT =
-            "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s";
+            "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s, last seen time=%s";
 
     private static final String FMT_SHORT =
             "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s";
@@ -93,7 +94,9 @@
         } else {
             print(FMT, host.id(), host.mac(),
                   host.location().deviceId(), host.location().port(),
-                  host.vlan(), host.ipAddresses(), annotations(host.annotations()));
+                  host.vlan(), host.ipAddresses(), annotations(host.annotations()),
+                  Tools.timeAgo(host.timestamp().unixTimestamp()));
         }
     }
 }
+
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultHost.java b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
index 38a8e0d..587fc7f 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultHost.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
@@ -16,6 +16,7 @@
 package org.onosproject.net;
 
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -36,6 +37,7 @@
     private final VlanId vlan;
     private final HostLocation location;
     private final Set<IpAddress> ips;
+    private final WallClockTimestamp timestamp;
 
     /**
      * Creates an end-station host using the supplied information.
@@ -51,10 +53,29 @@
     public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
                        VlanId vlan, HostLocation location, Set<IpAddress> ips,
                        Annotations... annotations) {
+        this(providerId, id, mac, vlan, location, ips, new WallClockTimestamp(), annotations);
+    }
+
+    /**
+     * Creates an end-station host using the supplied information.
+     *
+     * @param providerId provider identity
+     * @param id         host identifier
+     * @param mac        host MAC address
+     * @param vlan       host VLAN identifier
+     * @param location   host location
+     * @param ips        host IP addresses
+     * @param timestamp  last host updated time
+     * @param annotations optional key/value annotations
+     */
+    public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
+                       VlanId vlan, HostLocation location, Set<IpAddress> ips,
+                       WallClockTimestamp timestamp, Annotations... annotations) {
         super(providerId, id, annotations);
         this.mac = mac;
         this.vlan = vlan;
         this.location = location;
+        this.timestamp = timestamp;
         this.ips = new HashSet<>(ips);
     }
 
@@ -84,6 +105,11 @@
     }
 
     @Override
+    public WallClockTimestamp timestamp() {
+        return timestamp;
+    }
+
+    @Override
     public int hashCode() {
         return Objects.hash(id, mac, vlan, location);
     }
@@ -114,6 +140,7 @@
                 .add("location", location())
                 .add("ipAddresses", ipAddresses())
                 .add("annotations", annotations())
+                .add("timestamp", timestamp())
                 .toString();
     }
 
diff --git a/core/api/src/main/java/org/onosproject/net/Host.java b/core/api/src/main/java/org/onosproject/net/Host.java
index b9621b7..485b76f 100644
--- a/core/api/src/main/java/org/onosproject/net/Host.java
+++ b/core/api/src/main/java/org/onosproject/net/Host.java
@@ -18,6 +18,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.store.service.WallClockTimestamp;
 
 import java.util.Set;
 
@@ -63,6 +64,14 @@
      */
     HostLocation location();
 
+    /**
+     * Returns the host recent time.
+     * @return host last updated time
+     */
+    default WallClockTimestamp timestamp() {
+        return null;
+    }
     // TODO: explore capturing list of recent locations to aid in mobility
 
 }
+
diff --git a/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java b/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
index 3503eca..74fbbe9 100644
--- a/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
@@ -21,6 +21,7 @@
 import org.onosproject.net.AbstractDescription;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.SparseAnnotations;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
@@ -40,6 +41,7 @@
     private final VlanId vlan;
     private final HostLocation location;
     private final Set<IpAddress> ip;
+    private final WallClockTimestamp timestamp;
 
     /**
      * Creates a host description using the supplied information.
@@ -83,11 +85,28 @@
     public DefaultHostDescription(MacAddress mac, VlanId vlan,
                                   HostLocation location, Set<IpAddress> ip,
                                   SparseAnnotations... annotations) {
+        this(mac, vlan, location, ip, new WallClockTimestamp(), annotations);
+    }
+
+    /**
+     * Creates a host description using the supplied information.
+     *
+     * @param mac         host MAC address
+     * @param vlan        host VLAN identifier
+     * @param location    host location
+     * @param ip          host IP addresses
+     * @param timestamp     host recent updated time
+     * @param annotations optional key/value annotations map
+     */
+    public DefaultHostDescription(MacAddress mac, VlanId vlan,
+                                  HostLocation location, Set<IpAddress> ip,
+                                  WallClockTimestamp timestamp, SparseAnnotations... annotations) {
         super(annotations);
         this.mac = mac;
         this.vlan = vlan;
         this.location = location;
         this.ip = ImmutableSet.copyOf(ip);
+        this.timestamp = timestamp;
     }
 
     @Override
@@ -111,12 +130,18 @@
     }
 
     @Override
+    public WallClockTimestamp timestamp() {
+        return timestamp;
+    }
+
+    @Override
     public String toString() {
         return toStringHelper(this)
                 .add("mac", mac)
                 .add("vlan", vlan)
                 .add("location", location)
                 .add("ipAddress", ip)
+                .add("timestamp", timestamp)
                 .toString();
     }
 
@@ -139,5 +164,4 @@
         }
         return false;
     }
-
 }
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostDescription.java b/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
index ad423a3..dd25339 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
@@ -22,6 +22,7 @@
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.store.service.WallClockTimestamp;
 
 /**
  * Information describing host and its location.
@@ -55,4 +56,12 @@
      * @return host IP address
      */
     Set<IpAddress> ipAddress();
+
+    /**
+     * Returns the host recent updated Time.
+     * @return host last updated time.
+     */
+    default WallClockTimestamp timestamp() {
+        return null;
+    }
 }
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
index 8bd27c7..ec1b39a 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
@@ -39,7 +39,8 @@
         final ObjectNode result = context.mapper().createObjectNode()
                 .put("id", host.id().toString())
                 .put("mac", host.mac().toString())
-                .put("vlan", host.vlan().toString());
+                .put("vlan", host.vlan().toString())
+                .put("timestamp", host.timestamp().unixTimestamp());
 
         final ArrayNode jsonIpAddresses = result.putArray("ipAddresses");
         for (final IpAddress ipAddress : host.ipAddresses()) {
diff --git a/core/net/BUCK b/core/net/BUCK
index 73bbe7d..773b20a 100644
--- a/core/net/BUCK
+++ b/core/net/BUCK
@@ -12,6 +12,7 @@
     '//core/common:onos-core-common',
     '//core/store/dist:onos-core-dist',
     '//core/store/dist:onos-core-dist-tests',
+    '//utils/osgi:onlab-osgi-tests',
 ]
 
 osgi_jar_with_tests (
diff --git a/core/net/pom.xml b/core/net/pom.xml
index d30f7a6..57a39e8 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -125,6 +125,13 @@
             <groupId>org.onosproject</groupId>
             <artifactId>onos-incubator-net</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index bdb5e43..27b9b7a 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -106,6 +106,15 @@
             label = "Enable removal of duplicate ip address")
 
     private boolean allowDuplicateIps = true;
+
+    @Property(name = "monitorHosts", boolValue = false,
+            label = "Enable/Disable monitoring of hosts")
+    private boolean monitorHosts = false;
+
+    @Property(name = "probeRate", longValue = 30000,
+            label = "Set the probe Rate in milli seconds")
+    private long probeRate = 30000;
+
     private HostMonitor monitor;
 
 
@@ -114,17 +123,71 @@
         store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
         cfgService.registerProperties(getClass());
-        modified(context);
         networkConfigService.addListener(networkConfigListener);
         monitor = new HostMonitor(packetService, this, interfaceService, edgePortService);
+        monitor.setProbeRate(probeRate);
         monitor.start();
+        modified(context);
+        cfgService.registerProperties(getClass());
         log.info("Started");
     }
 
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(delegate);
+        eventDispatcher.removeSink(HostEvent.class);
+        networkConfigService.removeListener(networkConfigListener);
+        cfgService.unregisterProperties(getClass(), false);
+        monitor.shutdown();
+        log.info("Stopped");
+    }
+
     @Modified
     public void modified(ComponentContext context) {
+        boolean oldValue = monitorHosts;
+        readComponentConfiguration(context);
+        if (probeRate > 0) {
+            monitor.setProbeRate(probeRate);
+        } else {
+            log.warn("probeRate cannot be lessthan 0");
+        }
+
+        if (oldValue != monitorHosts) {
+            if (monitorHosts) {
+                startMonitoring();
+            } else {
+                stopMonitoring();
+            }
+        }
+    }
+
+    /**
+     * Extracts properties from the component configuration context.
+     *
+     * @param context the component context
+     */
+    private void readComponentConfiguration(ComponentContext context) {
         Dictionary<?, ?> properties = context.getProperties();
         Boolean flag;
+
+        flag = Tools.isPropertyEnabled(properties, "monitorHosts");
+        if (flag == null) {
+            log.info("monitorHosts is not enabled " +
+                             "using current value of {}", monitorHosts);
+        } else {
+            monitorHosts = flag;
+            log.info("Configured. monitorHosts {}",
+            monitorHosts ? "enabled" : "disabled");
+        }
+
+        Long longValue = Tools.getLongProperty(properties, "probeRate");
+        if (longValue == null || longValue == 0) {
+            log.info("probeRate is not set sing default value of {}", probeRate);
+        } else {
+            probeRate = longValue;
+            log.info("Configured. probeRate {}", probeRate);
+        }
+
         flag = Tools.isPropertyEnabled(properties, "allowDuplicateIps");
         if (flag == null) {
             log.info("Removal of duplicate ip address is not configured");
@@ -133,14 +196,32 @@
             log.info("Removal of duplicate ip address is {}",
                      allowDuplicateIps ? "disabled" : "enabled");
         }
+
+
     }
 
-    @Deactivate
-    public void deactivate() {
-        store.unsetDelegate(delegate);
-        eventDispatcher.removeSink(HostEvent.class);
-        networkConfigService.removeListener(networkConfigListener);
-        log.info("Stopped");
+    /**
+     * Starts monitoring the hosts by IP Address.
+     *
+     */
+    private void startMonitoring() {
+        store.getHosts().forEach(host -> {
+                    host.ipAddresses().forEach(ip -> {
+                           monitor.addMonitoringFor(ip);
+            });
+        });
+    }
+
+    /**
+     * Stops monitoring the hosts by IP Address.
+     *
+     */
+    private void stopMonitoring() {
+        store.getHosts().forEach(host -> {
+                    host.ipAddresses().forEach(ip -> {
+                           monitor.stopMonitoring(ip);
+            });
+        });
     }
 
     @Override
@@ -244,8 +325,15 @@
             }
             store.createOrUpdateHost(provider().id(), hostId,
                                      hostDescription, replaceIps);
+
+            if (monitorHosts) {
+                hostDescription.ipAddress().forEach(ip -> {
+                    monitor.addMonitoringFor(ip);
+                });
+            }
         }
 
+
         // When a new IP is detected, remove that IP on other hosts if it exists
         public void removeDuplicates(HostId hostId, HostDescription desc) {
             desc.ipAddress().forEach(ip -> {
@@ -258,9 +346,7 @@
                     }
                 });
             });
-        }
-
-
+         }
 
 
         // returns a HostDescription made from the union of the BasicHostConfig
@@ -276,6 +362,12 @@
         public void hostVanished(HostId hostId) {
             checkNotNull(hostId, HOST_ID_NULL);
             checkValidity();
+            Host host = store.getHost(hostId);
+            if (monitorHosts) {
+                host.ipAddresses().forEach(ip -> {
+                    monitor.stopMonitoring(ip);
+                });
+            }
             store.removeHost(hostId);
         }
 
@@ -323,3 +415,4 @@
         }
     }
 }
+
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index c2bac09..747c8eb 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -150,6 +150,13 @@
         hostProviders.put(provider.id(), provider);
     }
 
+    /*
+     * Sets the probe rate.
+     */
+    void setProbeRate(long probeRate) {
+        this.probeRate = probeRate;
+    }
+
     @Override
     public void run(Timeout timeout) throws Exception {
         monitoredAddresses.forEach(this::probe);
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
index 1eb014f..dd97d21 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -98,12 +98,14 @@
     protected TestHostProvider provider;
     protected HostProviderService providerService;
 
-    private static final ComponentContextAdapter REMOVE_DUPS =
+    private static final ComponentContextAdapter REMOVE_DUPS_MONITOR =
             new ComponentContextAdapter() {
                 @Override
                 public Dictionary getProperties() {
                     Hashtable<String, String> props = new Hashtable<>();
                     props.put("allowDuplicateIps", "true");
+                    props.put("monitorHosts", "true");
+                    props.put("probeRate", "40000");
                     return props;
                 }
             };
@@ -116,28 +118,27 @@
         registry = mgr;
         mgr.networkConfigService = new TestNetworkConfigService();
         mgr.cfgService = new ComponentConfigAdapter();
-        mgr.activate(REMOVE_DUPS);
+
+        mgr.activate(REMOVE_DUPS_MONITOR);
+
         mgr.addListener(listener);
 
         provider = new TestHostProvider();
         providerService = registry.register(provider);
-        assertTrue("provider should be registered",
-                   registry.getProviders().contains(provider.id()));
+        assertTrue("provider should be registered", registry.getProviders().contains(provider.id()));
     }
 
     @After
     public void tearDown() {
         registry.unregister(provider);
-        assertFalse("provider should not be registered",
-                    registry.getProviders().contains(provider.id()));
+        assertFalse("provider should not be registered", registry.getProviders().contains(provider.id()));
 
         mgr.removeListener(listener);
         mgr.deactivate();
         injectEventDispatcher(mgr, null);
     }
 
-    private void detect(HostId hid, MacAddress mac, VlanId vlan,
-                        HostLocation loc, IpAddress ip) {
+    private void detect(HostId hid, MacAddress mac, VlanId vlan, HostLocation loc, IpAddress ip) {
         HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
         providerService.hostDetected(hid, descr, false);
         assertNotNull("host should be found", mgr.getHost(hid));
@@ -217,8 +218,7 @@
         assertNull("host should have been removed", mgr.getHost(HID3));
     }
 
-    private void validateHosts(
-            String msg, Iterable<Host> hosts, HostId... ids) {
+    private void validateHosts(String msg, Iterable<Host> hosts, HostId... ids) {
         Set<HostId> hids = Sets.newHashSet(ids);
         for (Host h : hosts) {
             assertTrue(msg, hids.remove(h.id()));
@@ -252,8 +252,7 @@
         assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
     }
 
-    private static class TestHostProvider extends AbstractProvider
-            implements HostProvider {
+    private static class TestHostProvider extends AbstractProvider implements HostProvider {
 
         protected TestHostProvider() {
             super(PID);
@@ -284,3 +283,4 @@
     private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
     }
 }
+
diff --git a/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java b/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
index b4449ae..a359862 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
@@ -48,6 +48,7 @@
 import org.onosproject.store.service.MapEventListener;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
 import org.slf4j.Logger;
 
 import java.util.Collection;
@@ -87,7 +88,8 @@
     @Activate
     public void activate() {
         KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
-                .register(KryoNamespaces.API);
+                .register(KryoNamespaces.API)
+                .register(WallClockTimestamp.class);
 
         hostsConsistentMap = storageService.<HostId, DefaultHost>consistentMapBuilder()
                 .withName("onos-hosts")
@@ -122,7 +124,9 @@
         if (!Objects.equals(existingHost.providerId(), providerId) ||
                 !Objects.equals(existingHost.mac(), hostDescription.hwAddress()) ||
                 !Objects.equals(existingHost.vlan(), hostDescription.vlan()) ||
-                !Objects.equals(existingHost.location(), hostDescription.location())) {
+                !Objects.equals(existingHost.location(), hostDescription.location()) ||
+                hostDescription.timestamp() == null ||
+                hostDescription.timestamp().isNewerThan(existingHost.timestamp())) {
             return true;
         }
 
@@ -173,13 +177,13 @@
                            } else {
                                annotations = hostDescription.annotations();
                            }
-
                            return new DefaultHost(providerId,
                                                   hostId,
                                                   hostDescription.hwAddress(),
                                                   hostDescription.vlan(),
                                                   location,
                                                   addresses,
+                                                  hostDescription.timestamp(),
                                                   annotations);
                        });
         return null;
@@ -302,3 +306,4 @@
         }
     }
 }
+
diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index 46b7d88..3dffa9f 100644
--- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -44,17 +44,22 @@
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
+import org.onosproject.net.MastershipRole;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.host.DefaultHostDescription;
 import org.onosproject.net.host.HostDescription;
 import org.onosproject.net.host.HostProvider;
 import org.onosproject.net.host.HostProviderRegistry;
 import org.onosproject.net.host.HostProviderService;
 import org.onosproject.net.host.HostService;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
@@ -66,6 +71,7 @@
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
+import java.nio.ByteBuffer;
 import java.util.Dictionary;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -126,6 +132,8 @@
 
     protected ExecutorService eventHandler;
 
+    private static final byte[] SENDER_ADDRESS = IpAddress.valueOf("0.0.0.0").toOctets();
+
     /**
      * Creates an OpenFlow host provider.
      */
@@ -261,7 +269,60 @@
 
     @Override
     public void triggerProbe(Host host) {
-        log.info("Triggering probe on device {}", host);
+        log.info("Triggering probe on device {} ", host);
+        MastershipRole role = deviceService.getRole(host.location().deviceId());
+        if (role.equals(MastershipRole.MASTER)) {
+            host.ipAddresses().forEach(ip -> {
+                sendProbe(host, ip);
+            });
+        } else {
+            log.info("not the master, master will probe {}");
+        }
+    }
+
+    private void sendProbe(Host host, IpAddress targetIp) {
+        Ethernet probePacket = null;
+        if (targetIp.isIp4()) {
+            // IPv4: Use ARP
+            probePacket = buildArpRequest(targetIp, host);
+        } else {
+            // IPv6: Use Neighbor Discovery
+            //FIX ME need to implement ndp probe
+            log.info("Triggering probe on device {} ", host);
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(host.location().port()).build();
+
+        OutboundPacket outboundPacket = new DefaultOutboundPacket(host.location().deviceId(), treatment,
+                ByteBuffer.wrap(probePacket.serialize()));
+
+        packetService.emit(outboundPacket);
+    }
+
+    /*
+     * This method is using source ip as 0.0.0.0 , to receive the reply even from the sub net hosts.
+     */
+    private Ethernet buildArpRequest(IpAddress targetIp, Host host) {
+
+        ARP arp = new ARP();
+        arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
+           .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
+           .setProtocolType(ARP.PROTO_TYPE_IP)
+           .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
+           .setOpCode(ARP.OP_REQUEST);
+
+        arp.setSenderHardwareAddress(MacAddress.BROADCAST.toBytes())
+                .setSenderProtocolAddress(SENDER_ADDRESS)
+                .setTargetHardwareAddress(MacAddress.BROADCAST.toBytes())
+                .setTargetProtocolAddress(targetIp.toOctets());
+
+        Ethernet ethernet = new Ethernet();
+        ethernet.setEtherType(Ethernet.TYPE_ARP)
+                .setDestinationMACAddress(MacAddress.BROADCAST)
+                .setSourceMACAddress(MacAddress.BROADCAST).setPayload(arp);
+
+        ethernet.setPad(true);
+        return ethernet;
     }
 
     private class InternalHostProvider implements PacketProcessor {
@@ -449,3 +510,4 @@
     }
 
 }
+
diff --git a/utils/misc/src/main/java/org/onlab/util/Tools.java b/utils/misc/src/main/java/org/onlab/util/Tools.java
index 73d2a36..81c9bce 100644
--- a/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -348,6 +348,26 @@
     }
 
     /**
+     * Get Long property from the propertyName
+     * Return null if propertyName is not found.
+     *
+     * @param properties   properties to be looked up
+     * @param propertyName the name of the property to look up
+     * @return value when the propertyName is defined or return null
+     */
+    public static Long getLongProperty(Dictionary<?, ?> properties,
+                                             String propertyName) {
+        Long value;
+        try {
+            String s = get(properties, propertyName);
+            value = Strings.isNullOrEmpty(s) ? null : Long.valueOf(s);
+        } catch (NumberFormatException | ClassCastException e) {
+            value = null;
+        }
+        return value;
+    }
+
+    /**
      * Suspends the current thread for a specified number of millis.
      *
      * @param ms number of millis
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
index 1f992c9..072ca33 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
@@ -198,7 +198,7 @@
         @Override
         public boolean matchesSafely(JsonArray json) {
             boolean hostFound = false;
-            final int expectedAttributes = 5;
+            final int expectedAttributes = 6;
             for (int jsonHostIndex = 0; jsonHostIndex < json.size();
                  jsonHostIndex++) {