Delete prefix from sr-device-subnet when the next hop host is removed

Change-Id: I440897a531b69dd7bbe771eff69728bbff9a2513
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 4c56db5..1690522 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
@@ -171,6 +171,16 @@
                         processRoutingRule(pairDeviceId.get(), pairLocalPort.get(), hostMac, vlanId,
                                 ip, true));
             }
+
+            // Delete prefix from sr-device-subnet when the next hop host is removed
+            srManager.routeService.getRouteTables().forEach(tableId -> {
+                srManager.routeService.getRoutes(tableId).forEach(routeInfo -> {
+                    if (routeInfo.allRoutes().stream().anyMatch(rr -> ips.contains(rr.nextHop()))) {
+                        log.debug("HostRemoved. removeSubnet {}, {}", location, routeInfo.prefix());
+                        srManager.deviceConfiguration.removeSubnet(location, routeInfo.prefix());
+                    }
+                });
+            });
         });
     }
 
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 30462fb..f3f49ae 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
@@ -21,6 +21,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import org.easymock.EasyMock;
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
@@ -42,6 +43,11 @@
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.InterfaceIpAddress;
 import org.onosproject.net.provider.ProviderId;
+import org.onosproject.routeservice.ResolvedRoute;
+import org.onosproject.routeservice.Route;
+import org.onosproject.routeservice.RouteInfo;
+import org.onosproject.routeservice.RouteService;
+import org.onosproject.routeservice.RouteTableId;
 import org.onosproject.segmentrouting.config.DeviceConfiguration;
 import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
 import org.onosproject.store.service.StorageService;
@@ -51,8 +57,12 @@
 import java.util.Set;
 
 import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
 import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.*;
 
 /**r
@@ -223,6 +233,11 @@
         srManager.probingService = mockLocationProbingService;
         srManager.linkHandler = new MockLinkHandler(srManager);
 
+        // Not important for most of the HostHandler test case. Simply return an empty set here
+        srManager.routeService = createNiceMock(RouteService.class);
+        expect(srManager.routeService.getRouteTables()).andReturn(Sets.newHashSet()).anyTimes();
+        replay(srManager.routeService);
+
         hostHandler = new HostHandler(srManager);
 
         ROUTING_TABLE.clear();
@@ -867,4 +882,56 @@
         assertNull(hostHandler.vlanForPairPort(VlanId.NONE, CP51));
         assertNull(hostHandler.vlanForPairPort(INTF_VLAN_UNTAGGED, CP51));
     }
+
+    @Test
+    public void testHostRemovedWithRouteRemoved() 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);
+
+        // Add a host
+        // Expect: add one routing rule and one bridging rule
+        hostHandler.processHostAddedEvent(new HostEvent(HostEvent.Type.HOST_ADDED, subject));
+        assertEquals(1, ROUTING_TABLE.size());
+        assertNotNull(ROUTING_TABLE.get(new MockRoutingTableKey(DEV1, HOST_IP11.toIpPrefix())));
+        assertEquals(1, BRIDGING_TABLE.size());
+        assertNotNull(BRIDGING_TABLE.get(new MockBridgingTableKey(DEV1, HOST_MAC, INTF_VLAN_UNTAGGED)));
+
+        IpPrefix prefix = IpPrefix.valueOf("55.55.55.0/24");
+
+        // Setting up mock route service
+        RouteService routeService = hostHandler.srManager.routeService;
+        reset(routeService);
+
+        IpAddress nextHopIp2 = IpAddress.valueOf("20.0.0.1");
+        MacAddress nextHopMac2 = MacAddress.valueOf("00:22:33:44:55:66");
+        VlanId nextHopVlan2 = VlanId.NONE;
+
+        Route r1 = new Route(Route.Source.STATIC, prefix, HOST_IP11);
+        ResolvedRoute rr1 = new ResolvedRoute(r1, HOST_MAC, VlanId.NONE);
+        Route r2 = new Route(Route.Source.STATIC, prefix, nextHopIp2);
+        ResolvedRoute rr2 = new ResolvedRoute(r2, nextHopMac2, nextHopVlan2);
+        RouteInfo routeInfo = new RouteInfo(prefix, rr1, Sets.newHashSet(rr1, rr2));
+        RouteTableId routeTableId = new RouteTableId("ipv4");
+
+        expect(routeService.getRouteTables()).andReturn(Sets.newHashSet(routeTableId));
+        expect(routeService.getRoutes(routeTableId)).andReturn(Sets.newHashSet(routeInfo));
+        replay(routeService);
+
+        // Setting up mock device configuration
+        hostHandler.srManager.deviceConfiguration = EasyMock.createNiceMock(DeviceConfiguration.class);
+        DeviceConfiguration deviceConfiguration = hostHandler.srManager.deviceConfiguration;
+        expect(deviceConfiguration.inSameSubnet(CP11, HOST_IP11)).andReturn(true);
+        deviceConfiguration.removeSubnet(CP11, prefix);
+        expectLastCall();
+        replay(deviceConfiguration);
+
+        // Remove the host
+        // Expect: add the routing rule and the bridging rule
+        hostHandler.processHostRemovedEvent(new HostEvent(HostEvent.Type.HOST_REMOVED, subject));
+        assertEquals(0, ROUTING_TABLE.size());
+        assertEquals(0, BRIDGING_TABLE.size());
+
+        // Expect: subnet is removed from device config
+        verify(deviceConfiguration);
+    }
 }