Merge remote-tracking branch 'origin/master' into dev/murrelet
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index 235b4c5..39e53ff 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -89,6 +89,8 @@
 @Service
 @Property(name = "version", value = "4")
 public class Dhcp4HandlerImpl implements DhcpHandler, HostProvider {
+    public static final String DHCP_V4_RELAY_APP = "org.onosproject.Dhcp4HandlerImpl";
+    public static final ProviderId PROVIDER_ID = new ProviderId("dhcp4", DHCP_V4_RELAY_APP);
     private static Logger log = LoggerFactory.getLogger(Dhcp4HandlerImpl.class);
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -1013,7 +1015,7 @@
 
     @Override
     public ProviderId id() {
-        return DhcpRelayManager.PROVIDER_ID;
+        return PROVIDER_ID;
     }
 
     class InternalHostListener implements HostListener {
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index c247b90..d5afdb7 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -92,6 +92,8 @@
 @Service
 @Property(name = "version", value = "6")
 public class Dhcp6HandlerImpl implements DhcpHandler, HostProvider {
+    public static final String DHCP_V6_RELAY_APP = "org.onosproject.Dhcp6HandlerImpl";
+    public static final ProviderId PROVIDER_ID = new ProviderId("dhcp6", DHCP_V6_RELAY_APP);
     private static Logger log = LoggerFactory.getLogger(Dhcp6HandlerImpl.class);
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -328,7 +330,7 @@
 
     @Override
     public ProviderId id() {
-        return DhcpRelayManager.PROVIDER_ID;
+        return PROVIDER_ID;
     }
 
     @Override
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index 97b19e7..30c9c16 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -96,7 +96,6 @@
 import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
-import org.onosproject.net.provider.ProviderId;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -114,7 +113,6 @@
 @Service
 public class DhcpRelayManager implements DhcpRelayService {
     public static final String DHCP_RELAY_APP = "org.onosproject.dhcprelay";
-    public static final ProviderId PROVIDER_ID = new ProviderId("host", DHCP_RELAY_APP);
     public static final String ROUTE_STORE_IMPL =
             "org.onosproject.routeservice.store.RouteStoreImpl";
     private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
@@ -671,6 +669,11 @@
 
         private void deviceAdd(DeviceId deviceId) {
             IgnoreDhcpConfig config = cfgService.getConfig(appId, IgnoreDhcpConfig.class);
+            if (config == null) {
+                log.debug("No ignoreVlan config found for {}. Do nothing.", deviceId);
+                return;
+            }
+
             Collection<VlanId> vlanIds = config.ignoredVlans().get(deviceId);
             vlanIds.forEach(vlanId -> {
                 processIgnoreVlanRule(deviceId, vlanId, ADD);
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index f45555d..2d553e2 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -139,7 +139,7 @@
     private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
     private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
     private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
-    private static final Host EXISTS_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
+    private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
                                                             CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
                                                             CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
     private static final Interface CLIENT_INTERFACE = new Interface("C1",
@@ -178,7 +178,7 @@
     private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
     private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
     private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
-    private static final Host OUTER_RELAY_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
+    private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
                                                                  OUTER_RELAY_HOST_ID,
                                                                  OUTER_RELAY_MAC,
                                                                  OUTER_RELAY_VLAN,
@@ -199,7 +199,7 @@
     private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
     private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
     private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
-    private static final Host SERVER_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
+    private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
                                                             SERVER_HOST_ID,
                                                             SERVER_MAC,
                                                             SERVER_VLAN,
diff --git a/apps/pi-demo/ecmp/BUCK b/apps/pi-demo/ecmp/BUCK
index 7c6a9af..f268028 100644
--- a/apps/pi-demo/ecmp/BUCK
+++ b/apps/pi-demo/ecmp/BUCK
@@ -15,6 +15,7 @@
     '//apps/pi-demo/ecmp:onos-apps-pi-demo-ecmp',
     '//apps/pi-demo/common:onos-apps-pi-demo-common',
     '//drivers/default:onos-drivers-default',
+    '//incubator/bmv2/model:onos-incubator-bmv2-model',
 ]
 
 onos_app (
@@ -24,4 +25,12 @@
     url = 'http://onosproject.org',
     description = 'Provides ECMP support for a 2-stage clos fabric topology of PI-enabled devices',
     included_bundles = BUNDLES,
+    required_apps = [
+        # FIXME: there should be no dependendcy on a driver here.
+        # However, we depend on the DefaultP4Interpreter that currently lives in the p4runtime
+        # driver. Bringing up the whole app avoids to specify all transitive runtime dependencies
+        # as bundles. DefaultP4Interpreter and other pipeconf-related stuff should leave in a
+        # separate location, outside the drivers.
+        'org.onosproject.drivers.p4runtime'
+    ]
 )
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index 7a205ee..539af62 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -86,20 +86,36 @@
     void processHostAddedAtLocation(Host host, HostLocation location) {
         checkArgument(host.locations().contains(location), "{} is not a location of {}", location, host);
 
-        if (!srManager.isMasterOf(location)) {
-            return;
-        }
-
-        MacAddress mac = host.mac();
-        VlanId vlanId = host.vlan();
+        MacAddress hostMac = host.mac();
+        VlanId hostVlanId = host.vlan();
         Set<HostLocation> locations = host.locations();
         Set<IpAddress> ips = host.ipAddresses();
-        log.info("Host {}/{} is added at {}", mac, vlanId, locations);
+        log.info("Host {}/{} is added at {}", hostMac, hostVlanId, locations);
 
-        processBridgingRule(location.deviceId(), location.port(), mac, vlanId, false);
-        ips.forEach(ip ->
-                processRoutingRule(location.deviceId(), location.port(), mac, vlanId, ip, false)
-        );
+        if (srManager.isMasterOf(location)) {
+            processBridgingRule(location.deviceId(), location.port(), hostMac, hostVlanId, false);
+            ips.forEach(ip ->
+                    processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, false)
+            );
+        }
+
+        // Use the pair link temporarily before the second location of a dual-homed host shows up.
+        // This do not affect single-homed hosts since the flow will be blocked in
+        // processBridgingRule or processRoutingRule due to VLAN or IP mismatch respectively
+        srManager.getPairDeviceId(location.deviceId()).ifPresent(pairDeviceId -> {
+            if (srManager.mastershipService.isLocalMaster(pairDeviceId) &&
+                    host.locations().stream().noneMatch(l -> l.deviceId().equals(pairDeviceId))) {
+                srManager.getPairLocalPorts(pairDeviceId).ifPresent(pairRemotePort -> {
+                    // NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
+                    //       when the host is untagged
+                    VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(hostVlanId);
+
+                    processBridgingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, false);
+                    ips.forEach(ip -> processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId,
+                                    ip, false));
+                });
+            }
+        });
     }
 
     void processHostRemovedEvent(HostEvent event) {
diff --git a/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java b/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
index 3e576b95..98f6fd0 100644
--- a/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
+++ b/apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
@@ -77,6 +77,7 @@
     private static final IpAddress HOST_IP12 = IpAddress.valueOf("10.0.1.2");
     private static final IpAddress HOST_IP13 = IpAddress.valueOf("10.0.1.3");
     private static final IpAddress HOST_IP14 = IpAddress.valueOf("10.0.1.4");
+    private static final IpAddress HOST_IP32 = IpAddress.valueOf("10.0.3.2");
     // Device
     private static final DeviceId DEV1 = DeviceId.deviceId("of:0000000000000001");
     private static final DeviceId DEV2 = DeviceId.deviceId("of:0000000000000002");
@@ -103,6 +104,8 @@
     // Connect Point for dual-homed host failover
     private static final ConnectPoint CP31 = new ConnectPoint(DEV3, P1);
     private static final HostLocation HOST_LOC31 = new HostLocation(CP31, 0);
+    private static final ConnectPoint CP32 = new ConnectPoint(DEV3, P2);
+    private static final HostLocation HOST_LOC32 = new HostLocation(CP32, 0);
     private static final ConnectPoint CP41 = new ConnectPoint(DEV4, P1);
     private static final HostLocation HOST_LOC41 = new HostLocation(CP41, 0);
     private static final ConnectPoint CP39 = new ConnectPoint(DEV3, P9);
@@ -118,13 +121,17 @@
     private static final VlanId INTF_VLAN_NATIVE = VlanId.vlanId((short) 30);
     private static final Set<VlanId> INTF_VLAN_PAIR = Sets.newHashSet(VlanId.vlanId((short) 10),
             VlanId.vlanId((short) 20), VlanId.vlanId((short) 30));
+    private static final VlanId INTF_VLAN_OTHER = VlanId.vlanId((short) 40);
     // Interface subnet
     private static final IpPrefix INTF_PREFIX1 = IpPrefix.valueOf("10.0.1.254/24");
     private static final IpPrefix INTF_PREFIX2 = IpPrefix.valueOf("10.0.2.254/24");
+    private static final IpPrefix INTF_PREFIX3 = IpPrefix.valueOf("10.0.3.254/24");
     private static final InterfaceIpAddress INTF_IP1 =
             new InterfaceIpAddress(INTF_PREFIX1.address(), INTF_PREFIX1);
     private static final InterfaceIpAddress INTF_IP2 =
             new InterfaceIpAddress(INTF_PREFIX2.address(), INTF_PREFIX2);
+    private static final InterfaceIpAddress INTF_IP3 =
+            new InterfaceIpAddress(INTF_PREFIX3.address(), INTF_PREFIX3);
     // Interfaces
     private static final Interface INTF11 =
             new Interface(null, CP11, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
@@ -144,6 +151,9 @@
     private static final Interface INTF31 =
             new Interface(null, CP31, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
                     INTF_VLAN_UNTAGGED, null, null);
+    private static final Interface INTF32 =
+            new Interface(null, CP32, Lists.newArrayList(INTF_IP3), MacAddress.NONE, null,
+                    INTF_VLAN_OTHER, null, null);
     private static final Interface INTF39 =
             new Interface(null, CP39, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
                     null, INTF_VLAN_PAIR, null);
@@ -164,7 +174,7 @@
     private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(DEV1, DEV2, DEV3, DEV4);
     // A set of interfaces
     private static final Set<Interface> INTERFACES = Sets.newHashSet(INTF11, INTF12, INTF13, INTF21,
-            INTF22, INTF31, INTF39, INTF41, INTF49);
+            INTF22, INTF31, INTF32, INTF39, INTF41, INTF49);
 
     @Before
     public void setUp() throws Exception {
@@ -297,6 +307,48 @@
     }
 
     @Test
+    public void testSingleHomedHostAddedOnPairLeaf() throws Exception {
+        Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC32), Sets.newHashSet(HOST_IP32), false);
+
+        // Add a single-homed host with one location
+        // Expect: the pair link should not be utilized
+        hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
+        assertEquals(1, ROUTING_TABLE.size());
+        assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP32.toIpPrefix())).portNumber);
+        assertEquals(1, BRIDGING_TABLE.size());
+        assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_OTHER)).portNumber);
+    }
+
+    @Test
+    public void testDualHomedHostAddedOneByOne() throws Exception {
+        Host host1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC31), Sets.newHashSet(HOST_IP11), false);
+        Host host2 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC31, HOST_LOC41), Sets.newHashSet(HOST_IP11), false);
+
+        // Add a dual-homed host with one location
+        // Expect: the pair link is utilized temporarily before the second location is discovered
+        hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, host1));
+        assertEquals(2, ROUTING_TABLE.size());
+        assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(P9, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(2, BRIDGING_TABLE.size());
+        assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+        assertEquals(P9, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+
+        // Add the second location of dual-homed host
+        // Expect: no longer use the pair link
+        hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
+        assertEquals(2, ROUTING_TABLE.size());
+        assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV3, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV4, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(2, BRIDGING_TABLE.size());
+        assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV3, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+        assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV4, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+    }
+
+    @Test
     public void testHostRemoved() throws Exception {
         Host subject = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
                 Sets.newHashSet(HOST_LOC11), Sets.newHashSet(HOST_IP11), false);
diff --git a/cli/src/main/java/org/onosproject/cli/SummaryCommand.java b/cli/src/main/java/org/onosproject/cli/SummaryCommand.java
index 0d2fe51..51a2fc3 100644
--- a/cli/src/main/java/org/onosproject/cli/SummaryCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/SummaryCommand.java
@@ -18,6 +18,7 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.packet.IpAddress;
+import org.onosproject.cluster.ClusterMetadataService;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.core.CoreService;
@@ -64,11 +65,13 @@
         int numScc = get(TopologyService.class).currentTopology().clusterCount();
         int numFlows = get(FlowRuleService.class).getFlowRuleCount();
         long numIntents = get(IntentService.class).getIntentCount();
+        String clusterId = get(ClusterMetadataService.class).getClusterMetadata().getName();
 
         if (outputJson()) {
             print("%s", new ObjectMapper().createObjectNode()
                     .put("node", nodeIp.toString())
                     .put("version", version.toString())
+                    .put("clusterId", clusterId)
                     .put("nodes", numNodes)
                     .put("devices", numDevices)
                     .put("links", numLinks)
@@ -77,7 +80,7 @@
                     .put("flows", numFlows)
                     .put("intents", numIntents));
         } else {
-            print("node=%s, version=%s", nodeIp, version);
+            print("node=%s, version=%s clusterId=%s", nodeIp, version, clusterId);
             print("nodes=%d, devices=%d, links=%d, hosts=%d, SCC(s)=%s, flows=%d, intents=%d",
                   numNodes, numDevices, numLinks, numHosts, numScc, numFlows, numIntents);
         }
diff --git a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
index 16e7c1a..2aa631f 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java
@@ -160,7 +160,7 @@
     private void printPortStatsDeltaTable(DeviceId deviceId, Iterable<PortStatistics> portStats) {
         final String formatDeltaTable = "|%5s | %7s | %7s |  %7s | %7s | %7s | %7s |  %7s | %7s |%9s |";
         print("+---------------------------------------------------------------------------------------------------+");
-        print("| DeviceId = %s                                                                    |", deviceId);
+        print("| DeviceId = %-86s |", deviceId);
         print("|---------------------------------------------------------------------------------------------------|");
         print("|      | Receive                                | Transmit                               | Time [s] |");
         print("| Port | Packets |  Bytes  | Rate bps |   Drop  | Packets |  Bytes  | Rate bps |   Drop  | Interval |");
@@ -175,8 +175,8 @@
             }
             float duration = ((float) stat.durationSec()) +
                     (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1));
-            float rateRx = stat.bytesReceived() * 8 / duration;
-            float rateTx = stat.bytesSent() * 8 / duration;
+            float rateRx = duration > 0 ? stat.bytesReceived() * 8 / duration : 0;
+            float rateTx = duration > 0 ? stat.bytesSent() * 8 / duration : 0;
             print(formatDeltaTable, stat.port(),
                   humanReadable(stat.packetsReceived()),
                   humanReadable(stat.bytesReceived()),
diff --git a/core/api/src/main/java/org/onosproject/net/group/GroupProgrammable.java b/core/api/src/main/java/org/onosproject/net/group/GroupProgrammable.java
index 178a288..5be93d2 100644
--- a/core/api/src/main/java/org/onosproject/net/group/GroupProgrammable.java
+++ b/core/api/src/main/java/org/onosproject/net/group/GroupProgrammable.java
@@ -16,9 +16,12 @@
 
 package org.onosproject.net.group;
 
+import com.google.common.collect.ImmutableList;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.HandlerBehaviour;
 
+import java.util.Collection;
+
 /**
  * Group programmable device behaviour.
  */
@@ -31,4 +34,13 @@
      * @param groupOps operations to be performed
      */
     void performGroupOperation(DeviceId deviceId, GroupOperations groupOps);
+
+    /**
+     * Queries the groups from the device.
+     *
+     * @return collection of groups
+     */
+    default Collection<Group> getGroups() {
+        return ImmutableList.of();
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java b/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
index 0ef9aef..0198444 100644
--- a/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
+++ b/core/api/src/main/java/org/onosproject/store/service/DocumentPath.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.store.service;
 
+import com.google.common.collect.Comparators;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import org.apache.commons.collections.CollectionUtils;
@@ -24,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -233,19 +235,7 @@
 
     @Override
     public int compareTo(DocumentPath that) {
-        int shorterLength = this.pathElements.size() > that.pathElements.size()
-                ? that.pathElements.size() : this.pathElements.size();
-        for (int i = 0; i < shorterLength; i++) {
-            if (this.pathElements.get(i).compareTo(that.pathElements.get(i)) != 0) {
-                return this.pathElements.get(i).compareTo(that.pathElements.get(i));
-            }
-        }
-        if (this.pathElements.size() > that.pathElements.size()) {
-            return 1;
-        } else if (that.pathElements.size() > this.pathElements.size()) {
-            return -1;
-        } else {
-            return 0;
-        }
+        return Comparators.lexicographical(Comparator.<String>naturalOrder())
+                .compare(this.pathElements, that.pathElements);
     }
 }
diff --git a/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java b/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
index 6e69eb6..c0137c8 100644
--- a/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
+++ b/core/api/src/test/java/org/onosproject/store/service/DocumentPathTest.java
@@ -16,8 +16,13 @@
 
 package org.onosproject.store.service;
 
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
@@ -73,10 +78,10 @@
         DocumentPath one = path("root");
         DocumentPath four = path("root.a.b.c.d");
         DocumentPath difFour = path("root.e.c.b.a");
-        assertEquals(-1, one.compareTo(four));
-        assertEquals(1, four.compareTo(one));
-        assertEquals(4, difFour.compareTo(four));
-        assertEquals(0, difFour.compareTo(difFour));
+        assertThat(one.compareTo(four), is(lessThan(0)));
+        assertThat(four.compareTo(one), is(greaterThan(0)));
+        assertThat(difFour.compareTo(four), is(greaterThan(0)));
+        assertThat(difFour.compareTo(difFour), is(equalTo(0)));
     }
 
     private static DocumentPath exceptions(String nodeName, DocumentPath path) {
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupDriverProvider.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupDriverProvider.java
index 414d9e2..6eea583 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupDriverProvider.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupDriverProvider.java
@@ -16,17 +16,34 @@
 
 package org.onosproject.net.group.impl;
 
+import com.google.common.collect.Sets;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.group.Group;
 import org.onosproject.net.group.GroupOperations;
 import org.onosproject.net.group.GroupProgrammable;
 import org.onosproject.net.group.GroupProvider;
+import org.onosproject.net.group.GroupProviderService;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
+import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
+
 /**
  * Driver-based Group rule provider.
  */
@@ -37,19 +54,49 @@
     // To be extracted for reuse as we deal with other.
     private static final String SCHEME = "default";
     private static final String PROVIDER_NAME = "org.onosproject.provider";
+
+    // potentially positive device event
+    private static final Set<DeviceEvent.Type> POSITIVE_DEVICE_EVENT =
+            Sets.immutableEnumSet(DEVICE_ADDED,
+                    DEVICE_AVAILABILITY_CHANGED);
+
     protected DeviceService deviceService;
+    protected GroupProviderService groupProviderService;
+    protected MastershipService mastershipService;
+
+    private InternalDeviceListener deviceListener = new InternalDeviceListener();
+    private ScheduledExecutorService executor
+            = newSingleThreadScheduledExecutor(groupedThreads("GroupDriverProvider", "%d", log));
+    private ScheduledFuture<?> poller = null;
 
     public GroupDriverProvider() {
         super(new ProviderId(SCHEME, PROVIDER_NAME));
     }
 
     /**
-     * Initializes the provider with the necessary device service.
+     * Initializes the provider with the necessary device service, group provider service,
+     * mastership service and poll frequency.
      *
-     * @param deviceService device service
+     * @param deviceService        device service
+     * @param groupProviderService group provider service
+     * @param mastershipService    mastership service
+     * @param pollFrequency        group entry poll frequency
      */
-    void init(DeviceService deviceService) {
+    void init(DeviceService deviceService, GroupProviderService groupProviderService,
+              MastershipService mastershipService, int pollFrequency) {
         this.deviceService = deviceService;
+        this.groupProviderService = groupProviderService;
+        this.mastershipService = mastershipService;
+
+        deviceService.addListener(deviceListener);
+
+        if (poller != null && !poller.isCancelled()) {
+            poller.cancel(false);
+        }
+
+        poller = executor.scheduleAtFixedRate(this::pollGroups, pollFrequency,
+                pollFrequency, TimeUnit.SECONDS);
+
     }
 
     @Override
@@ -60,6 +107,20 @@
         }
     }
 
+    private void pollGroups() {
+        deviceService.getAvailableDevices().forEach(device -> {
+            if (mastershipService.isLocalMaster(device.id()) &&
+                    device.is(GroupProgrammable.class)) {
+                pollDeviceGroups(device.id());
+            }
+        });
+    }
+
+    private void pollDeviceGroups(DeviceId deviceId) {
+        Collection<Group> groups = getGroupProgrammable(deviceId).getGroups();
+        groupProviderService.pushGroupMetrics(deviceId, groups);
+    }
+
     private GroupProgrammable getGroupProgrammable(DeviceId deviceId) {
         Device device = deviceService.getDevice(deviceId);
         if (device.is(GroupProgrammable.class)) {
@@ -69,4 +130,29 @@
             return null;
         }
     }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            executor.execute(() -> handleEvent(event));
+        }
+
+        @Override
+        public boolean isRelevant(DeviceEvent event) {
+            Device device = event.subject();
+            return POSITIVE_DEVICE_EVENT.contains(event.type()) &&
+                    device.is(GroupProgrammable.class);
+        }
+
+        private void handleEvent(DeviceEvent event) {
+            Device device = event.subject();
+            boolean isRelevant = mastershipService.isLocalMaster(device.id()) &&
+                    deviceService.isAvailable(device.id());
+
+            if (isRelevant) {
+                pollDeviceGroups(device.id());
+            }
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
index 31e95a4..bc3c64d 100644
--- a/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
+++ b/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java
@@ -26,6 +26,7 @@
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
+import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
@@ -54,6 +55,8 @@
 import java.util.Collections;
 import java.util.Dictionary;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
 import static org.onosproject.security.AppGuard.checkPermission;
 import static org.onosproject.security.AppPermission.Type.GROUP_READ;
 import static org.onosproject.security.AppPermission.Type.GROUP_WRITE;
@@ -76,6 +79,8 @@
     private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
     private final DeviceListener deviceListener = new InternalDeviceListener();
 
+    private final  GroupDriverProvider defaultProvider = new GroupDriverProvider();
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected GroupStore store;
 
@@ -85,10 +90,18 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService cfgService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected MastershipService mastershipService;
+
+    private static final int DEFAULT_POLL_FREQUENCY = 30;
+    @Property(name = "fallbackGroupPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
+            label = "Frequency (in seconds) for polling groups via fallback provider")
+    private int fallbackGroupPollFrequency = DEFAULT_POLL_FREQUENCY;
+
     @Property(name = "purgeOnDisconnection", boolValue = false,
             label = "Purge entries associated with a device when the device goes offline")
     private boolean purgeOnDisconnection = false;
-    private final  GroupDriverProvider defaultProvider = new GroupDriverProvider();
+
 
     @Activate
     public void activate(ComponentContext context) {
@@ -114,7 +127,8 @@
         if (context != null) {
             readComponentConfiguration(context);
         }
-        defaultProvider.init(deviceService);
+        defaultProvider.init(deviceService, new InternalGroupProviderService(defaultProvider),
+                mastershipService, fallbackGroupPollFrequency);
     }
 
     @Override
@@ -140,6 +154,12 @@
             log.info("Configured. PurgeOnDisconnection is {}",
                     purgeOnDisconnection ? "enabled" : "disabled");
         }
+        String s = get(properties, "fallbackGroupPollFrequency");
+        try {
+            fallbackGroupPollFrequency = isNullOrEmpty(s) ? DEFAULT_POLL_FREQUENCY : Integer.parseInt(s);
+        } catch (NumberFormatException e) {
+            fallbackGroupPollFrequency = DEFAULT_POLL_FREQUENCY;
+        }
     }
 
     /**
diff --git a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
index 2415eea..7135c49 100644
--- a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -21,6 +21,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.junit.TestTools;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onosproject.cfg.ComponentConfigAdapter;
@@ -28,11 +29,13 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.GroupId;
+import org.onosproject.mastership.MastershipServiceAdapter;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
@@ -67,6 +70,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -89,7 +93,7 @@
     private static final Device FOO_DEV =
             new DefaultDevice(FOO_PID, FOO_DID, Device.Type.SWITCH, "", "", "", "", null, ANNOTATIONS);
 
-    private GroupManager mgr;
+    private static GroupManager mgr;
     private GroupService groupService;
     private GroupProviderRegistry providerRegistry;
     private TestGroupListener internalListener = new TestGroupListener();
@@ -108,6 +112,7 @@
         mgr.deviceService = new TestDeviceService();
         mgr.cfgService = new ComponentConfigAdapter();
         mgr.store = new SimpleGroupStore();
+        mgr.mastershipService = new TestMastershipService();
         injectEventDispatcher(mgr, new TestEventDispatcher());
         providerRegistry = mgr;
 
@@ -302,6 +307,27 @@
         testRemoveGroup(FOO_DID);
     }
 
+    @Test
+    public void fallbackPoll() {
+        // Test Group creation before AUDIT process
+        testGroupCreationBeforeAudit(FOO_DID);
+        programmableTestCleanUp();
+
+        // Test audit with extraneous and missing groups
+        testAuditWithExtraneousMissingGroups(FOO_DID);
+
+        // Test audit with confirmed groups
+        Group createdGroup = testAuditWithConfirmedGroups(FOO_DID);
+        GroupDriverProvider fallback = (GroupDriverProvider) mgr.defaultProvider();
+
+        fallback.init(mgr.deviceService, fallback.groupProviderService, mgr.mastershipService, 1);
+
+        TestTools.assertAfter(2000, () -> {
+            Group e = mgr.getGroups(FOO_DID).iterator().next();
+            assertEquals("incorrect group", createdGroup, e);
+        });
+    }
+
     private void programmableTestCleanUp() {
         groupOperations.clear();
         lastDeviceIdProgrammable = null;
@@ -414,7 +440,7 @@
     }
 
     // Test AUDIT with confirmed groups
-    private void testAuditWithConfirmedGroups(DeviceId deviceId) {
+    private Group testAuditWithConfirmedGroups(DeviceId deviceId) {
         GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
         Group createdGroup = groupService.getGroup(deviceId, key);
         createdGroup = new DefaultGroup(createdGroup.id(),
@@ -424,6 +450,7 @@
         List<Group> groupEntries = Collections.singletonList(createdGroup);
         providerService.pushGroupMetrics(deviceId, groupEntries);
         internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADDED));
+        return createdGroup;
     }
 
     // Test group add bucket operations
@@ -649,7 +676,7 @@
         internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED));
     }
 
-    private Group createSouthboundGroupEntry(GroupId gId,
+    private static Group createSouthboundGroupEntry(GroupId gId,
                                              List<PortNumber> ports,
                                              long referenceCount, DeviceId deviceId) {
         List<PortNumber> outPorts = new ArrayList<>();
@@ -749,6 +776,13 @@
         }
     }
 
+    private class TestMastershipService extends MastershipServiceAdapter {
+        @Override
+        public MastershipRole getLocalRole(DeviceId deviceId) {
+            return MastershipRole.MASTER;
+        }
+    }
+
     private class TestDriverManager extends DriverManager {
         TestDriverManager(DriverRegistry registry) {
             this.registry = registry;
@@ -766,6 +800,11 @@
             lastDeviceIdProgrammable = deviceId;
             groupOperations.addAll(groupOps.operations());
         }
+
+        @Override
+        public Collection<Group> getGroups() {
+            return ImmutableList.of(mgr.getGroups(FOO_DID).iterator().next());
+        }
     }
 
     public void validate(DeviceId expectedDeviceId,
@@ -783,5 +822,3 @@
         lastDeviceIdProgrammable = null;
     }
 }
-
-
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
index 9a90999..b7e121b 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
@@ -105,7 +105,7 @@
 public class NettyMessagingManager implements MessagingService {
     private static final long DEFAULT_TIMEOUT_MILLIS = 500;
     private static final long HISTORY_EXPIRE_MILLIS = Duration.ofMinutes(1).toMillis();
-    private static final long MIN_TIMEOUT_MILLIS = 100;
+    private static final long MIN_TIMEOUT_MILLIS = 250;
     private static final long MAX_TIMEOUT_MILLIS = 5000;
     private static final long TIMEOUT_INTERVAL = 50;
     private static final int WINDOW_SIZE = 100;
diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/DistributedFlowRuleStore.java b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/DistributedFlowRuleStore.java
index 3382abe..e2d485f 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/DistributedFlowRuleStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/DistributedFlowRuleStore.java
@@ -78,6 +78,7 @@
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapEvent;
 import org.onosproject.store.service.EventuallyConsistentMapListener;
+import org.onosproject.store.service.IllegalDocumentModificationException;
 import org.onosproject.store.service.NoSuchDocumentPathException;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageException;
@@ -661,18 +662,26 @@
     @Override
     public void purgeFlowRule(DeviceId deviceId) {
         DocumentPath path = getPathFor(deviceId);
-        try {
-            for (String flowId : flows.getChildren(path).keySet()) {
-                flows.removeNode(DocumentPath.from("root", deviceId.toString(), flowId));
+        retryUntilSuccess(() -> {
+            try {
+                for (String flowId : flows.getChildren(path).keySet()) {
+                    flows.removeNode(DocumentPath.from("root", deviceId.toString(), flowId));
+                }
+            } catch (NoSuchDocumentPathException e) {
+                // Do nothing. There are no flows for the device.
             }
-        } catch (NoSuchDocumentPathException e) {
-            // Do nothing
-        }
-        try {
-            flows.removeNode(path);
-        } catch (NoSuchDocumentPathException e) {
-            // Do nothing
-        }
+
+            // New children may have been created since they were removed above. Catch
+            // IllegalDocumentModificationException and retry if necessary.
+            try {
+                flows.removeNode(path);
+            } catch (NoSuchDocumentPathException e) {
+                return null;
+            } catch (IllegalDocumentModificationException e) {
+                return retry();
+            }
+            return null;
+        });
     }
 
     @Override
@@ -682,7 +691,7 @@
                 purgeFlowRule(DeviceId.deviceId(deviceId));
             }
         } catch (NoSuchDocumentPathException e) {
-            // Do nothing
+            // Do nothing if no children exist.
         }
     }
 
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 b5dcc76..5f59921 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
@@ -108,7 +108,7 @@
     private Consumer<Status> statusChangeListener;
 
     // TODO make this configurable
-    private static final int PROBE_TIMEOUT_MS = 1000;
+    private static final int PROBE_TIMEOUT_MS = 1500;
 
     private Cache<MacAddress, PendingHostLocation> pendingHostsCache = CacheBuilder.newBuilder()
             .expireAfterWrite(PROBE_TIMEOUT_MS, TimeUnit.MILLISECONDS)
@@ -117,8 +117,9 @@
                     case EXPIRED:
                         PendingHostLocation expired = notification.getValue();
                         if (expired != null) {
-                            log.info("Evict timeout probe {} from pendingHostLocations", notification.getValue());
-                            timeoutPendingHostLocation(notification.getKey());
+                            if (timeoutPendingHostLocation(notification.getKey())) {
+                                log.info("Evict {} from pendingHosts due to probe timeout", notification.getValue());
+                            }
                         }
                         break;
                     case EXPLICIT:
@@ -401,11 +402,12 @@
         pendingHosts.remove(probeMac);
     }
 
-    private void timeoutPendingHostLocation(MacAddress probeMac) {
-        pendingHosts.computeIfPresent(probeMac, (k, v) -> {
+    private boolean timeoutPendingHostLocation(MacAddress probeMac) {
+        PendingHostLocation phl = pendingHosts.computeIfPresent(probeMac, (k, v) -> {
             v.setExpired(true);
             return v;
         });
+        return phl != null;
     }
 
     private Set<Host> filter(Collection<DefaultHost> collection, Predicate<DefaultHost> predicate) {
diff --git a/core/store/primitives/pom.xml b/core/store/primitives/pom.xml
index 544be38..88f30a5 100644
--- a/core/store/primitives/pom.xml
+++ b/core/store/primitives/pom.xml
@@ -70,7 +70,7 @@
         <dependency>
             <groupId>io.atomix</groupId>
             <artifactId>atomix</artifactId>
-            <version>2.0.0</version>
+            <version>2.0.2</version>
         </dependency>
 
         <dependency>
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
index 6028685..36b854f 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StoragePartitionServer.java
@@ -16,6 +16,7 @@
 package org.onosproject.store.primitives.impl;
 
 import java.io.File;
+import java.time.Duration;
 import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Supplier;
@@ -41,6 +42,9 @@
 
     private static final int MAX_ENTRIES_PER_LOG_SEGMENT = 32768;
     private static final int MAX_SEGMENT_SIZE = 1024 * 1024 * 64;
+    private static final long ELECTION_TIMEOUT_MILLIS = 2500;
+    private static final long HEARTBEAT_INTERVAL_MILLIS = 1000;
+
     private final MemberId localMemberId;
     private final StoragePartition partition;
     private final Supplier<RaftServerProtocol> protocol;
@@ -98,8 +102,10 @@
         RaftServer.Builder builder = RaftServer.newBuilder(localMemberId)
                 .withName("partition-" + partition.getId())
                 .withProtocol(protocol.get())
+                .withElectionTimeout(Duration.ofMillis(ELECTION_TIMEOUT_MILLIS))
+                .withHeartbeatInterval(Duration.ofMillis(HEARTBEAT_INTERVAL_MILLIS))
                 .withStorage(RaftStorage.newBuilder()
-                        .withStorageLevel(StorageLevel.DISK)
+                        .withStorageLevel(StorageLevel.MAPPED)
                         .withSerializer(new AtomixSerializerAdapter(Serializer.using(StorageNamespaces.RAFT_STORAGE)))
                         .withDirectory(dataFolder)
                         .withMaxEntriesPerSegment(MAX_ENTRIES_PER_LOG_SEGMENT)
diff --git a/drivers/optical/src/main/resources/optical-drivers.xml b/drivers/optical/src/main/resources/optical-drivers.xml
index bb4638a..a83441d 100644
--- a/drivers/optical/src/main/resources/optical-drivers.xml
+++ b/drivers/optical/src/main/resources/optical-drivers.xml
@@ -94,7 +94,7 @@
     </driver>
 
     <driver name="polatis" extends="default"
-            manufacturer="Polatis" hwVersion="N-VST-48x48-HU1-DMHNV-805" swVersion="6.6.1.7">
+            manufacturer="Polatis" hwVersion=".*" swVersion=".*">
         <behaviour api="org.onosproject.net.optical.OpticalDevice"
                    impl="org.onosproject.net.optical.DefaultOpticalDevice"/>
         <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
diff --git a/features/features.xml b/features/features.xml
index c95b3a9..e920ab0 100644
--- a/features/features.xml
+++ b/features/features.xml
@@ -59,7 +59,7 @@
         <bundle>mvn:com.typesafe/config/1.2.1</bundle>
         <bundle>mvn:com.googlecode.concurrent-trees/concurrent-trees/2.6.0</bundle>
         <bundle>mvn:commons-io/commons-io/2.4</bundle>
-        <bundle>mvn:io.atomix/atomix/2.0.0</bundle>
+        <bundle>mvn:io.atomix/atomix/2.0.2</bundle>
 
         <bundle>mvn:org.glassfish.jersey.core/jersey-client/2.25.1</bundle>
 
diff --git a/lib/BUCK b/lib/BUCK
index 1ca9fbb..b4eed7b 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Sun, 3 Sep 2017 12:12:12 GMT. Do not edit this file manually. *****
+# ***** This file was auto-generated at Wed, 13 Sep 2017 22:16:27 GMT. Do not edit this file manually. *****
 # ***** Use onos-lib-gen *****
 
 pass_thru_pom(
@@ -208,10 +208,10 @@
 
 remote_jar (
   name = 'atomix',
-  out = 'atomix-2.0.0.jar',
-  url = 'mvn:io.atomix:atomix:jar:2.0.0',
-  sha1 = '44b1271a4a77d9831b000f2eedf52587969ae9fb',
-  maven_coords = 'io.atomix:atomix:2.0.0',
+  out = 'atomix-2.0.2.jar',
+  url = 'mvn:io.atomix:atomix:jar:2.0.2',
+  sha1 = '9b3b05af6337c35bc69922fb7b535c78f07a5f5b',
+  maven_coords = 'io.atomix:atomix:2.0.2',
   visibility = [ 'PUBLIC' ],
 )
 
@@ -1268,55 +1268,55 @@
 
 remote_jar (
   name = 'onos-yang-model',
-  out = 'onos-yang-model-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-model:jar:2.2.0-b6',
-  sha1 = 'a84fe63b3244e5e919a378d8c09aff5462130bf1',
-  maven_coords = 'org.onosproject:onos-yang-model:2.2.0-b6',
+  out = 'onos-yang-model-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-model:jar:2.2.0',
+  sha1 = 'bead6c7c27a326c0701f4572e70dbbef1ad407ce',
+  maven_coords = 'org.onosproject:onos-yang-model:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-compiler-api',
-  out = 'onos-yang-compiler-api-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.2.0-b6',
-  sha1 = '9f6151b00b98cff6d41f123b3198b4c5a12007c6',
-  maven_coords = 'org.onosproject:onos-yang-compiler-api:2.2.0-b6',
+  out = 'onos-yang-compiler-api-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-compiler-api:jar:2.2.0',
+  sha1 = 'cb58fc09248a79ca90607a233d9bb8a8a73eaac8',
+  maven_coords = 'org.onosproject:onos-yang-compiler-api:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-runtime',
-  out = 'onos-yang-runtime-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.2.0-b6',
-  sha1 = '41d0382fb1d43cf380b47f081f0007596ae85a55',
-  maven_coords = 'org.onosproject:onos-yang-runtime:2.2.0-b6',
+  out = 'onos-yang-runtime-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-runtime:jar:2.2.0',
+  sha1 = '314698bbb8e7a412c59688e2dddebd0499fcc164',
+  maven_coords = 'org.onosproject:onos-yang-runtime:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-json',
-  out = 'onos-yang-serializers-json-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.2.0-b6',
-  sha1 = '644ad68650897fb08a683541684d1f6e4c531551',
-  maven_coords = 'org.onosproject:onos-yang-serializers-json:2.2.0-b6',
+  out = 'onos-yang-serializers-json-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-json:jar:2.2.0',
+  sha1 = '517bbe15286ef530025938beb74c87b55244ec94',
+  maven_coords = 'org.onosproject:onos-yang-serializers-json:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-xml',
-  out = 'onos-yang-serializers-xml-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.2.0-b6',
-  sha1 = '569a2cc659f84e8c52b5ef66cd028483cd677846',
-  maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.2.0-b6',
+  out = 'onos-yang-serializers-xml-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-xml:jar:2.2.0',
+  sha1 = '2114dcd5aa31b442a2115c0a18522f19a5fbbf0c',
+  maven_coords = 'org.onosproject:onos-yang-serializers-xml:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
 remote_jar (
   name = 'onos-yang-serializers-utils',
-  out = 'onos-yang-serializers-utils-2.2.0-b6.jar',
-  url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.2.0-b6',
-  sha1 = '38cadd39f1474c86726aa6f2d54991d2f4f60637',
-  maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.2.0-b6',
+  out = 'onos-yang-serializers-utils-2.2.0.jar',
+  url = 'mvn:org.onosproject:onos-yang-serializers-utils:jar:2.2.0',
+  sha1 = '144cce2a54e5177393736e896c612380e573745f',
+  maven_coords = 'org.onosproject:onos-yang-serializers-utils:2.2.0',
   visibility = [ 'PUBLIC' ],
 )
 
diff --git a/lib/deps.json b/lib/deps.json
index 7ed72bc..5a9124c 100644
--- a/lib/deps.json
+++ b/lib/deps.json
@@ -118,7 +118,7 @@
     "aopalliance-repackaged": "mvn:org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b32",
     "amqp-client": "mvn:com.rabbitmq:amqp-client:jar:3.6.1",
     "asm": "mvn:org.ow2.asm:asm:5.0.4",
-    "atomix": "mvn:io.atomix:atomix:2.0.0",
+    "atomix": "mvn:io.atomix:atomix:2.0.2",
     "commons-codec": "mvn:commons-codec:commons-codec:1.10",
     "commons-collections": "mvn:commons-collections:commons-collections:3.2.2",
     "commons-configuration": "mvn:commons-configuration:commons-configuration:1.10",
@@ -242,12 +242,12 @@
     "onos-yang-maven-plugin": "mvn:org.onosproject:onos-yang-maven-plugin:1.11",
     "onos-yang-utils-generator": "mvn:org.onosproject:onos-yang-utils-generator:1.11",
     // Note: update BVER in tools/dev/bin/patch-yang-libs
-    "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.2.0-b6",
-    "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.2.0-b6",
-    "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.2.0-b6",
-    "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.2.0-b6",
-    "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.2.0-b6",
-    "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.2.0-b6",
+    "onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.2.0",
+    "onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.2.0",
+    "onos-yang-runtime":"mvn:org.onosproject:onos-yang-runtime:2.2.0",
+    "onos-yang-serializers-json":"mvn:org.onosproject:onos-yang-serializers-json:2.2.0",
+    "onos-yang-serializers-xml":"mvn:org.onosproject:onos-yang-serializers-xml:2.2.0",
+    "onos-yang-serializers-utils":"mvn:org.onosproject:onos-yang-serializers-utils:2.2.0",
     "org.apache.servicemix.bundles.dom4j":"mvn:org.apache.servicemix.bundles:org.apache.servicemix.bundles.dom4j:1.6.1_5",
     "plexus-utils": "mvn:org.codehaus.plexus:plexus-utils:3.0.24",
     "sshd-core": "mvn:org.apache.sshd:sshd-core:1.4.0",
diff --git a/lib/pom.xml b/lib/pom.xml
index 55eea9a..07ef09b 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -40,7 +40,7 @@
         <netty4.version>4.1.8.Final</netty4.version>
         <openflowj.version>3.2.0.onos</openflowj.version>
         <onos-maven-plugin.version>1.10</onos-maven-plugin.version>
-        <onos-yang-tools.version>2.2.0-b6</onos-yang-tools.version>
+        <onos-yang-tools.version>2.2.0</onos-yang-tools.version>
         <osgi.version>5.0.0</osgi.version>
         <karaf.version>3.0.8</karaf.version>
         <jersey.version>2.25.1</jersey.version>
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 a0d6e37..227415e 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
@@ -90,6 +90,9 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 import java.util.Set;
 
@@ -447,7 +450,10 @@
                                 IPv6.getMCastMacAddress(ip.getIp6Address().toOctets()),
                                 host.id().vlanId());
                     }
-                    sendProbe(probe, location);
+
+                    // NOTE: delay the probe a little bit to wait for the store synchronization is done
+                    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+                    executorService.schedule(() -> sendProbe(probe, location), 1000, TimeUnit.MILLISECONDS);
                 });
             });
         }
diff --git a/tools/build/onos-buck b/tools/build/onos-buck
index 9ed162b..7d4b174 100755
--- a/tools/build/onos-buck
+++ b/tools/build/onos-buck
@@ -5,8 +5,8 @@
 
 set -e
 
-BUCK_URL="http://onlab.vicci.org/onos/third-party/buck-v2017.08.24.01.zip"
-BUCK_SHA="3b8dcb39f8ece99db3b4e77815b1ddf05e04d77a"
+BUCK_URL="http://onlab.vicci.org/onos/third-party/buck-v2017.09.01.01.zip"
+BUCK_SHA="9addcfd68518ee51b8f08135a7828b38dffb8fe5"
 
 [  "-U" = "$1" ] && shift && FORCE_UPDATE=True
 
diff --git a/tools/dev/bin/patch-yang-libs b/tools/dev/bin/patch-yang-libs
index 89ebeb6..0522d9e 100755
--- a/tools/dev/bin/patch-yang-libs
+++ b/tools/dev/bin/patch-yang-libs
@@ -3,8 +3,8 @@
 # Patches lib/BUCK file to use locally built YANG tools.
 # -----------------------------------------------------------------------------
 
-BVER=2.2.0-b6
-SVER=2.2-SNAPSHOT
+BVER=2.2.0
+SVER=2.3-SNAPSHOT
 
 YANG_TOOLS_ROOT=${YANG_TOOLS_ROOT:-~/onos-yang-tools}
 
diff --git a/tools/package/init/onos.conf b/tools/package/init/onos.conf
index d130afe..b8caab6 100644
--- a/tools/package/init/onos.conf
+++ b/tools/package/init/onos.conf
@@ -1,5 +1,5 @@
 description  "Open Network Operating System"
-author       "ON.Lab"
+author       "Open Networking Foundation"
 
 # onos.conf: ONOS service configuration for upstart-based systems
 
@@ -22,7 +22,7 @@
     mkdir -p /opt/onos/var 2>/dev/null && chown $ONOS_USER:$ONOS_GROUP /opt/onos/var
     mkdir -p /opt/onos/config 2>/dev/null && chown $ONOS_USER:$ONOS_GROUP /opt/onos/config
     mkdir -p /opt/onos/apps 2>/dev/null && chown -R $ONOS_USER:$ONOS_GROUP /opt/onos/apps
-    [ ! -h $ONOS_OME/karaf ] && ln -s /opt/onos/apache-karaf* $ONOS_HOME/karaf || :
+    [ ! -h $ONOS_HOME/karaf ] && ln -s /opt/onos/apache-karaf* $ONOS_HOME/karaf || :
     [ ! -h $ONOS_HOME/log ]  && ln -s $ONOS_HOME/karaf/data/log $ONOS_HOME/log || :
 end script
 
diff --git a/tools/test/bin/onos b/tools/test/bin/onos
index 44ba393..c74ebc6 100755
--- a/tools/test/bin/onos
+++ b/tools/test/bin/onos
@@ -34,4 +34,4 @@
 
 [ -n "$1" ] && OCI=$(find_node $1) && shift
 
-ssh -p 8101 -o StrictHostKeyChecking=no $OCI "$@"
+ssh -q -p 8101 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $OCI "$@"
diff --git a/tools/test/bin/onos-all b/tools/test/bin/onos-all
index 6d5617d..e7d8031 100755
--- a/tools/test/bin/onos-all
+++ b/tools/test/bin/onos-all
@@ -24,5 +24,5 @@
 
 for node in $nodes; do
   echo "Issuing command on $node.."
-  ssh -p 8101 -o StrictHostKeyChecking=no $node "$@"
+  ssh -q -p 8101 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $node "$@"
 done
diff --git a/tools/test/bin/onos-secure-ssh b/tools/test/bin/onos-secure-ssh
index cd9f12c..9bd8881 100755
--- a/tools/test/bin/onos-secure-ssh
+++ b/tools/test/bin/onos-secure-ssh
@@ -23,10 +23,6 @@
 (umask 077; touch "$HOME/.ssh/known_hosts")
 
 for node in $nodes; do
-    # Prune the node entry from the known hosts file since server key changes
-    ssh-keygen -f "$HOME/.ssh/known_hosts" -R [$node]:8101 ||
-        ( echo "Failed to remove key from known_hosts" >&2 && exit 1 )
-
     # Setup passwordless login for the local user on the remote node
     ssh $ONOS_USER@$node "
         [ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' -q
diff --git a/web/gui/onos-gui-build b/web/gui/onos-gui-build
index b0bb79f..0b43815 100755
--- a/web/gui/onos-gui-build
+++ b/web/gui/onos-gui-build
@@ -10,6 +10,7 @@
 cd $ONOS_ROOT/tools/gui
 
 # Ensure lock file is removed
+rm -rf node_modules
 rm -f package-lock.json
 
 # Install Project Dependencies
@@ -19,4 +20,4 @@
 
 # Build the GUI Project
 echo "Packaging JavaScript and CSS"
-npm run build
\ No newline at end of file
+npm run build