[GEANT] Adaptation to routing API deprecation

Change-Id: I7d5cfac89a4ac5c82dc079b0c2240abadc3bbcba
diff --git a/sdx-l3/pom.xml b/sdx-l3/pom.xml
index 694c128..413b82b 100644
--- a/sdx-l3/pom.xml
+++ b/sdx-l3/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
-  ~ Copyright 2016-present Open Networking Laboratory
+  ~ Copyright 2016 - present Open Networking Laboratory
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -54,6 +54,14 @@
 
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <classifier>tests</classifier>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onos-app-routing</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
index 2a64240..af22d6a 100644
--- a/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
+++ b/sdx-l3/src/main/java/org/onosproject/sdxl3/SdxL3Fib.java
@@ -17,6 +17,7 @@
 package org.onosproject.sdxl3;
 
 import com.google.common.collect.ImmutableList;
+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;
@@ -30,7 +31,13 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceEvent;
+import org.onosproject.incubator.net.intf.InterfaceListener;
 import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.incubator.net.routing.ResolvedRoute;
+import org.onosproject.incubator.net.routing.RouteEvent;
+import org.onosproject.incubator.net.routing.RouteListener;
+import org.onosproject.incubator.net.routing.RouteService;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -40,21 +47,15 @@
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.constraint.PartialFailureConstraint;
-import org.onosproject.routing.FibListener;
-import org.onosproject.routing.FibUpdate;
 import org.onosproject.routing.IntentSynchronizationService;
-import org.onosproject.routing.RoutingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 /**
  * FIB component of SDX-L3.
  */
@@ -72,12 +73,13 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected RoutingService routingService;
+    protected RouteService routeService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected SdxL3PeerService peerService;
 
-    private final InternalFibListener fibListener = new InternalFibListener();
+    private final InternalRouteListener routeListener = new InternalRouteListener();
+    private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
 
     private static final int PRIORITY_OFFSET = 100;
     private static final int PRIORITY_MULTIPLIER = 5;
@@ -93,68 +95,43 @@
     public void activate() {
         appId = coreService.getAppId(SdxL3.SDX_L3_APP);
 
-        routingService.addFibListener(fibListener);
-        routingService.start();
+        interfaceService.addListener(interfaceListener);
+
+        routeService.addListener(routeListener);
     }
 
     @Deactivate
     public void deactivate() {
-        // TODO remove listener
-        routingService.stop();
+        interfaceService.removeListener(interfaceListener);
+        routeService.removeListener(routeListener);
     }
 
-    private void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
-        int submitCount = 0, withdrawCount = 0;
-        //
-        // NOTE: Semantically, we MUST withdraw existing intents before
-        // submitting new intents.
-        //
+    private void update(ResolvedRoute route) {
         synchronized (this) {
-            MultiPointToSinglePointIntent intent;
+            IpPrefix prefix = route.prefix();
+            MultiPointToSinglePointIntent intent =
+                    generateRouteIntent(prefix, route.nextHop(), route.nextHopMac());
 
-            //
-            // Prepare the Intent batch operations for the intents to withdraw
-            //
-            for (FibUpdate withdraw : withdraws) {
-                checkArgument(withdraw.type() == FibUpdate.Type.DELETE,
-                        "FibUpdate with wrong type in withdraws list");
-
-                IpPrefix prefix = withdraw.entry().prefix();
-                intent = routeIntents.remove(prefix);
-                if (intent == null) {
-                    log.trace("SDX-L3 No intent in routeIntents to delete " +
-                            "for prefix: {}", prefix);
-                    continue;
-                }
-                intentSynchronizer.withdraw(intent);
-                withdrawCount++;
+            if (intent == null) {
+                log.debug("SDX-L3 no interface found for route {}", route);
+                return;
             }
 
-            //
-            // Prepare the Intent batch operations for the intents to submit
-            //
-            for (FibUpdate update : updates) {
-                checkArgument(update.type() == FibUpdate.Type.UPDATE,
-                        "FibUpdate with wrong type in updates list");
+            routeIntents.put(prefix, intent);
+            intentSynchronizer.submit(intent);
+        }
+    }
 
-                IpPrefix prefix = update.entry().prefix();
-                intent = generateRouteIntent(prefix, update.entry().nextHopIp(),
-                        update.entry().nextHopMac());
-
-                if (intent == null) {
-                    // This preserves the old semantics - if an intent can't be
-                    // generated, we don't do anything with that prefix. But
-                    // perhaps we should withdraw the old intent anyway?
-                    continue;
-                }
-
-                routeIntents.put(prefix, intent);
-                intentSynchronizer.submit(intent);
-                submitCount++;
+    private void withdraw(ResolvedRoute route) {
+        synchronized (this) {
+            IpPrefix prefix = route.prefix();
+            MultiPointToSinglePointIntent intent = routeIntents.remove(prefix);
+            if (intent == null) {
+                log.trace("SDX-L3 no intent in routeIntents to delete " +
+                                  "for prefix: {}", prefix);
+                return;
             }
-
-            log.debug("SDX-L3 submitted {}/{}, withdrew = {}/{}", submitCount,
-                    updates.size(), withdrawCount, withdraws.size());
+            intentSynchronizer.withdraw(intent);
         }
     }
 
@@ -181,26 +158,41 @@
 
         if (egressInterface == null) {
             log.warn("No outgoing interface found for {}",
-                    nextHopIpAddress);
+                     nextHopIpAddress);
             return null;
         }
-
-        // Generate the intent itself
-        Set<ConnectPoint> ingressPorts = new HashSet<>();
         ConnectPoint egressPort = egressInterface.connectPoint();
-        log.debug("Generating intent for prefix {}, next hop mac {}",
-                prefix, nextHopMacAddress);
 
-        for (Interface intf : interfaceService.getInterfaces()) {
-            // TODO this should be only peering interfaces
-            if (!intf.connectPoint().equals(egressInterface.connectPoint())) {
-                ConnectPoint srcPort = intf.connectPoint();
-                ingressPorts.add(srcPort);
+        Set<Interface> ingressInterfaces = new HashSet<>();
+        Set<ConnectPoint> ingressPorts = new HashSet<>();
+        log.debug("Generating intent for prefix {}, next hop mac {}",
+                  prefix, nextHopMacAddress);
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+
+        // Get ingress interfaces and ports
+        // TODO this should be only peering interfaces
+        interfaceService.getInterfaces().stream()
+                .filter(intf -> !intf.equals(egressInterface))
+                .forEach(intf -> {
+                    ingressInterfaces.add(intf);
+                    ConnectPoint ingressPort = intf.connectPoint();
+                    ingressPorts.add(ingressPort);
+                });
+
+        // By default the ingress traffic is not tagged
+        VlanId ingressVlanId = VlanId.NONE;
+
+        // Match VLAN Id ANY if the source VLAN Id is not null
+        // TODO need to be able to set a different VLAN Id per ingress interface
+        for (Interface intf : ingressInterfaces) {
+            if (!intf.vlan().equals(VlanId.NONE)) {
+                selector.matchVlanId(VlanId.ANY);
+                ingressVlanId = intf.vlan();
             }
         }
 
         // Match the destination IP prefix at the first hop
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         if (prefix.isIp4()) {
             selector.matchEthType(Ethernet.TYPE_IPV4);
             // if it is default route, then we do not need match destination
@@ -215,22 +207,29 @@
             if (prefix.prefixLength() != 0) {
                 selector.matchIPv6Dst(prefix);
             }
-
         }
 
         // Rewrite the destination MAC address
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
                 .setEthDst(nextHopMacAddress);
-        if (!egressInterface.vlan().equals(VlanId.NONE)) {
-            treatment.setVlanId(egressInterface.vlan());
-            // If we set VLAN ID, we have to make sure a VLAN tag exists.
-            // TODO support no VLAN -> VLAN routing
-            selector.matchVlanId(VlanId.ANY);
+
+        // Set egress VLAN Id
+        // TODO need to make the comparison with different ingress VLAN Ids
+        if (!ingressVlanId.equals(egressInterface.vlan())) {
+            if (egressInterface.vlan().equals(VlanId.NONE)) {
+                treatment.popVlan();
+            } else {
+                treatment.setVlanId(egressInterface.vlan());
+            }
         }
 
+        // Set priority
         int priority =
                 prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
+
+        // Set key
         Key key = Key.of(prefix.toString(), appId);
+
         return MultiPointToSinglePointIntent.builder()
                 .appId(appId)
                 .key(key)
@@ -243,10 +242,84 @@
                 .build();
     }
 
-    private class InternalFibListener implements FibListener {
+    private void updateInterface(Interface intf) {
+        synchronized (this) {
+            for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry : routeIntents.entrySet()) {
+                MultiPointToSinglePointIntent intent = entry.getValue();
+                Set<ConnectPoint> ingress = Sets.newHashSet(intent.ingressPoints());
+                ingress.add(intf.connectPoint());
+
+                MultiPointToSinglePointIntent newIntent =
+                        MultiPointToSinglePointIntent.builder(intent)
+                                .ingressPoints(ingress)
+                                .build();
+
+                routeIntents.put(entry.getKey(), newIntent);
+                intentSynchronizer.submit(newIntent);
+            }
+        }
+    }
+
+    private void removeInterface(Interface intf) {
+        synchronized (this) {
+            for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry : routeIntents.entrySet()) {
+                MultiPointToSinglePointIntent intent = entry.getValue();
+                if (intent.egressPoint().equals(intf.connectPoint())) {
+                    // This intent just lost its head. Remove it and let
+                    // higher layer routing reroute.
+                    intentSynchronizer.withdraw(routeIntents.remove(entry.getKey()));
+                } else {
+                    if (intent.ingressPoints().contains(intf.connectPoint())) {
+
+                        Set<ConnectPoint> ingress = Sets.newHashSet(intent.ingressPoints());
+                        ingress.remove(intf.connectPoint());
+
+                        MultiPointToSinglePointIntent newIntent =
+                                MultiPointToSinglePointIntent.builder(intent)
+                                        .ingressPoints(ingress)
+                                        .build();
+
+                        routeIntents.put(entry.getKey(), newIntent);
+                        intentSynchronizer.submit(newIntent);
+                    }
+                }
+            }
+        }
+    }
+
+    private class InternalRouteListener implements RouteListener {
         @Override
-        public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) {
-            SdxL3Fib.this.update(updates, withdraws);
+        public void event(RouteEvent event) {
+            switch (event.type()) {
+                case ROUTE_ADDED:
+                case ROUTE_UPDATED:
+                    update(event.subject());
+                    break;
+                case ROUTE_REMOVED:
+                    withdraw(event.subject());
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    private class InternalInterfaceListener implements InterfaceListener {
+
+        @Override
+        public void event(InterfaceEvent event) {
+            switch (event.type()) {
+                case INTERFACE_ADDED:
+                    updateInterface(event.subject());
+                    break;
+                case INTERFACE_UPDATED:
+                    break;
+                case INTERFACE_REMOVED:
+                    removeInterface(event.subject());
+                    break;
+                default:
+                    break;
+            }
         }
     }
 
diff --git a/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxL3FibTest.java b/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxL3FibTest.java
index 90dcb8a..d057324 100644
--- a/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxL3FibTest.java
+++ b/sdx-l3/src/test/java/org/onosproject/sdxl3/SdxL3FibTest.java
@@ -30,7 +30,13 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceListener;
 import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.incubator.net.intf.InterfaceServiceAdapter;
+import org.onosproject.incubator.net.routing.ResolvedRoute;
+import org.onosproject.incubator.net.routing.RouteEvent;
+import org.onosproject.incubator.net.routing.RouteListener;
+import org.onosproject.incubator.net.routing.RouteServiceAdapter;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
@@ -42,11 +48,7 @@
 import org.onosproject.net.intent.AbstractIntentTest;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
-import org.onosproject.routing.FibEntry;
-import org.onosproject.routing.FibListener;
-import org.onosproject.routing.FibUpdate;
 import org.onosproject.routing.IntentSynchronizationService;
-import org.onosproject.routing.RoutingServiceAdapter;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -54,8 +56,10 @@
 import java.util.List;
 import java.util.Set;
 
+import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMock;
 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;
@@ -112,7 +116,8 @@
 
     private static final ApplicationId APPID = TestApplicationId.create("sdxl3");
 
-    private FibListener fibListener;
+    private RouteListener routeListener;
+    private InterfaceListener interfaceListener;
 
     @Override
     @Before
@@ -120,6 +125,9 @@
         super.setUp();
 
         interfaceService = createMock(InterfaceService.class);
+        interfaceService.addListener(anyObject(InterfaceListener.class));
+        expectLastCall().andDelegateTo(new InterfaceServiceDelegate());
+
         peerService = createMock(SdxL3PeerService.class);
 
         // These will set expectations on routingConfig and interfaceService
@@ -132,7 +140,7 @@
         intentSynchronizer = createMock(IntentSynchronizationService.class);
 
         sdxL3Fib = new SdxL3Fib();
-        sdxL3Fib.routingService = new TestRoutingService();
+        sdxL3Fib.routeService = new TestRouteService();
         sdxL3Fib.coreService = new TestCoreService();
         sdxL3Fib.interfaceService = interfaceService;
         sdxL3Fib.intentSynchronizer = intentSynchronizer;
@@ -182,7 +190,7 @@
         interface4 = new Interface("test4",
                                    CONN_POINT4,
                                    interfaceIpAddresses4, MacAddress.valueOf(MAC2),
-                                   VlanId.NONE);
+                                   VlanId.vlanId((short) 2));
         interfaces.add(interface4);
 
         expect(interfaceService.getInterfacesByPort(CONN_POINT1)).andReturn(
@@ -217,28 +225,27 @@
     }
 
     /**
-     * Tests adding a FIB entry to the IntentSynchronizer. Peers within the same
+     * Tests adding a route to the IntentSynchronizer. Peers within the same
      * subnet exist.
      *
      * We verify that the synchronizer records the correct state and that the
      * correct intent is submitted to the IntentService.
      */
     @Test
-    public void testFibAdd() {
+    public void testRouteAdd() {
         IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
-        FibEntry fibEntry = new FibEntry(prefix,
-                                         Ip4Address.valueOf(PEER1_IP),
-                                         MacAddress.valueOf(MAC1));
+        ResolvedRoute route = new ResolvedRoute(prefix,
+                                                Ip4Address.valueOf(PEER1_IP),
+                                                MacAddress.valueOf(MAC1));
 
         // Construct a MultiPointToSinglePointIntent intent
         TrafficSelector.Builder selectorBuilder =
                 DefaultTrafficSelector.builder();
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                fibEntry.prefix());
+        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(prefix).matchVlanId(VlanId.ANY);
 
         TrafficTreatment.Builder treatmentBuilder =
                 DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(MacAddress.valueOf(MAC1));
+        treatmentBuilder.setEthDst(MacAddress.valueOf(MAC1)).popVlan();
 
         Set<ConnectPoint> ingressPoints = new HashSet<>();
         ingressPoints.add(CONN_POINT2);
@@ -260,31 +267,30 @@
         intentSynchronizer.submit(eqExceptId(intent));
         replay(intentSynchronizer);
 
-        // Send in the UPDATE FibUpdate
-        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
-        fibListener.update(Collections.singleton(fibUpdate), Collections.emptyList());
+        // Send in the added event
+        routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_ADDED, route));
 
         verify(intentSynchronizer);
     }
 
     /**
-     * Tests adding a FIB entry with to a next hop in a VLAN.
+     * Tests adding a route entry with a next hop in a VLAN.
      *
      * We verify that the synchronizer records the correct state and that the
      * correct intent is submitted to the IntentService.
      */
     @Test
-    public void testFibAddWithVlan() {
+    public void testRouteAddWithVlan() {
         IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
-        FibEntry fibEntry = new FibEntry(prefix,
-                                         Ip4Address.valueOf(PEER3_IP),
-                                         MacAddress.valueOf(MAC1));
+        ResolvedRoute route = new ResolvedRoute(prefix,
+                                                Ip4Address.valueOf(PEER3_IP),
+                                                MacAddress.valueOf(MAC1));
 
         // Construct a MultiPointToSinglePointIntent intent
         TrafficSelector.Builder selectorBuilder =
                 DefaultTrafficSelector.builder();
         selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(fibEntry.prefix())
+                .matchIPDst(prefix)
                 .matchVlanId(VlanId.ANY);
 
         TrafficTreatment.Builder treatmentBuilder =
@@ -313,40 +319,40 @@
 
         replay(intentSynchronizer);
 
-        // Send in the UPDATE FibUpdate
-        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry);
-        fibListener.update(Collections.singleton(fibUpdate), Collections.emptyList());
+        // Send in the added event
+        routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_ADDED, route));
 
         verify(intentSynchronizer);
     }
 
     /**
-     * Tests updating a FIB entry.
+     * Tests updating a route entry.
      *
      * We verify that the synchronizer records the correct state and that the
      * correct intent is submitted to the IntentService.
      */
     @Test
-    public void testFibUpdate() {
+    public void testRouteUpdate() {
         // Firstly add a route
-        testFibAdd();
+        testRouteAdd();
 
         IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
 
         // Start to construct a new route entry and new intent
-        FibEntry fibEntryUpdate = new FibEntry(prefix,
-                                               Ip4Address.valueOf(PEER2_IP),
-                                               MacAddress.valueOf(MAC1));
+        ResolvedRoute route = new ResolvedRoute(prefix,
+                                                Ip4Address.valueOf(PEER2_IP),
+                                                MacAddress.valueOf(MAC1));
 
         // Construct a new MultiPointToSinglePointIntent intent
         TrafficSelector.Builder selectorBuilderNew =
                 DefaultTrafficSelector.builder();
-        selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                fibEntryUpdate.prefix());
+        selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(prefix)
+                .matchVlanId(VlanId.ANY);
 
         TrafficTreatment.Builder treatmentBuilderNew =
                 DefaultTrafficTreatment.builder();
-        treatmentBuilderNew.setEthDst(MacAddress.valueOf(MAC1));
+        treatmentBuilderNew.setEthDst(MacAddress.valueOf(MAC1)).popVlan();
 
         Set<ConnectPoint> ingressPointsNew = new HashSet<>();
         ingressPointsNew.add(CONN_POINT1);
@@ -371,40 +377,38 @@
         intentSynchronizer.submit(eqExceptId(intentNew));
         replay(intentSynchronizer);
 
-        // Send in the UPDATE FibUpdate
-        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE,
-                                            fibEntryUpdate);
-        fibListener.update(Collections.singletonList(fibUpdate),
-                           Collections.emptyList());
+        // Send in the update event
+        routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, route));
 
         verify(intentSynchronizer);
     }
 
     /**
-     * Tests deleting a FIB entry.
+     * Tests deleting a route entry.
      *
      * We verify that the synchronizer records the correct state and that the
      * correct intent is withdrawn from the IntentService.
      */
     @Test
-    public void testFibDelete() {
+    public void testRouteDelete() {
         // Firstly add a route
-        testFibAdd();
+        testRouteAdd();
 
         IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
 
         // Construct the existing route entry
-        FibEntry fibEntry = new FibEntry(prefix, null, null);
+        ResolvedRoute route = new ResolvedRoute(prefix, null, null);
 
         // Construct the existing MultiPointToSinglePoint intent
         TrafficSelector.Builder selectorBuilder =
                 DefaultTrafficSelector.builder();
-        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
-                fibEntry.prefix());
+        selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(prefix)
+                .matchVlanId(VlanId.ANY);
 
         TrafficTreatment.Builder treatmentBuilder =
                 DefaultTrafficTreatment.builder();
-        treatmentBuilder.setEthDst(MacAddress.valueOf(MAC1));
+        treatmentBuilder.setEthDst(MacAddress.valueOf(MAC1)).popVlan();
 
         Set<ConnectPoint> ingressPoints = new HashSet<>();
         ingressPoints.add(CONN_POINT2);
@@ -428,9 +432,8 @@
         intentSynchronizer.withdraw(eqExceptId(addedIntent));
         replay(intentSynchronizer);
 
-        // Send in the DELETE FibUpdate
-        FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry);
-        fibListener.update(Collections.emptyList(), Collections.singletonList(fibUpdate));
+        // Send in the removed event
+        routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, route));
 
         verify(intentSynchronizer);
     }
@@ -442,12 +445,17 @@
         }
     }
 
-    private class TestRoutingService extends RoutingServiceAdapter {
-
+    private class TestRouteService extends RouteServiceAdapter {
         @Override
-        public void addFibListener(FibListener fibListener) {
-            SdxL3FibTest.this.fibListener = fibListener;
+        public void addListener(RouteListener routeListener) {
+            SdxL3FibTest.this.routeListener = routeListener;
+        }
+    }
+
+    private class InterfaceServiceDelegate extends InterfaceServiceAdapter {
+        @Override
+        public void addListener(InterfaceListener listener) {
+            SdxL3FibTest.this.interfaceListener = listener;
         }
     }
 }
-