Integrating hosts learned through DHCP into topology

Change-Id: I5394b9bad9660b79f8217521d6c27699e85e0559
diff --git a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
index 2e9818c..ccb9e67 100644
--- a/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
+++ b/onos-app-dhcpserver/src/main/java/org/onosproject/dhcpserver/impl/DHCPManager.java
@@ -28,8 +28,10 @@
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.UDP;
+import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.dhcpserver.DHCPService;
@@ -39,20 +41,30 @@
 import org.onosproject.incubator.net.config.NetworkConfigListener;
 import org.onosproject.incubator.net.config.NetworkConfigRegistry;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
 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.HostProvider;
+import org.onosproject.net.host.HostProviderRegistry;
+import org.onosproject.net.host.HostProviderService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.ProviderId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -67,6 +79,7 @@
 @Service
 public class DHCPManager implements DHCPService {
 
+    private static final ProviderId PID = new ProviderId("of", "org.onosproject.dhcpserver", true);
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private final NetworkConfigListener cfgListener = new InternalConfigListener();
@@ -103,6 +116,11 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DHCPStore dhcpStore;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostProviderRegistry hostProviderRegistry;
+
+    protected HostProviderService hostProviderService;
+
     private ApplicationId appId;
 
     // Hardcoded values are default values.
@@ -132,6 +150,7 @@
     private static String routerAddress = "10.0.0.2";
 
     private static String domainServer = "10.0.0.2";
+    private final HostProvider hostProvider = new InternalHostProvider();
 
     @Activate
     protected void activate() {
@@ -140,6 +159,7 @@
 
         cfgService.addListener(cfgListener);
         factories.forEach(cfgService::registerConfigFactory);
+        hostProviderService = hostProviderRegistry.register(hostProvider);
         packetService.addProcessor(processor, PacketProcessor.observer(1));
         requestPackets();
         log.info("Started");
@@ -150,6 +170,8 @@
         cfgService.removeListener(cfgListener);
         factories.forEach(cfgService::unregisterConfigFactory);
         packetService.removeProcessor(processor);
+        hostProviderRegistry.unregister(hostProvider);
+        hostProviderService = null;
         cancelPackets();
         log.info("Stopped");
     }
@@ -434,6 +456,7 @@
                             Ethernet ethReply = buildReply(packet, requestedIP.toString(),
                                     outgoingPacketType.getValue());
                             sendReply(context, ethReply);
+                            discoverHost(context, requestedIP);
                         }
                     } else if (flagIfRequestedIP) {
                         // INIT-REBOOT state
@@ -441,6 +464,7 @@
                             Ethernet ethReply = buildReply(packet, requestedIP.toString(),
                                     outgoingPacketType.getValue());
                             sendReply(context, ethReply);
+                            discoverHost(context, requestedIP);
                         }
                     } else {
                         // RENEWING and REBINDING state
@@ -451,6 +475,7 @@
                                 Ethernet ethReply = buildReply(packet, clientIaddr.toString(),
                                         outgoingPacketType.getValue());
                                 sendReply(context, ethReply);
+                                discoverHost(context, clientIaddr);
                             }
                         }
                     }
@@ -490,6 +515,25 @@
             sendReply(context, ethReply);
         }
 
+        /**
+         * Integrates hosts learned through DHCP into topology.
+         * @param context context of the incoming message
+         * @param ipAssigned IP Address assigned to the host by DHCP Manager
+         */
+        private void discoverHost(PacketContext context, Ip4Address ipAssigned) {
+            Ethernet packet = context.inPacket().parsed();
+            MacAddress mac = packet.getSourceMAC();
+            VlanId vlanId = VlanId.vlanId(packet.getVlanID());
+            HostLocation hostLocation = new HostLocation(context.inPacket().receivedFrom(), 0);
+
+            Set<IpAddress> ips = new HashSet<>();
+            ips.add(ipAssigned);
+
+            HostId hostId = HostId.hostId(mac, vlanId);
+            DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips);
+            hostProviderService.hostDetected(hostId, desc);
+        }
+
 
         @Override
         public void process(PacketContext context) {
@@ -604,4 +648,19 @@
             }
         }
     }
+
+    private class InternalHostProvider extends AbstractProvider implements HostProvider {
+
+        /**
+         * Creates a provider with the supplier identifier.
+         */
+        protected InternalHostProvider() {
+            super(PID);
+        }
+
+        @Override
+        public void triggerProbe(Host host) {
+            // nothing to do
+        }
+    }
 }
\ No newline at end of file
diff --git a/onos-app-dhcpserver/src/test/java/org/onosproject/dhcpserver/impl/DHCPManagerTest.java b/onos-app-dhcpserver/src/test/java/org/onosproject/dhcpserver/impl/DHCPManagerTest.java
index a98d119..0807653 100644
--- a/onos-app-dhcpserver/src/test/java/org/onosproject/dhcpserver/impl/DHCPManagerTest.java
+++ b/onos-app-dhcpserver/src/test/java/org/onosproject/dhcpserver/impl/DHCPManagerTest.java
@@ -26,25 +26,32 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.UDP;
-import org.onosproject.core.CoreService;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.dhcpserver.DHCPStore;
-import org.onosproject.incubator.net.config.NetworkConfigRegistry;
 import org.onosproject.incubator.net.config.NetworkConfigRegistryAdapter;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+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.packet.DefaultInboundPacket;
 import org.onosproject.net.packet.DefaultPacketContext;
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
 import org.onosproject.net.packet.PacketProcessor;
-import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.packet.PacketServiceAdapter;
+import org.onosproject.net.provider.AbstractProvider;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -58,16 +65,10 @@
 
     private DHCPManager dhcpManager;
 
-    protected NetworkConfigRegistry cfgService;
-
-    protected PacketService packetService;
-
-    protected CoreService coreService;
-
-    protected DHCPStore dhcpStore;
-
     protected PacketProcessor packetProcessor;
 
+    protected HostProviderService hostProviderService;
+
     private static final MacAddress CLIENT1_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
 
     private static final String EXPECTED_IP = "10.2.0.2";
@@ -76,6 +77,8 @@
 
     private static final int TRANSACTION_ID = 1000;
 
+    private static final ProviderId PID = new ProviderId("of", "foo");
+
     @Before
     public void setUp() {
         dhcpManager = new DHCPManager();
@@ -83,6 +86,9 @@
         dhcpManager.packetService = new TestPacketService();
         dhcpManager.coreService = new TestCoreService();
         dhcpManager.dhcpStore = new TestDHCPStore();
+        hostProviderService = new TestHostProviderService(new TestHostProvider());
+        dhcpManager.hostProviderService = hostProviderService;
+        dhcpManager.hostProviderRegistry = new TestHostRegistry();
         dhcpManager.activate();
     }
 
@@ -289,12 +295,80 @@
         }
     }
 
+    /**
+     * Mocks the CoreService.
+     */
     private class TestCoreService extends CoreServiceAdapter {
 
     }
 
+    /**
+     * Mocks the NetworkConfigRegistry.
+     */
     private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
 
     }
 
+    /**
+     * Mocks the HostProviderService.
+     */
+    private class TestHostProviderService extends AbstractProviderService<HostProvider>
+            implements HostProviderService {
+
+        protected TestHostProviderService(HostProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void hostDetected(HostId hostId, HostDescription hostDescription) {
+        }
+
+        @Override
+        public void hostVanished(HostId hostId) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProvider.
+     */
+    private static class TestHostProvider extends AbstractProvider
+            implements HostProvider {
+
+        protected TestHostProvider() {
+            super(PID);
+        }
+
+        @Override
+        public ProviderId id() {
+            return PID;
+        }
+
+        @Override
+        public void triggerProbe(Host host) {
+        }
+
+    }
+
+    /**
+     * Mocks the HostProviderRegistry.
+     */
+    private class TestHostRegistry implements HostProviderRegistry {
+
+        @Override
+        public HostProviderService register(HostProvider provider) {
+            return hostProviderService;
+        }
+
+        @Override
+        public void unregister(HostProvider provider) {
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+
+    }
+
 }