Send probes when host moves

Majorly for the 2nd step of [1A/x, 1B/x] -> [1A/x, 1B/y] -> [1A/y, 1B/y]
But will also cover [1A/x] -> [1A/y] -> [1A/y, 1B/y]

When receiving probe for 1A/y in [1A/x, 1B/y] state, simply replace 1A/x with 1A/y instead of creating a transient 3rd locaiton

Change-Id: I058a265bbe5019d4305aa09d70e095fec0d7e429
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index fecdd30..f71c1d0 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -46,7 +46,6 @@
  */
 public class HostHandler {
     private static final Logger log = LoggerFactory.getLogger(HostHandler.class);
-    static final int HOST_MOVED_DELAY_MS = 1000;
 
     protected final SegmentRoutingManager srManager;
     private HostService hostService;
@@ -170,20 +169,16 @@
     }
 
     void processHostMovedEvent(HostEvent event) {
-        Set<HostLocation> prevLocations = event.prevSubject().locations();
-        Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
-        Set<HostLocation> newLocations = event.subject().locations();
-        Set<IpAddress> newIps = event.subject().ipAddresses();
-
-        processHostMoved(event.subject(), prevLocations, prevIps, newLocations, newIps);
-    }
-
-    private void processHostMoved(Host host, Set<HostLocation> prevLocations, Set<IpAddress> prevIps,
-                                  Set<HostLocation> newLocations, Set<IpAddress> newIps) {
+        Host host = event.subject();
         MacAddress hostMac = host.mac();
         VlanId hostVlanId = host.vlan();
+        Set<HostLocation> prevLocations = event.prevSubject().locations();
+        Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
+        Set<HostLocation> newLocations = host.locations();
+        Set<IpAddress> newIps = host.ipAddresses();
         EthType hostTpid = host.tpid();
         boolean doubleTaggedHost = isDoubleTaggedHost(host);
+
         log.info("Host {}/{} is moved from {} to {}", hostMac, hostVlanId, prevLocations, newLocations);
         Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId)
                 .collect(Collectors.toSet());
@@ -275,6 +270,17 @@
                                        ip, false);
                 }
             });
+
+            // Probe on pair device when host move
+            // Majorly for the 2nd step of [1A/x, 1B/x] -> [1A/x, 1B/y] -> [1A/y, 1B/y]
+            // But will also cover [1A/x] -> [1A/y] -> [1A/y, 1B/y]
+            if (srManager.activeProbing) {
+                srManager.getPairDeviceId(newLocation.deviceId()).ifPresent(pairDeviceId ->
+                        srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort ->
+                                probe(host, newLocation, pairDeviceId, pairRemotePort)
+                        )
+                );
+            }
         });
 
         // For each unchanged location, add new IPs and remove old IPs.
diff --git a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
index ea44703..26420ac 100644
--- a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
+++ b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/HostHandlerTest.java
@@ -455,6 +455,9 @@
                 Sets.newHashSet(HOST_LOC11, HOST_LOC21), Sets.newHashSet(HOST_IP13, HOST_IP14), false);
         Host host4 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
                 Sets.newHashSet(HOST_LOC11, HOST_LOC22), Sets.newHashSet(HOST_IP12, HOST_IP13), false);
+        Host host5 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC, HOST_VLAN_UNTAGGED,
+                Sets.newHashSet(HOST_LOC12, HOST_LOC21), Sets.newHashSet(HOST_IP11, HOST_IP12), false);
+
 
         // Add a host with IP11, IP12 and LOC11, LOC21
         // Expect: 4 routing rules and 2 bridging rules
@@ -468,9 +471,21 @@
         assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
         assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
 
+        // Move the host to LOC12, LOC21 and keep the IP
+        // Expect: 4 routing rules and 2 bridging rules all at the new location
+        hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host5, host1));
+        assertEquals(4, ROUTING_TABLE.size());
+        assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
+        assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP11.toIpPrefix())).portNumber);
+        assertEquals(P1, ROUTING_TABLE.get(new MockRoutingTableKey(DEV2, HOST_IP12.toIpPrefix())).portNumber);
+        assertEquals(2, BRIDGING_TABLE.size());
+        assertEquals(P2, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+        assertEquals(P1, BRIDGING_TABLE.get(new MockBridgingTableKey(DEV2, HOST_MAC, INTF_VLAN_UNTAGGED)).portNumber);
+
         // Move the host to LOC12, LOC22 and keep the IP
         // Expect: 4 routing rules and 2 bridging rules all at the new location
-        hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host1));
+        hostHandler.processHostMovedEvent(new HostEvent(HostEvent.Type.HOST_MOVED, host2, host5));
         assertEquals(4, ROUTING_TABLE.size());
         assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())).portNumber);
         assertEquals(P2, ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP12.toIpPrefix())).portNumber);
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 b9f7a7d..aa811ba 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
@@ -336,12 +336,15 @@
                 checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()),
                         "Existing and new VLANs differ.");
 
-                Set<HostLocation> locations = new HashSet<>(existingHost.locations());
-                locations.add(location);
+                // Move within the same switch
+                // Simply replace old location that is on the same device
+                Set<HostLocation> newLocations = Sets.newHashSet(location);
+                existingHost.locations().stream().filter(loc -> !loc.deviceId().equals(location.deviceId()))
+                        .forEach(newLocations::add);
 
                 return new DefaultHost(existingHost.providerId(),
                                 hostId, existingHost.mac(), existingHost.vlan(),
-                                locations, existingHost.ipAddresses(),
+                                newLocations, existingHost.ipAddresses(),
                                 existingHost.configured(), existingHost.annotations());
             }
             return null;