Extra route fixes
[vpnservice.git] / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / vpnservice / VpnInterfaceManager.java
index c37666a919aa10b4dfd458ba030bda4fd4b28229..b33fea8d226418e66572bde08f04bed564c31d7a 100644 (file)
@@ -17,7 +17,10 @@ import org.opendaylight.controller.md.sal.binding.api.*;
 import org.opendaylight.vpnservice.mdsalutil.*;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
@@ -41,7 +44,7 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
-import java.util.concurrent.Future;
+import java.util.concurrent.*;
 
 import com.google.common.base.Optional;
 
@@ -73,7 +76,9 @@ import org.slf4j.LoggerFactory;
 
 public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration;
+    private ConcurrentMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
+    private ExecutorService executorService = Executors.newSingleThreadExecutor();
     private final DataBroker broker;
     private final IBgpManager bgpManager;
     private IFibManager fibManager;
@@ -83,6 +88,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     private IdManagerService idManager;
     private OdlArputilService arpManager;
     private InterfaceStateChangeListener interfaceListener;
+    private VpnInterfaceOpListener vpnInterfaceOpListener;
     private ArpNotificationHandler arpNotificationHandler;
     protected enum UpdateRouteAction {
         ADVERTISE_ROUTE, WITHDRAW_ROUTE
@@ -98,6 +104,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         broker = db;
         this.bgpManager = bgpManager;
         interfaceListener = new InterfaceStateChangeListener(db, this);
+        vpnInterfaceOpListener = new VpnInterfaceOpListener();
         arpNotificationHandler = new ArpNotificationHandler(this, broker);
         notificationService.registerNotificationListener(arpNotificationHandler);
         registerListener(db);
@@ -133,10 +140,12 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         if (listenerRegistration != null) {
             try {
                 listenerRegistration.close();
+                opListenerRegistration.close();
             } catch (final Exception e) {
                 LOG.error("Error when cleaning up DataChangeListener.", e);
             }
             listenerRegistration = null;
+            opListenerRegistration = null;
         }
         LOG.info("VPN Interface Manager Closed");
     }
@@ -145,6 +154,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         try {
             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
                     getWildCardPath(), VpnInterfaceManager.this, DataChangeScope.SUBTREE);
+            opListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                                                                   getWildCardPath(), vpnInterfaceOpListener, DataChangeScope.SUBTREE);
         } catch (final Exception e) {
             LOG.error("VPN Service DataChange listener registration fail!", e);
             throw new IllegalStateException("VPN Service registration Listener failed.", e);
@@ -159,13 +170,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     @Override
     protected void add(final InstanceIdentifier<VpnInterface> identifier,
             final VpnInterface vpnInterface) {
-        LOG.trace("key: {} , value: {}", identifier, vpnInterface );
+        LOG.trace("VPN Interface key: {} , value: {}", identifier, vpnInterface );
         addInterface(identifier, vpnInterface);
     }
 
     private void addInterface(final InstanceIdentifier<VpnInterface> identifier,
                               final VpnInterface vpnInterface) {
-        LOG.trace("Add event - key: {}, value: {}" ,identifier, vpnInterface );
+        LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
         String interfaceName = key.getName();
 
@@ -173,11 +184,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
         if (interfaceState != null) {
             // Interface state is up
-            processVpnInterfaceUp(interfaceName, interfaceState.getIfIndex());
+            processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex());
+        } else {
+            LOG.trace("VPN interfaces are not yet operational.");
         }
     }
 
-    protected synchronized void processVpnInterfaceUp(String interfaceName, int lPortTag) {
+    protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag) {
 
         VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
         if(vpnInterface == null) {
@@ -186,15 +199,28 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
         String vpnName = vpnInterface.getVpnInstanceName();
         LOG.info("Binding vpn service to interface {} ", interfaceName);
-        bindService(vpnName, interfaceName, lPortTag);
-        updateDpnDbs(vpnName, interfaceName, true);
-        processVpnInterfaceAdjacencies(VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+        long vpnId = VpnUtil.getVpnId(broker, vpnName);
+        if (vpnId == VpnConstants.INVALID_ID) {
+            LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
+            return;
+        }
+        synchronized (interfaceName.intern()) {
+            if (VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName()) != null) {
+                LOG.trace("VPN Interface already provisioned , bailing out from here.");
+                return;
+            }
+            bindService(dpId, vpnName, interfaceName, lPortTag);
+            updateDpnDbs(dpId, vpnName, interfaceName, true);
+            processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()), vpnInterface);
+        }
 
     }
 
-    private void updateDpnDbs(String vpnName, String interfaceName, boolean add) {
+    private void updateDpnDbs(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
         long vpnId = VpnUtil.getVpnId(broker, vpnName);
-        BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
+        if (dpId == null) {
+            dpId = InterfaceUtils.getDpnForInterface(interfaceManager, interfaceName);
+        }
         if(!dpId.equals(BigInteger.ZERO)) {
             if(add)
                 updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
@@ -204,7 +230,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
     }
 
-    private void bindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
+    private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
         int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
 
@@ -221,11 +247,12 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                             VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
         VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
                           InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
-        makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName, vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+                    vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
 
     }
 
-    private void processVpnInterfaceAdjacencies(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
+    private void processVpnInterfaceAdjacencies(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
         String intfName = intf.getName();
 
         synchronized (intfName) {
@@ -240,7 +267,6 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 // Get the rd of the vpn instance
                 String rd = getRouteDistinguisher(intf.getVpnInstanceName());
 
-                BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
                 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
                 if (nextHopIp == null){
                     LOG.error("NextHop for interface {} is null", intfName);
@@ -261,6 +287,15 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                 VpnUtil.getPrefixToInterfaceIdentifier(
                                         VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
                                 VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
+                    } else {
+                        //Extra route adjacency
+                        VpnUtil.syncUpdate(
+                                broker,
+                                LogicalDatastoreType.OPERATIONAL,
+                                VpnUtil.getVpnToExtrarouteIdentifier(
+                                        (rd != null) ? rd : intf.getVpnInstanceName(), nextHop.getIpAddress()),
+                                VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIp()));
+
                     }
                 }
 
@@ -270,21 +305,22 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
                 for (Adjacency nextHop : aug.getAdjacency()) {
                     long label = nextHop.getLabel();
-                    String adjNextHop = nextHop.getNextHopIp();
+                    //String adjNextHop = nextHop.getNextHopIp();
                     if (rd != null) {
                         addPrefixToBGP(rd, nextHop.getIpAddress(),
-                                            (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, label);
+                                            nextHopIp, label);
                     } else {
                         // ### add FIB route directly
                         addFibEntryToDS(intf.getVpnInstanceName(), nextHop.getIpAddress(),
-                                            (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : nextHopIp, (int) label);
+                                            nextHopIp, (int) label);
                     }
                 }
             }
         }
     }
 
-    private void makeArpFlow(short sIndex, int lPortTag, String vpnInterfaceName, long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
+    private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
+                             long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow){
         List<MatchInfo> matches = new ArrayList<MatchInfo>();
         BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(vpnId));
         BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
@@ -304,7 +340,6 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
 
         // Install the flow entry in L3_INTERFACE_TABLE
-        BigInteger dpId = InterfaceUtils.getDpnForInterface(interfaceManager, vpnInterfaceName);
         String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
                     NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
         FlowEntity flowEntity;
@@ -350,7 +385,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         } else {
             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
                                     VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                                    VpnUtil.getVpnInstanceOpData(rd, vpnId));
+                                    VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId));
             VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
                 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces =  new ArrayList<>();
@@ -423,13 +458,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
 
         if (existingVpnInterface.isPresent() && interfaceState != null) {
-            processVpnInterfaceDown(interfaceName, interfaceState.getIfIndex());
+            processVpnInterfaceDown(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName, interfaceState.getIfIndex(), false);
         } else {
             LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
         }
     }
 
-    protected synchronized void processVpnInterfaceDown(String interfaceName, int lPortTag) {
+    protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown) {
         VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
         if(vpnInterface == null) {
             LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
@@ -438,11 +473,24 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         String vpnName = vpnInterface.getVpnInstanceName();
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
 
-        removeAdjacenciesFromVpn(identifier, vpnInterface);
-        LOG.info("Unbinding vpn service from interface {} ", interfaceName);
-        unbindService(vpnName, interfaceName, lPortTag);
-        updateDpnDbs(vpnName, interfaceName, false);
-        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, identifier, VpnUtil.DEFAULT_CALLBACK);
+        synchronized (interfaceName.intern()) {
+            removeAdjacenciesFromVpn(identifier, vpnInterface);
+            LOG.info("Unbinding vpn service from interface {} ", interfaceName);
+            unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown);
+
+            //wait till DCN for removal of vpn interface in operational DS arrives
+            Runnable notifyTask = new VpnNotifyTask();
+            synchronized (interfaceName.intern()) {
+                vpnIntfMap.put(interfaceName, notifyTask);
+                synchronized (notifyTask) {
+                    try {
+                        notifyTask.wait(VpnConstants.WAIT_TIME_IN_MILLISECONDS);
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+
+        }
     }
 
     private void removeAdjacenciesFromVpn(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
@@ -459,11 +507,11 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 for (Adjacency nextHop : nextHops) {
                     VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                                       VpnUtil.getNextHopLabelKey(rd, nextHop.getIpAddress()));
-                    VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                    /*VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
                                    VpnUtil.getPrefixToInterfaceIdentifier(
                                        VpnUtil.getVpnId(broker, intf.getVpnInstanceName()),
                                        nextHop.getIpAddress()),
-                                   VpnUtil.DEFAULT_CALLBACK);
+                                   VpnUtil.DEFAULT_CALLBACK);*/
                     if (rd.equals(intf.getVpnInstanceName())) {
                         //this is an internal vpn - the rd is assigned to the vpn instance name;
                         //remove from FIB directly
@@ -477,12 +525,16 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     }
 
 
-    private void unbindService(String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
-        VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION,
-                       InterfaceUtils.buildServiceId(vpnInterfaceName,VpnConstants.L3VPN_SERVICE_IDENTIFIER),
-                       VpnUtil.DEFAULT_CALLBACK);
+    private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
+                               int lPortTag, boolean isInterfaceStateDown) {
+        if (!isInterfaceStateDown) {
+            VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION,
+                           InterfaceUtils.buildServiceId(vpnInterfaceName,
+                                                         VpnConstants.L3VPN_SERVICE_IDENTIFIER),
+                           VpnUtil.DEFAULT_CALLBACK);
+        }
         long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
-        makeArpFlow(VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
+        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
                     vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
     }
 
@@ -496,56 +548,29 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     }
 
     @Override
-    protected void update(InstanceIdentifier<VpnInterface> identifier,
-                                   VpnInterface original, VpnInterface update) {
-        LOG.trace("Update VPN Interface {} , original {}, update {}",
-                                                  identifier, original, update);
-        String vpnName = original.getVpnInstanceName();
-
-        boolean vpnNameChanged = false;
-        String rd = getRouteDistinguisher(vpnName);
-        String newRd = rd;
-        String newVpnName = update.getVpnInstanceName();
-        if(!vpnName.equals(newVpnName)) {
-            //VPN for this interface got changed.
-            //Remove the interface from old VPN and add it to new VPN
-            newRd = getRouteDistinguisher(newVpnName);
-            if(newRd.equals("")) {
-                LOG.warn("VPN Instance {} not found. Update operation aborted", newVpnName);
-                return;
-            }
-            vpnNameChanged = true;
-            LOG.debug("New VPN Name for the interface {} is {}", newVpnName, original.getName());
+    protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Updating VPN Interface : key " + identifier + ",  original value=" + original + ", update " +
+                    "value=" + update);
         }
-
+        String oldVpnName = original.getVpnInstanceName();
+        String newVpnName = update.getVpnInstanceName();
         List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
         List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
-        if(vpnNameChanged && newAdjs != null && !newAdjs.isEmpty()) {
-            long label = VpnConstants.INVALID_ID;
-            InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-            Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
-            if (adjacencies.isPresent()) {
-                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
-                for(Adjacency nextHop : nextHops) {
-                    label = nextHop.getLabel();
-                    if(label == VpnConstants.INVALID_ID) {
-                        //Generate label using ID Manager
-                        label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
-                                                    VpnUtil.getNextHopLabelKey(newRd, nextHop.getIpAddress()));
-                    }
-                    if (rd != null) {
-                        removePrefixFromBGP(rd, nextHop.getIpAddress());
-                    } else {
-                        removeFibEntryFromDS(vpnName, nextHop.getIpAddress());
-                    }
-                    //updatePrefixToBGP(newRd, nextHop, nextHopIp, label);
-                }
-                processVpnInterfaceAdjacencies(identifier, update);
-                VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, update);
-            }
-        } else if (oldAdjs != newAdjs) {
-            //handle both addition and removal of adjacencies
-            //currently, new adjacency may be an extra route
+        if (oldAdjs == null) {
+            oldAdjs = new ArrayList<>();
+        }
+        if (newAdjs == null) {
+            newAdjs = new ArrayList<>();
+        }
+        //handles switching between <internal VPN - external VPN>
+        if (!oldVpnName.equals(newVpnName)) {
+            remove(identifier, original);
+            add(identifier, update);
+        }
+        //handle both addition and removal of adjacencies
+        //currently, new adjacency may be an extra route
+        if (!oldAdjs.equals(newAdjs)) {
             for (Adjacency adj : newAdjs) {
                 if (oldAdjs.contains(adj)) {
                     oldAdjs.remove(adj);
@@ -554,15 +579,10 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     addNewAdjToVpnInterface(identifier, adj);
                 }
             }
-
             for (Adjacency adj : oldAdjs) {
                 delAdjFromVpnInterface(identifier, adj);
             }
         }
-        else {
-            LOG.debug("No Update information is available for VPN Interface to proceed");
-        }
-
     }
 
     public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, String srcInterface){
@@ -619,7 +639,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
                     setVrfEntry(vrfEntryList).build();
 
-        VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, vrfTableNew);
+        VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
     }
 
     public synchronized void removeFibEntryFromDS(String rd, String prefix) {
@@ -629,7 +649,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         InstanceIdentifierBuilder<VrfEntry> idBuilder =
             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
-        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfEntryId, VpnUtil.DEFAULT_CALLBACK);
+        VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, VpnUtil.DEFAULT_CALLBACK);
 
     }
 
@@ -640,7 +660,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
 
-        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
+        VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
 
     }
 
@@ -673,7 +693,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
 
             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
-            addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label);
+            addExtraRoute(adj.getIpAddress(), adj.getNextHopIp(), rd, currVpnIntf.getVpnInstanceName(), (int) label, currVpnIntf.getName());
 
         }
 
@@ -702,7 +722,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                             adjIt.remove();
 
                             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
-                            VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug);
+                            VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
+                                                                              currVpnIntf.getVpnInstanceName(),
+                                                                              aug);
 
                             VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
 
@@ -717,7 +739,25 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
     }
 
-    protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label) {
+    protected void addExtraRoute(String destination, String nextHop, String rd, String routerID, int label, String intfName) {
+
+        //add extra route to vpn mapping; advertise with nexthop as tunnel ip
+        VpnUtil.syncUpdate(
+            broker,
+            LogicalDatastoreType.OPERATIONAL,
+            VpnUtil.getVpnToExtrarouteIdentifier(
+                (rd != null) ? rd : routerID, destination),
+            VpnUtil.getVpnToExtraroute(destination, nextHop));
+
+        if(intfName != null && !intfName.isEmpty()) {
+            BigInteger dpnId = InterfaceUtils.getDpnForInterface(interfaceManager, intfName);
+            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+            if (nextHopIp == null && !nextHopIp.isEmpty()) {
+                LOG.error("NextHop for interface {} is null. Adding extra route {} without nextHop", intfName,
+                        destination);
+            }
+            nextHop = nextHopIp;
+        }
         if (rd != null) {
             addPrefixToBGP(rd, destination, nextHop, label);
         } else {
@@ -735,8 +775,95 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
+    class VpnInterfaceOpListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<VpnInterface> {
+
+        public VpnInterfaceOpListener() {
+            super(VpnInterface.class);
+        }
+
+        @Override
+        protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
+            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
+            String interfaceName = key.getName();
+
+            //increment the vpn interface count in Vpn Instance Op Data
+            Long ifCnt = 0L;
+            String rd = getRouteDistinguisher(del.getVpnInstanceName());
+            if(rd == null || rd.isEmpty()) rd = del.getVpnInstanceName();
+            VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
+            if(vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
+                ifCnt = vpnInstOp.getVpnInterfaceCount();
+            }
+
+            LOG.trace("VpnInterfaceOpListener remove: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
+
+            if(ifCnt != 0) {
+                VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
+                        VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
+            }
+
+            // Vpn Interface removed => No more adjacencies from it.
+            // Hence clean up interface from vpn-dpn-interface list.
+            Adjacency adjacency = del.getAugmentation(Adjacencies.class).getAdjacency().get(0);
+            Optional<Prefixes> prefixToInterface = Optional.absent();
+            prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                         VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                                VpnUtil.getIpPrefix(adjacency.getIpAddress())));
+            if (!prefixToInterface.isPresent()) {
+                prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                                                 VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                                         VpnUtil.getIpPrefix(adjacency.getNextHopIp())));
+            }
+            if (prefixToInterface.isPresent()) {
+                VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                               VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
+                                                 prefixToInterface.get().getIpAddress()),
+                               VpnUtil.DEFAULT_CALLBACK);
+                updateDpnDbs(prefixToInterface.get().getDpnId(), del.getVpnInstanceName(), interfaceName, false);
+            }
+            notifyTaskIfRequired(interfaceName);
+        }
+
+        private void notifyTaskIfRequired(String intfName) {
+            Runnable notifyTask = vpnIntfMap.remove(intfName);
+            if (notifyTask == null) {
+                return;
+            }
+            executorService.execute(notifyTask);
+        }
+
+        @Override
+        protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
+        }
+
+        @Override
+        protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
+            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
+            String interfaceName = key.getName();
+
+            //increment the vpn interface count in Vpn Instance Op Data
+            Long ifCnt = 0L;
+            String rd = getRouteDistinguisher(add.getVpnInstanceName());
+            if(rd == null || rd.isEmpty()) rd = add.getVpnInstanceName();
+            VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
+            if(vpnInstOp != null &&  vpnInstOp.getVpnInterfaceCount() != null) {
+                ifCnt = vpnInstOp.getVpnInterfaceCount();
+            }
+
+            LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
+
+            VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
+                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
+                    VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
+
+
+        }
+    }
+
     protected void updatePrefixesForDPN(BigInteger dpnId, UpdateRouteAction action) {
 
+        LOG.info("Tunnel event triggered {} for Dpn:{} ", action.name(), dpnId);
         InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
         InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
         Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
@@ -746,46 +873,60 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
             while (vpnInstIter.hasNext()) {
                 VpnInstance vpnInstance = vpnInstIter.next();
-                VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
-                String rd = vpnConfig.getRouteDistinguisher();
-
-                InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
-                Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-                if (dpnInVpn.isPresent()) {
-                    if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
-                        fibManager.populateFibOnNewDpn(dpnId, VpnUtil
-                            .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
+                try {
+                    VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
+                    String rd = vpnConfig.getRouteDistinguisher();
+                    if (rd == null || rd.isEmpty()) {
+                        rd = vpnInstance.getVpnInstanceName();
                     }
-                    List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
-                        .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
-                    for(org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
-                        .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
-                        InstanceIdentifier<VpnInterface> vpnIntfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
-                        InstanceIdentifier<Adjacencies> path = vpnIntfId.augmentation(Adjacencies.class);
-                        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
-
-                        if (adjacencies.isPresent()) {
-                            List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
-                            Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
-
-                            while (adjacencyIterator.hasNext()) {
-                                Adjacency adjacency = adjacencyIterator.next();
-                                try {
-                                    if(action == UpdateRouteAction.ADVERTISE_ROUTE)
-                                        bgpManager.addPrefix(rd, adjacency.getIpAddress(), adjacency.getNextHopIp(), adjacency.getLabel().intValue());
-                                    else if(action == UpdateRouteAction.WITHDRAW_ROUTE)
-                                        bgpManager.deletePrefix(rd, adjacency.getIpAddress());
-                                } catch (Exception e) {
-                                    LOG.error("Exception when updating prefix {} in vrf {} to BGP", adjacency.getIpAddress(), rd);
+                    InstanceIdentifier<VpnToDpnList> id =
+                        VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
+                    Optional<VpnToDpnList> dpnInVpn =
+                        VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+                    if (dpnInVpn.isPresent()) {
+                        // if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
+                        //    fibManager.populateFibOnNewDpn(dpnId, VpnUtil
+                        //        .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
+                        // }
+                        List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                            .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
+                            vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+                        for (org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
+                            .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
+                            InstanceIdentifier<VpnInterface> vpnIntfId =
+                                VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
+                            InstanceIdentifier<Adjacencies> path =
+                                vpnIntfId.augmentation(Adjacencies.class);
+                            Optional<Adjacencies> adjacencies =
+                                VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+
+                            if (adjacencies.isPresent()) {
+                                List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
+                                Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
+
+                                while (adjacencyIterator.hasNext()) {
+                                    Adjacency adjacency = adjacencyIterator.next();
+                                    try {
+                                        if (action == UpdateRouteAction.ADVERTISE_ROUTE)
+                                            bgpManager.addPrefix(rd, adjacency.getIpAddress(),
+                                                                 adjacency.getNextHopIp(),
+                                                                 adjacency.getLabel().intValue());
+                                        else if (action == UpdateRouteAction.WITHDRAW_ROUTE)
+                                            bgpManager.deletePrefix(rd, adjacency.getIpAddress());
+                                    } catch (Exception e) {
+                                        LOG.error("Exception when updating prefix {} in vrf {} to BGP",
+                                            adjacency.getIpAddress(), rd);
+                                    }
                                 }
                             }
-                        }
 
+                        }
+                        // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
+                        //    fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
+                        // }
                     }
-                    if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
-                        fibManager.cleanUpDpnForVpn(dpnId, VpnUtil
-                            .getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
-                    }
+                } catch (Exception e) {
+                    LOG.error("updatePrefixesForDPN {} in vpn {} failed", dpnId, vpnInstance.getVpnInstanceName(), e);
                 }
             }
         }