Refactored the HostStore to allow multiple MAC addresses bound to a single port

Change-Id: Icd3b2e483b15486251ac1cca107478a012d1a3e7
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
index 6c27ea8..2f8fbd2 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleHostStore.java
@@ -15,10 +15,18 @@
  */
 package org.onlab.onos.store.trivial.impl;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
+import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
+import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
+import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
+import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -34,7 +42,6 @@
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
 import org.onlab.onos.net.host.HostStoreDelegate;
-import org.onlab.onos.net.host.InterfaceIpAddress;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.AbstractStore;
@@ -43,13 +50,11 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import static org.onlab.onos.net.host.HostEvent.Type.*;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
 
 // TODO: multi-provider, annotation not supported.
 /**
@@ -70,8 +75,9 @@
     // Hosts tracked by their location
     private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
 
-    private final Map<ConnectPoint, PortAddresses> portAddresses =
-            new ConcurrentHashMap<>();
+    private final SetMultimap<ConnectPoint, PortAddresses> portAddresses =
+            Multimaps.synchronizedSetMultimap(
+                    HashMultimap.<ConnectPoint, PortAddresses>create());
 
     @Activate
     public void activate() {
@@ -213,77 +219,37 @@
 
     @Override
     public void updateAddressBindings(PortAddresses addresses) {
-        synchronized (portAddresses) {
-            PortAddresses existing = portAddresses.get(addresses.connectPoint());
-            if (existing == null) {
-                portAddresses.put(addresses.connectPoint(), addresses);
-            } else {
-                Set<InterfaceIpAddress> union =
-                    Sets.union(existing.ipAddresses(),
-                               addresses.ipAddresses()).immutableCopy();
-
-                MacAddress newMac = (addresses.mac() == null) ? existing.mac()
-                        : addresses.mac();
-
-                PortAddresses newAddresses =
-                        new PortAddresses(addresses.connectPoint(), union, newMac);
-
-                portAddresses.put(newAddresses.connectPoint(), newAddresses);
-            }
-        }
+        portAddresses.put(addresses.connectPoint(), addresses);
     }
 
     @Override
     public void removeAddressBindings(PortAddresses addresses) {
-        synchronized (portAddresses) {
-            PortAddresses existing = portAddresses.get(addresses.connectPoint());
-            if (existing != null) {
-                Set<InterfaceIpAddress> difference =
-                        Sets.difference(existing.ipAddresses(),
-                                        addresses.ipAddresses()).immutableCopy();
-
-                // If they removed the existing mac, set the new mac to null.
-                // Otherwise, keep the existing mac.
-                MacAddress newMac = existing.mac();
-                if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
-                    newMac = null;
-                }
-
-                PortAddresses newAddresses =
-                        new PortAddresses(addresses.connectPoint(), difference, newMac);
-
-                portAddresses.put(newAddresses.connectPoint(), newAddresses);
-            }
-        }
+        portAddresses.remove(addresses.connectPoint(), addresses);
     }
 
     @Override
     public void clearAddressBindings(ConnectPoint connectPoint) {
-        synchronized (portAddresses) {
-            portAddresses.remove(connectPoint);
-        }
+        portAddresses.removeAll(connectPoint);
     }
 
     @Override
     public Set<PortAddresses> getAddressBindings() {
         synchronized (portAddresses) {
-            return new HashSet<>(portAddresses.values());
+            return ImmutableSet.copyOf(portAddresses.values());
         }
     }
 
     @Override
-    public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
-        PortAddresses addresses;
-
+    public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
         synchronized (portAddresses) {
-            addresses = portAddresses.get(connectPoint);
-        }
+            Set<PortAddresses> addresses = portAddresses.get(connectPoint);
 
-        if (addresses == null) {
-            addresses = new PortAddresses(connectPoint, null, null);
+            if (addresses == null) {
+                return Collections.emptySet();
+            } else {
+                return ImmutableSet.copyOf(addresses);
+            }
         }
-
-        return addresses;
     }
 
     // Auxiliary extension to allow location to mutate.