Remove next hop location from resolved route

The next hop location should be obtained from host service

Change-Id: I8652e6b8b1367097ffbfcb1651538c34819f67d6
diff --git a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index 2113e71..23bbf07 100644
--- a/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -29,7 +29,6 @@
 import org.onlab.packet.ndp.NeighborSolicitation;
 import org.onosproject.net.neighbour.NeighbourMessageContext;
 import org.onosproject.net.neighbour.NeighbourMessageType;
-import org.onosproject.routeservice.ResolvedRoute;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -165,12 +164,15 @@
         //       The source might be an indirectly attached host (e.g. behind a router)
         //       Lookup the route store for the nexthop instead.
         if (destRouterAddress == null) {
-            Optional<ResolvedRoute> nexthop = srManager.routeService.longestPrefixLookup(destIpAddress);
-            if (nexthop.isPresent()) {
+            Optional<DeviceId> deviceId = srManager.routeService
+                    .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
+                    .flatMap(locations -> locations.stream().findFirst())
+                    .map(ConnectPoint::deviceId);
+            if (deviceId.isPresent()) {
                 try {
-                    destRouterAddress = config.getRouterIpv4(nexthop.get().location().deviceId());
+                    destRouterAddress = config.getRouterIpv4(deviceId.get());
                 } catch (DeviceConfigNotFoundException e) {
-                    log.warn("Device config not found. Abort ICMP processing");
+                    log.warn("Device config for {} not found. Abort ICMP processing", deviceId);
                     return;
                 }
             }
@@ -240,12 +242,15 @@
         //       The source might be an indirect host behind a router.
         //       Lookup the route store for the nexthop instead.
         if (destRouterAddress == null) {
-            Optional<ResolvedRoute> nexthop = srManager.routeService.longestPrefixLookup(destIpAddress);
-            if (nexthop.isPresent()) {
+            Optional<DeviceId> deviceId = srManager.routeService
+                    .longestPrefixLookup(destIpAddress).map(srManager::nextHopLocations)
+                    .flatMap(locations -> locations.stream().findFirst())
+                    .map(ConnectPoint::deviceId);
+            if (deviceId.isPresent()) {
                 try {
-                    destRouterAddress = config.getRouterIpv6(nexthop.get().location().deviceId());
+                    destRouterAddress = config.getRouterIpv6(deviceId.get());
                 } catch (DeviceConfigNotFoundException e) {
-                    log.warn("Device config not found. Abort ICMPv6 processing");
+                    log.warn("Device config for {} not found. Abort ICMPv6 processing", deviceId);
                     return;
                 }
             }
diff --git a/src/main/java/org/onosproject/segmentrouting/RouteHandler.java b/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
index c82b39b..214ba6b 100644
--- a/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
@@ -22,9 +22,9 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.routeservice.ResolvedRoute;
 import org.onosproject.routeservice.RouteEvent;
-import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,22 +38,24 @@
     private static final Logger log = LoggerFactory.getLogger(RouteHandler.class);
     private final SegmentRoutingManager srManager;
 
-    public RouteHandler(SegmentRoutingManager srManager) {
+    RouteHandler(SegmentRoutingManager srManager) {
         this.srManager = srManager;
     }
 
     protected void init(DeviceId deviceId) {
-        srManager.routeService.getRouteTables().forEach(routeTableId -> {
-            srManager.routeService.getRoutes(routeTableId).forEach(routeInfo -> {
-                routeInfo.allRoutes().stream()
-                        .filter(resolvedRoute -> resolvedRoute.location() != null &&
-                                resolvedRoute.location().deviceId().equals(deviceId))
-                        .forEach(this::processRouteAddedInternal);
-            });
-        });
+        srManager.routeService.getRouteTables().forEach(routeTableId ->
+            srManager.routeService.getRoutes(routeTableId).forEach(routeInfo ->
+                routeInfo.allRoutes().forEach(resolvedRoute ->
+                    srManager.nextHopLocations(resolvedRoute).stream()
+                            .filter(location -> deviceId.equals(location.deviceId()))
+                            .forEach(location -> processRouteAddedInternal(resolvedRoute)
+                    )
+                )
+            )
+        );
     }
 
-    protected void processRouteAdded(RouteEvent event) {
+    void processRouteAdded(RouteEvent event) {
         log.info("processRouteAdded {}", event);
         processRouteAddedInternal(event.subject());
     }
@@ -67,7 +69,12 @@
         IpPrefix prefix = route.prefix();
         MacAddress nextHopMac = route.nextHopMac();
         VlanId nextHopVlan = route.nextHopVlan();
-        ConnectPoint location = route.location();
+        ConnectPoint location = srManager.nextHopLocations(route).stream().findFirst().orElse(null);
+
+        if (location == null) {
+            log.info("{} ignored. Cannot find nexthop location", prefix);
+            return;
+        }
 
         srManager.deviceConfiguration.addSubnet(location, prefix);
         // XXX need to handle the case where there are two connectpoints
@@ -77,13 +84,13 @@
                 nextHopMac, nextHopVlan, location.port());
     }
 
-    protected void processRouteUpdated(RouteEvent event) {
+    void processRouteUpdated(RouteEvent event) {
         log.info("processRouteUpdated {}", event);
         processRouteRemovedInternal(event.prevSubject());
         processRouteAddedInternal(event.subject());
     }
 
-    protected void processRouteRemoved(RouteEvent event) {
+    void processRouteRemoved(RouteEvent event) {
         log.info("processRouteRemoved {}", event);
         processRouteRemovedInternal(event.subject());
     }
@@ -97,7 +104,12 @@
         IpPrefix prefix = route.prefix();
         MacAddress nextHopMac = route.nextHopMac();
         VlanId nextHopVlan = route.nextHopVlan();
-        ConnectPoint location = route.location();
+        ConnectPoint location = srManager.nextHopLocations(route).stream().findFirst().orElse(null);
+
+        if (location == null) {
+            log.info("{} ignored. Cannot find nexthop location", prefix);
+            return;
+        }
 
         srManager.deviceConfiguration.removeSubnet(location, prefix);
         srManager.defaultRoutingHandler.revokeSubnet(ImmutableSet.of(prefix));
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 39b901b..6be675a 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -29,6 +29,7 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
+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;
@@ -50,6 +51,8 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
 import org.onosproject.net.Link;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
@@ -84,6 +87,7 @@
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.topology.PathService;
 import org.onosproject.net.topology.TopologyService;
+import org.onosproject.routeservice.ResolvedRoute;
 import org.onosproject.routeservice.RouteEvent;
 import org.onosproject.routeservice.RouteListener;
 import org.onosproject.routeservice.RouteService;
@@ -696,6 +700,19 @@
     }
 
     /**
+     * Returns locations of given resolved route.
+     *
+     * @param resolvedRoute resolved route
+     * @return locations of nexthop. Might be empty if next hop is not found
+     */
+    Set<ConnectPoint> nextHopLocations(ResolvedRoute resolvedRoute) {
+        HostId hostId = HostId.hostId(resolvedRoute.nextHopMac(), resolvedRoute.nextHopVlan());
+        return Optional.ofNullable(hostService.getHost(hostId))
+                .map(Host::locations).orElse(Sets.newHashSet())
+                .stream().map(l -> (ConnectPoint) l).collect(Collectors.toSet());
+    }
+
+    /**
      * Returns vlan port map of given device.
      *
      * @param deviceId device id