Code changes to ensure ONOS has each IP address attached to only one host at a time

Change-Id: I1b4de39175d5bfd5ddf04c9087f4f3beff264594
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 01d943e..bdb5e43 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
@@ -18,12 +18,16 @@
 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.Modified;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.incubator.net.intf.InterfaceService;
 import org.onosproject.net.edge.EdgePortService;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
@@ -48,8 +52,10 @@
 import org.onosproject.net.host.HostStoreDelegate;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.provider.AbstractProviderService;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
+import java.util.Dictionary;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -93,18 +99,42 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EdgePortService edgePortService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
+    @Property(name = "allowDuplicateIps", boolValue = true,
+            label = "Enable removal of duplicate ip address")
+
+    private boolean allowDuplicateIps = true;
     private HostMonitor monitor;
 
+
     @Activate
-    public void activate() {
+    public void activate(ComponentContext context) {
         store.setDelegate(delegate);
         eventDispatcher.addSink(HostEvent.class, listenerRegistry);
+        cfgService.registerProperties(getClass());
+        modified(context);
         networkConfigService.addListener(networkConfigListener);
         monitor = new HostMonitor(packetService, this, interfaceService, edgePortService);
         monitor.start();
         log.info("Started");
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+        Boolean flag;
+        flag = Tools.isPropertyEnabled(properties, "allowDuplicateIps");
+        if (flag == null) {
+            log.info("Removal of duplicate ip address is not configured");
+        } else {
+            allowDuplicateIps = flag;
+            log.info("Removal of duplicate ip address is {}",
+                     allowDuplicateIps ? "disabled" : "enabled");
+        }
+    }
+
     @Deactivate
     public void deactivate() {
         store.unsetDelegate(delegate);
@@ -208,10 +238,31 @@
             checkNotNull(hostId, HOST_ID_NULL);
             checkValidity();
             hostDescription = validateHost(hostDescription, hostId);
+
+            if (!allowDuplicateIps) {
+                removeDuplicates(hostId, hostDescription);
+            }
             store.createOrUpdateHost(provider().id(), hostId,
-                                                       hostDescription, replaceIps);
+                                     hostDescription, replaceIps);
         }
 
+        // 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 -> {
+                Set<Host> allHosts = store.getHosts(ip);
+                allHosts.forEach(eachHost -> {
+                    if (!(eachHost.id().equals(hostId))) {
+                        log.info("Duplicate ip {} found on host {} and {}", ip,
+                                 hostId.toString(), eachHost.id().toString());
+                        store.removeIp(eachHost.id(), ip);
+                    }
+                });
+            });
+        }
+
+
+
+
         // returns a HostDescription made from the union of the BasicHostConfig
         // annotations if it exists
         private HostDescription validateHost(HostDescription hostDescription, HostId hostId) {
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 bd5d68f..1eb014f 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
@@ -21,9 +21,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.junit.TestTools;
+import org.onlab.osgi.ComponentContextAdapter;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.common.event.impl.TestEventDispatcher;
 import org.onosproject.event.Event;
 import org.onosproject.net.DeviceId;
@@ -43,6 +45,8 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.trivial.SimpleHostStore;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Set;
 
@@ -94,6 +98,16 @@
     protected TestHostProvider provider;
     protected HostProviderService providerService;
 
+    private static final ComponentContextAdapter REMOVE_DUPS =
+            new ComponentContextAdapter() {
+                @Override
+                public Dictionary getProperties() {
+                    Hashtable<String, String> props = new Hashtable<>();
+                    props.put("allowDuplicateIps", "true");
+                    return props;
+                }
+            };
+
     @Before
     public void setUp() {
         mgr = new HostManager();
@@ -101,8 +115,8 @@
         injectEventDispatcher(mgr, new TestEventDispatcher());
         registry = mgr;
         mgr.networkConfigService = new TestNetworkConfigService();
-        mgr.activate();
-
+        mgr.cfgService = new ComponentConfigAdapter();
+        mgr.activate(REMOVE_DUPS);
         mgr.addListener(listener);
 
         provider = new TestHostProvider();