Speeding up stuff.
HostDescription now passes up just a single IpAddress.
diff --git a/apps/tvue/src/main/java/org/onlab/onos/tvue/package-info.java b/apps/tvue/src/main/java/org/onlab/onos/tvue/package-info.java
index bfd46a6..c3a6d857 100644
--- a/apps/tvue/src/main/java/org/onlab/onos/tvue/package-info.java
+++ b/apps/tvue/src/main/java/org/onlab/onos/tvue/package-info.java
@@ -1,4 +1,4 @@
 /**
- * REST resources for the sample topology viewer application.
+ * Sample topology viewer application.
  */
 package org.onlab.onos.tvue;
diff --git a/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java b/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
index e843770..1597b55 100644
--- a/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/SummaryCommand.java
@@ -22,8 +22,10 @@
     protected void execute() {
         TopologyService topologyService = get(TopologyService.class);
         Topology topology = topologyService.currentTopology();
-        print("version=%s, nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
-              get(CoreService.class).version().toString(),
+        print("node=%s, version=%s",
+              get(ClusterService.class).getLocalNode().ip(),
+              get(CoreService.class).version().toString());
+        print("nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
               get(ClusterService.class).getNodes().size(),
               get(DeviceService.class).getDeviceCount(),
               get(LinkService.class).getLinkCount(),
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 bc6e3e5..2e92dad 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
@@ -1,6 +1,5 @@
 package org.onlab.onos.net.host;
 
-import com.google.common.collect.ImmutableSet;
 import org.onlab.onos.net.AbstractDescription;
 import org.onlab.onos.net.HostLocation;
 import org.onlab.onos.net.SparseAnnotations;
@@ -8,9 +7,6 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import static com.google.common.base.MoreObjects.toStringHelper;
 
 /**
@@ -22,7 +18,7 @@
     private final MacAddress mac;
     private final VlanId vlan;
     private final HostLocation location;
-    private final Set<IpPrefix> ips;
+    private final IpPrefix ip;
 
     /**
      * Creates a host description using the supplied information.
@@ -35,7 +31,7 @@
     public DefaultHostDescription(MacAddress mac, VlanId vlan,
                                   HostLocation location,
                                   SparseAnnotations... annotations) {
-        this(mac, vlan, location, new HashSet<IpPrefix>(), annotations);
+        this(mac, vlan, location, null, annotations);
     }
 
     /**
@@ -44,17 +40,17 @@
      * @param mac         host MAC address
      * @param vlan        host VLAN identifier
      * @param location    host location
-     * @param ips         of host IP addresses
+     * @param ip          host IP address
      * @param annotations optional key/value annotations map
      */
     public DefaultHostDescription(MacAddress mac, VlanId vlan,
-                                  HostLocation location, Set<IpPrefix> ips,
+                                  HostLocation location, IpPrefix ip,
                                   SparseAnnotations... annotations) {
         super(annotations);
         this.mac = mac;
         this.vlan = vlan;
         this.location = location;
-        this.ips = new HashSet<>(ips);
+        this.ip = ip;
     }
 
     @Override
@@ -73,8 +69,8 @@
     }
 
     @Override
-    public Set<IpPrefix> ipAddresses() {
-        return ImmutableSet.copyOf(ips);
+    public IpPrefix ipAddress() {
+        return ip;
     }
 
     @Override
@@ -83,7 +79,7 @@
                 .add("mac", mac)
                 .add("vlan", vlan)
                 .add("location", location)
-                .add("ipAddresses", ips)
+                .add("ipAddress", ip)
                 .toString();
     }
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/HostDescription.java b/core/api/src/main/java/org/onlab/onos/net/host/HostDescription.java
index 27014b6..f45a383 100644
--- a/core/api/src/main/java/org/onlab/onos/net/host/HostDescription.java
+++ b/core/api/src/main/java/org/onlab/onos/net/host/HostDescription.java
@@ -1,7 +1,5 @@
 package org.onlab.onos.net.host;
 
-import java.util.Set;
-
 import org.onlab.onos.net.Description;
 import org.onlab.onos.net.HostLocation;
 import org.onlab.packet.IpPrefix;
@@ -35,10 +33,10 @@
     HostLocation location();
 
     /**
-     * Returns zero or more IP address(es) associated with this host's MAC.
+     * Returns the IP address associated with this host's MAC.
      *
-     * @return a set of IP addresses.
+     * @return host IP address
      */
-    Set<IpPrefix> ipAddresses();
+    IpPrefix ipAddress();
 
 }
diff --git a/core/api/src/test/java/org/onlab/onos/event/AbstractEventAccumulatorTest.java b/core/api/src/test/java/org/onlab/onos/event/AbstractEventAccumulatorTest.java
index 9e561bf..ed18195 100644
--- a/core/api/src/test/java/org/onlab/onos/event/AbstractEventAccumulatorTest.java
+++ b/core/api/src/test/java/org/onlab/onos/event/AbstractEventAccumulatorTest.java
@@ -45,15 +45,18 @@
     public void timeTrigger() {
         TestAccumulator accumulator = new TestAccumulator();
         accumulator.add(new TestEvent(FOO, "a"));
-        delay(40);
+        delay(30);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestEvent(FOO, "b"));
-        delay(40);
+        delay(30);
         assertTrue("should not have fired yet", accumulator.batch.isEmpty());
         accumulator.add(new TestEvent(FOO, "c"));
-        delay(40);
+        delay(30);
+        assertTrue("should not have fired yet", accumulator.batch.isEmpty());
+        accumulator.add(new TestEvent(FOO, "d"));
+        delay(30);
         assertFalse("should have fired", accumulator.batch.isEmpty());
-        assertEquals("incorrect batch", "abc", accumulator.batch);
+        assertEquals("incorrect batch", "abcd", accumulator.batch);
     }
 
     @Test
diff --git a/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java b/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java
index 1b00be7..5ae7c27 100644
--- a/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/host/DefualtHostDecriptionTest.java
@@ -1,10 +1,5 @@
 package org.onlab.onos.net.host;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Set;
-
 import org.junit.Test;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.HostLocation;
@@ -13,7 +8,8 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
-import com.google.common.collect.Sets;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Test for the default host description.
@@ -22,24 +18,22 @@
 
     private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
     private static final VlanId VLAN = VlanId.vlanId((short) 10);
+    private static final IpPrefix IP = IpPrefix.valueOf("10.0.0.1");
+
     private static final HostLocation LOC = new HostLocation(
-                DeviceId.deviceId("of:foo"),
-                PortNumber.portNumber(100),
-                123L
-            );
-    private static final Set<IpPrefix> IPS = Sets.newHashSet(
-                IpPrefix.valueOf("10.0.0.1"),
-                IpPrefix.valueOf("10.0.0.2")
-            );
+            DeviceId.deviceId("of:foo"),
+            PortNumber.portNumber(100),
+            123L
+    );
 
     @Test
     public void basics() {
         HostDescription host =
-                new DefaultHostDescription(MAC, VLAN, LOC, IPS);
+                new DefaultHostDescription(MAC, VLAN, LOC, IP);
         assertEquals("incorrect mac", MAC, host.hwAddress());
         assertEquals("incorrect vlan", VLAN, host.vlan());
         assertEquals("incorrect location", LOC, host.location());
-        assertTrue("incorrect ip's", IPS.equals(host.ipAddresses()));
+        assertEquals("incorrect ip's", IP, host.ipAddress());
         assertTrue("incorrect toString", host.toString().contains("vlan=10"));
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
index 29a0f18..4f9bcbb 100644
--- a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
@@ -168,7 +168,6 @@
         checkNotNull(hostId, HOST_ID_NULL);
         HostEvent event = store.removeHost(hostId);
         if (event != null) {
-            log.info("Host {} administratively removed", hostId);
             post(event);
         }
     }
@@ -214,7 +213,6 @@
             HostEvent event = store.createOrUpdateHost(provider().id(), hostId,
                                                        hostDescription);
             if (event != null) {
-                log.debug("Host {} detected", hostId);
                 post(event);
             }
         }
@@ -225,7 +223,6 @@
             checkValidity();
             HostEvent event = store.removeHost(hostId);
             if (event != null) {
-                log.debug("Host {} vanished", hostId);
                 post(event);
             }
         }
diff --git a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
index 0b07380..6864fd7 100644
--- a/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/host/impl/HostManagerTest.java
@@ -58,8 +58,6 @@
 
     private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1");
     private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2");
-    private static final Set<IpPrefix> IPSET1 = Sets.newHashSet(IP1);
-    private static final Set<IpPrefix> IPSET2 = Sets.newHashSet(IP2);
 
     private static final DeviceId DID1 = DeviceId.deviceId("of:001");
     private static final DeviceId DID2 = DeviceId.deviceId("of:002");
@@ -94,14 +92,14 @@
         provider = new TestHostProvider();
         providerService = registry.register(provider);
         assertTrue("provider should be registered",
-                registry.getProviders().contains(provider.id()));
+                   registry.getProviders().contains(provider.id()));
     }
 
     @After
     public void tearDown() {
         registry.unregister(provider);
         assertFalse("provider should not be registered",
-                registry.getProviders().contains(provider.id()));
+                    registry.getProviders().contains(provider.id()));
 
         mgr.removeListener(listener);
         mgr.deactivate();
@@ -109,8 +107,8 @@
     }
 
     private void detect(HostId hid, MacAddress mac, VlanId vlan,
-            HostLocation loc, Set<IpPrefix> ips) {
-        HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ips);
+                        HostLocation loc, IpPrefix ip) {
+        HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
         providerService.hostDetected(hid, descr);
         assertNotNull("host should be found", mgr.getHost(hid));
     }
@@ -130,26 +128,26 @@
         assertNull("host shouldn't be found", mgr.getHost(HID1));
 
         // host addition
-        detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
+        detect(HID1, MAC1, VLAN1, LOC1, IP1);
         assertEquals("exactly one should be found", 1, mgr.getHostCount());
-        detect(HID2, MAC2, VLAN2, LOC2, IPSET1);
+        detect(HID2, MAC2, VLAN2, LOC2, IP1);
         assertEquals("two hosts should be found", 2, mgr.getHostCount());
         validateEvents(HOST_ADDED, HOST_ADDED);
 
         // host motion
-        detect(HID1, MAC1, VLAN1, LOC2, IPSET1);
+        detect(HID1, MAC1, VLAN1, LOC2, IP1);
         validateEvents(HOST_MOVED);
         assertEquals("only two hosts should be found", 2, mgr.getHostCount());
 
         // host update
-        detect(HID1, MAC1, VLAN1, LOC2, IPSET2);
+        detect(HID1, MAC1, VLAN1, LOC2, IP2);
         validateEvents(HOST_UPDATED);
         assertEquals("only two hosts should be found", 2, mgr.getHostCount());
     }
 
     @Test
     public void hostVanished() {
-        detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
+        detect(HID1, MAC1, VLAN1, LOC1, IP1);
         providerService.hostVanished(HID1);
         validateEvents(HOST_ADDED, HOST_REMOVED);
 
@@ -157,7 +155,7 @@
     }
 
     private void validateHosts(
-            String msg, Iterable<Host> hosts, HostId ... ids) {
+            String msg, Iterable<Host> hosts, HostId... ids) {
         Set<HostId> hids = Sets.newHashSet(ids);
         for (Host h : hosts) {
             assertTrue(msg, hids.remove(h.id()));
@@ -167,8 +165,8 @@
 
     @Test
     public void getHosts() {
-        detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
-        detect(HID2, MAC2, VLAN1, LOC2, IPSET2);
+        detect(HID1, MAC1, VLAN1, LOC1, IP1);
+        detect(HID2, MAC2, VLAN1, LOC2, IP2);
 
         validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2);
         validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2);
@@ -210,7 +208,7 @@
     @Test
     public void bindAddressesToPort() {
         PortAddresses add1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -241,7 +239,7 @@
     @Test
     public void unbindAddressesFromPort() {
         PortAddresses add1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -250,7 +248,7 @@
         assertNotNull(storedAddresses.mac());
 
         PortAddresses rem1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1), null);
+                                               Sets.newHashSet(PREFIX1), null);
 
         mgr.unbindAddressesFromPort(rem1);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -267,7 +265,7 @@
         assertNull(storedAddresses.mac());
 
         PortAddresses rem3 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX2), MAC1);
 
         mgr.unbindAddressesFromPort(rem3);
         storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -279,7 +277,7 @@
     @Test
     public void clearAddresses() {
         PortAddresses add1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -297,7 +295,7 @@
     @Test
     public void getAddressBindingsForPort() {
         PortAddresses add1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
 
         mgr.bindAddressesToPort(add1);
         PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
@@ -314,7 +312,7 @@
         assertTrue(storedAddresses.isEmpty());
 
         PortAddresses add1 = new PortAddresses(CP1,
-                Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
+                                               Sets.newHashSet(PREFIX1, PREFIX2), MAC1);
 
         mgr.bindAddressesToPort(add1);
 
@@ -323,7 +321,7 @@
         assertTrue(storedAddresses.size() == 1);
 
         PortAddresses add2 = new PortAddresses(CP2,
-                Sets.newHashSet(PREFIX3), MAC2);
+                                               Sets.newHashSet(PREFIX3), MAC2);
 
         mgr.bindAddressesToPort(add2);
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
index 09820f4..9362156 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
@@ -1,26 +1,20 @@
 package org.onlab.onos.store.host.impl;
 
-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 com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 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.Service;
+import org.onlab.onos.net.Annotations;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DefaultHost;
 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.host.HostDescription;
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
@@ -33,10 +27,13 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
-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 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;
 
 /**
  * Manages inventory of end-station hosts using trivial in-memory
@@ -46,13 +43,13 @@
 @Component(immediate = true)
 @Service
 public class DistributedHostStore
-extends AbstractStore<HostEvent, HostStoreDelegate>
-implements HostStore {
+        extends AbstractStore<HostEvent, HostStoreDelegate>
+        implements HostStore {
 
     private final Logger log = getLogger(getClass());
 
     // Host inventory
-    private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
+    private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
 
     // Hosts tracked by their location
     private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
@@ -72,8 +69,8 @@
 
     @Override
     public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
-            HostDescription hostDescription) {
-        Host host = hosts.get(hostId);
+                                        HostDescription hostDescription) {
+        StoredHost host = hosts.get(hostId);
         if (host == null) {
             return createHost(providerId, hostId, hostDescription);
         }
@@ -82,12 +79,12 @@
 
     // creates a new host and sends HOST_ADDED
     private HostEvent createHost(ProviderId providerId, HostId hostId,
-            HostDescription descr) {
-        DefaultHost newhost = new DefaultHost(providerId, hostId,
-                descr.hwAddress(),
-                descr.vlan(),
-                descr.location(),
-                descr.ipAddresses());
+                                 HostDescription descr) {
+        StoredHost newhost = new StoredHost(providerId, hostId,
+                                            descr.hwAddress(),
+                                            descr.vlan(),
+                                            descr.location(),
+                                            ImmutableSet.of(descr.ipAddress()));
         synchronized (this) {
             hosts.put(hostId, newhost);
             locations.put(descr.location(), newhost);
@@ -96,28 +93,24 @@
     }
 
     // checks for type of update to host, sends appropriate event
-    private HostEvent updateHost(ProviderId providerId, Host host,
-            HostDescription descr) {
-        DefaultHost updated;
+    private HostEvent updateHost(ProviderId providerId, StoredHost host,
+                                 HostDescription descr) {
         HostEvent event;
         if (!host.location().equals(descr.location())) {
-            updated = new DefaultHost(providerId, host.id(),
-                    host.mac(),
-                    host.vlan(),
-                    descr.location(),
-                    host.ipAddresses());
-            event = new HostEvent(HOST_MOVED, updated);
+            host.setLocation(descr.location());
+            return new HostEvent(HOST_MOVED, host);
+        }
 
-        } 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 {
+        if (host.ipAddresses().contains(descr.ipAddress())) {
             return null;
         }
+
+        Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
+        addresses.add(descr.ipAddress());
+        StoredHost updated = new StoredHost(providerId, host.id(),
+                                            host.mac(), host.vlan(),
+                                            descr.location(), addresses);
+        event = new HostEvent(HOST_UPDATED, updated);
         synchronized (this) {
             hosts.put(host.id(), updated);
             locations.remove(host.location(), host);
@@ -145,7 +138,7 @@
 
     @Override
     public Iterable<Host> getHosts() {
-        return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
+        return ImmutableSet.<Host>copyOf(hosts.values());
     }
 
     @Override
@@ -275,4 +268,35 @@
         return addresses;
     }
 
+    // Auxiliary extension to allow location to mutate.
+    private class StoredHost extends DefaultHost {
+        private HostLocation location;
+
+        /**
+         * 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 annotations optional key/value annotations
+         */
+        public StoredHost(ProviderId providerId, HostId id,
+                          MacAddress mac, VlanId vlan, HostLocation location,
+                          Set<IpPrefix> ips, Annotations... annotations) {
+            super(providerId, id, mac, vlan, location, ips, annotations);
+            this.location = location;
+        }
+
+        void setLocation(HostLocation location) {
+            this.location = location;
+        }
+
+        @Override
+        public HostLocation location() {
+            return location;
+        }
+    }
 }
diff --git a/core/store/hz/net/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java b/core/store/hz/net/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
index 5c706e6..0ca4ae2 100644
--- a/core/store/hz/net/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
+++ b/core/store/hz/net/src/main/java/org/onlab/onos/store/host/impl/DistributedHostStore.java
@@ -1,26 +1,20 @@
 package org.onlab.onos.store.host.impl;
 
-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 com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 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.Service;
+import org.onlab.onos.net.Annotations;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DefaultHost;
 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.host.HostDescription;
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
@@ -33,10 +27,13 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
-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 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;
 
 /**
  * TEMPORARY: Manages inventory of end-station hosts using distributed
@@ -46,13 +43,13 @@
 @Component(immediate = true)
 @Service
 public class DistributedHostStore
-extends AbstractStore<HostEvent, HostStoreDelegate>
-implements HostStore {
+        extends AbstractStore<HostEvent, HostStoreDelegate>
+        implements HostStore {
 
     private final Logger log = getLogger(getClass());
 
     // Host inventory
-    private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
+    private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
 
     // Hosts tracked by their location
     private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
@@ -72,8 +69,8 @@
 
     @Override
     public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
-            HostDescription hostDescription) {
-        Host host = hosts.get(hostId);
+                                        HostDescription hostDescription) {
+        StoredHost host = hosts.get(hostId);
         if (host == null) {
             return createHost(providerId, hostId, hostDescription);
         }
@@ -82,12 +79,12 @@
 
     // creates a new host and sends HOST_ADDED
     private HostEvent createHost(ProviderId providerId, HostId hostId,
-            HostDescription descr) {
-        DefaultHost newhost = new DefaultHost(providerId, hostId,
-                descr.hwAddress(),
-                descr.vlan(),
-                descr.location(),
-                descr.ipAddresses());
+                                 HostDescription descr) {
+        StoredHost newhost = new StoredHost(providerId, hostId,
+                                            descr.hwAddress(),
+                                            descr.vlan(),
+                                            descr.location(),
+                                            ImmutableSet.of(descr.ipAddress()));
         synchronized (this) {
             hosts.put(hostId, newhost);
             locations.put(descr.location(), newhost);
@@ -96,28 +93,24 @@
     }
 
     // checks for type of update to host, sends appropriate event
-    private HostEvent updateHost(ProviderId providerId, Host host,
-            HostDescription descr) {
-        DefaultHost updated;
+    private HostEvent updateHost(ProviderId providerId, StoredHost host,
+                                 HostDescription descr) {
         HostEvent event;
         if (!host.location().equals(descr.location())) {
-            updated = new DefaultHost(providerId, host.id(),
-                    host.mac(),
-                    host.vlan(),
-                    descr.location(),
-                    host.ipAddresses());
-            event = new HostEvent(HOST_MOVED, updated);
+            host.setLocation(descr.location());
+            return new HostEvent(HOST_MOVED, host);
+        }
 
-        } 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 {
+        if (host.ipAddresses().contains(descr.ipAddress())) {
             return null;
         }
+
+        Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
+        addresses.add(descr.ipAddress());
+        StoredHost updated = new StoredHost(providerId, host.id(),
+                                            host.mac(), host.vlan(),
+                                            descr.location(), addresses);
+        event = new HostEvent(HOST_UPDATED, updated);
         synchronized (this) {
             hosts.put(host.id(), updated);
             locations.remove(host.location(), host);
@@ -145,7 +138,7 @@
 
     @Override
     public Iterable<Host> getHosts() {
-        return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
+        return ImmutableSet.<Host>copyOf(hosts.values());
     }
 
     @Override
@@ -275,4 +268,35 @@
         return addresses;
     }
 
+    // Auxiliary extension to allow location to mutate.
+    private class StoredHost extends DefaultHost {
+        private HostLocation location;
+
+        /**
+         * 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 annotations optional key/value annotations
+         */
+        public StoredHost(ProviderId providerId, HostId id,
+                          MacAddress mac, VlanId vlan, HostLocation location,
+                          Set<IpPrefix> ips, Annotations... annotations) {
+            super(providerId, id, mac, vlan, location, ips, annotations);
+            this.location = location;
+        }
+
+        void setLocation(HostLocation location) {
+            this.location = location;
+        }
+
+        @Override
+        public HostLocation location() {
+            return location;
+        }
+    }
 }
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 92d6a22..67ed050 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
@@ -1,26 +1,20 @@
 package org.onlab.onos.store.trivial.impl;
 
-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 com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
 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.Service;
+import org.onlab.onos.net.Annotations;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DefaultHost;
 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.host.HostDescription;
 import org.onlab.onos.net.host.HostEvent;
 import org.onlab.onos.net.host.HostStore;
@@ -33,10 +27,13 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
-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 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;
 
 /**
  * Manages inventory of end-station hosts using trivial in-memory
@@ -51,7 +48,7 @@
     private final Logger log = getLogger(getClass());
 
     // Host inventory
-    private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
+    private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
 
     // Hosts tracked by their location
     private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
@@ -72,7 +69,7 @@
     @Override
     public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
                                         HostDescription hostDescription) {
-        Host host = hosts.get(hostId);
+        StoredHost host = hosts.get(hostId);
         if (host == null) {
             return createHost(providerId, hostId, hostDescription);
         }
@@ -82,11 +79,11 @@
     // creates a new host and sends HOST_ADDED
     private HostEvent createHost(ProviderId providerId, HostId hostId,
                                  HostDescription descr) {
-        DefaultHost newhost = new DefaultHost(providerId, hostId,
-                                              descr.hwAddress(),
-                                              descr.vlan(),
-                                              descr.location(),
-                                              descr.ipAddresses());
+        StoredHost newhost = new StoredHost(providerId, hostId,
+                                            descr.hwAddress(),
+                                            descr.vlan(),
+                                            descr.location(),
+                                            ImmutableSet.of(descr.ipAddress()));
         synchronized (this) {
             hosts.put(hostId, newhost);
             locations.put(descr.location(), newhost);
@@ -95,28 +92,24 @@
     }
 
     // checks for type of update to host, sends appropriate event
-    private HostEvent updateHost(ProviderId providerId, Host host,
+    private HostEvent updateHost(ProviderId providerId, StoredHost host,
                                  HostDescription descr) {
-        DefaultHost updated;
         HostEvent event;
         if (!host.location().equals(descr.location())) {
-            updated = new DefaultHost(providerId, host.id(),
-                                      host.mac(),
-                                      host.vlan(),
-                                      descr.location(),
-                                      host.ipAddresses());
-            event = new HostEvent(HOST_MOVED, updated);
+            host.setLocation(descr.location());
+            return new HostEvent(HOST_MOVED, host);
+        }
 
-        } 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 {
+        if (host.ipAddresses().contains(descr.ipAddress())) {
             return null;
         }
+
+        Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
+        addresses.add(descr.ipAddress());
+        StoredHost updated = new StoredHost(providerId, host.id(),
+                                            host.mac(), host.vlan(),
+                                            descr.location(), addresses);
+        event = new HostEvent(HOST_UPDATED, updated);
         synchronized (this) {
             hosts.put(host.id(), updated);
             locations.remove(host.location(), host);
@@ -144,7 +137,7 @@
 
     @Override
     public Iterable<Host> getHosts() {
-        return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
+        return ImmutableSet.<Host>copyOf(hosts.values());
     }
 
     @Override
@@ -274,4 +267,35 @@
         return addresses;
     }
 
+    // Auxiliary extension to allow location to mutate.
+    private class StoredHost extends DefaultHost {
+        private HostLocation location;
+
+        /**
+         * 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 annotations optional key/value annotations
+         */
+        public StoredHost(ProviderId providerId, HostId id,
+                          MacAddress mac, VlanId vlan, HostLocation location,
+                          Set<IpPrefix> ips, Annotations... annotations) {
+            super(providerId, id, mac, vlan, location, ips, annotations);
+            this.location = location;
+        }
+
+        void setLocation(HostLocation location) {
+            this.location = location;
+        }
+
+        @Override
+        public HostLocation location() {
+            return location;
+        }
+    }
 }
diff --git a/pom.xml b/pom.xml
index ad4ddcb..bf5e1f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -493,7 +493,7 @@
                         <group>
                             <title>Core Subsystems</title>
                             <packages>
-                                org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl
+                                org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl
                             </packages>
                         </group>
                         <group>
@@ -518,7 +518,7 @@
                         <group>
                             <title>Sample Applications</title>
                             <packages>
-                                org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.foo
+                                org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo
                             </packages>
                         </group>
                     </groups>
diff --git a/providers/openflow/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java b/providers/openflow/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
index 4f5bb81..45a7bd8 100644
--- a/providers/openflow/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
+++ b/providers/openflow/host/src/main/java/org/onlab/onos/provider/of/host/impl/OpenFlowHostProvider.java
@@ -1,12 +1,5 @@
 package org.onlab.onos.provider.of.host.impl;
 
-import static com.google.common.collect.Sets.newHashSet;
-import static org.onlab.onos.net.DeviceId.deviceId;
-import static org.onlab.onos.net.PortNumber.portNumber;
-import static org.slf4j.LoggerFactory.getLogger;
-
-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;
@@ -36,6 +29,10 @@
 import org.onlab.packet.VlanId;
 import org.slf4j.Logger;
 
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.PortNumber.portNumber;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Provider which uses an OpenFlow controller to detect network
  * end-station hosts.
@@ -58,6 +55,8 @@
 
     private final InternalHostProvider listener = new InternalHostProvider();
 
+    private boolean ipLearn = true;
+
     /**
      * Creates an OpenFlow host provider.
      */
@@ -69,7 +68,6 @@
     public void activate() {
         providerService = providerRegistry.register(this);
         controller.addPacketListener(10, listener);
-
         log.info("Started");
     }
 
@@ -78,7 +76,6 @@
         providerRegistry.unregister(this);
         controller.removePacketListener(listener);
         providerService = null;
-
         log.info("Stopped");
     }
 
@@ -95,33 +92,33 @@
 
             VlanId vlan = VlanId.vlanId(eth.getVlanID());
             ConnectPoint heardOn = new ConnectPoint(deviceId(Dpid.uri(pktCtx.dpid())),
-                    portNumber(pktCtx.inPort()));
+                                                    portNumber(pktCtx.inPort()));
 
-         // If this is not an edge port, bail out.
+            // If this is not an edge port, bail out.
             Topology topology = topologyService.currentTopology();
             if (topologyService.isInfrastructure(topology, heardOn)) {
                 return;
             }
 
             HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())),
-                    portNumber(pktCtx.inPort()),
-                    System.currentTimeMillis());
+                                                 portNumber(pktCtx.inPort()),
+                                                 System.currentTimeMillis());
+
             HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
+
             // Potentially a new or moved host
             if (eth.getEtherType() == Ethernet.TYPE_ARP) {
-
-
                 ARP arp = (ARP) eth.getPayload();
-                Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(arp.getSenderProtocolAddress()));
+                IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress());
                 HostDescription hdescr =
-                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
+                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
                 providerService.hostDetected(hid, hdescr);
 
-            } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
-                IPv4 ip = (IPv4) eth.getPayload();
-                Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(ip.getSourceAddress()));
+            } else if (ipLearn && eth.getEtherType() == Ethernet.TYPE_IPV4) {
+                IPv4 pip = (IPv4) eth.getPayload();
+                IpPrefix ip = IpPrefix.valueOf(pip.getSourceAddress());
                 HostDescription hdescr =
-                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
+                        new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
                 providerService.hostDetected(hid, hdescr);
 
             }