BUG 6841: Few Remote flows not deleted on DPNs
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInterfaceManager.java
index 1a6b259991d88e3e6f125caf0192cdd123d4ae2a..6963239076acda6a7c5863a4ad311d497872d819 100644 (file)
  */
 package org.opendaylight.netvirt.vpnmanager;
 
-import com.google.common.base.*;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Iterators;
-import com.google.common.util.concurrent.*;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.ActionType;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.InstructionType;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchFieldType;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
-import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.vpnmanager.intervpnlink.InterVpnLinkUtil;
 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
-
-import org.opendaylight.controller.md.sal.binding.api.*;
-import org.opendaylight.genius.mdsalutil.*;
-import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
+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.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.*;
-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.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AddDpnEventBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveDpnEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RemoveDpnEventBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.add.dpn.event.AddEventDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
@@ -68,180 +119,71 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neu
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.remove.dpn.event.RemoveEventDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-        .VpnInstanceOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpResponseInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-
-import java.math.BigInteger;
-import java.util.Collection;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.concurrent.*;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface> implements AutoCloseable {
+public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInterface, VpnInterfaceManager>
+        implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
-    private ListenerRegistration<DataChangeListener> listenerRegistration, opListenerRegistration;
-    private final DataBroker broker;
+    private final DataBroker dataBroker;
     private final IBgpManager bgpManager;
-    private IFibManager fibManager;
-    private IMdsalApiManager mdsalManager;
-    private OdlInterfaceRpcService ifaceMgrRpcService;
-    private IdManagerService idManager;
-    private OdlArputilService arpManager;
-    private NeutronvpnService neuService;
-    private VpnSubnetRouteHandler vpnSubnetRouteHandler;
+    private final IFibManager fibManager;
+    private final IMdsalApiManager mdsalManager;
+    private final IdManagerService idManager;
+    private final OdlArputilService arpManager;
+    private final OdlInterfaceRpcService ifaceMgrRpcService;
+    private final NotificationPublishService notificationPublishService;
     private ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<String, Runnable>();
     private ExecutorService executorService = Executors.newSingleThreadExecutor();
-    private InterfaceStateChangeListener interfaceListener;
-    private SubnetRouteInterfaceStateChangeListener subnetRouteInterfaceListener;
-    private TunnelInterfaceStateListener tunnelInterfaceStateListener;
-    private VpnInterfaceOpListener vpnInterfaceOpListener;
-    private ArpNotificationHandler arpNotificationHandler;
-    private DpnInVpnChangeListener dpnInVpnChangeListener;
-    private NotificationPublishService notificationPublishService;
-    private FibRpcService fibService;
 
-    /**
-     * Responsible for listening to data change related to VPN Interface
-     * Bind VPN Service on the interface and informs the BGP service
-     *
-     * @param db - dataBroker service reference
-     * @param bgpManager Used to advertise routes to the BGP Router
-     * @param notificationService Used to subscribe to notification events
-     */
-    public VpnInterfaceManager(final DataBroker db, final IBgpManager bgpManager, NotificationService notificationService) {
-        super(VpnInterface.class);
-        broker = db;
+    public VpnInterfaceManager(final DataBroker dataBroker,
+                               final IBgpManager bgpManager,
+                               final OdlArputilService arpManager,
+                               final IdManagerService idManager,
+                               final IMdsalApiManager mdsalManager,
+                               final IFibManager fibManager,
+                               final OdlInterfaceRpcService ifaceMgrRpcService,
+                               final NotificationPublishService notificationPublishService) {
+        super(VpnInterface.class, VpnInterfaceManager.class);
+        this.dataBroker = dataBroker;
         this.bgpManager = bgpManager;
-        interfaceListener = new InterfaceStateChangeListener(db, this);
-        subnetRouteInterfaceListener = new SubnetRouteInterfaceStateChangeListener(db, this);
-        vpnInterfaceOpListener = new VpnInterfaceOpListener();
-        arpNotificationHandler = new ArpNotificationHandler(this, broker);
-        vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
-        dpnInVpnChangeListener = new DpnInVpnChangeListener(broker);
-        notificationService.registerNotificationListener(vpnSubnetRouteHandler);
-        notificationService.registerNotificationListener(arpNotificationHandler);
-        notificationService.registerNotificationListener(dpnInVpnChangeListener);
-        registerListener(db);
-    }
-
-    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.arpManager = arpManager;
+        this.idManager = idManager;
         this.mdsalManager = mdsalManager;
-    }
-
-    public void setIfaceMgrRpcService(OdlInterfaceRpcService ifMgrRpcService) {
-        this.ifaceMgrRpcService = ifMgrRpcService;
-        interfaceListener.setIfaceMgrRpcService(ifMgrRpcService);
-    }
-
-    public void setFibManager(IFibManager fibManager) {
         this.fibManager = fibManager;
-    }
-
-    public IFibManager getFibManager() {
-        return this.fibManager;
-    }
-
-
-    public void setIdManager(IdManagerService idManager) {
-        this.idManager = idManager;
-        vpnSubnetRouteHandler.setIdManager(idManager);
-    }
-
-    public void setArpManager(OdlArputilService arpManager) {
-        this.arpManager = arpManager;
-    }
-
-    void setNotificationPublishService(NotificationPublishService notificationPublishService) {
+        this.ifaceMgrRpcService = ifaceMgrRpcService;
         this.notificationPublishService = notificationPublishService;
     }
 
-    public void setNeutronvpnManager(NeutronvpnService neuService) { this.neuService = neuService; }
-
-    public void setFibRpcService(FibRpcService fibService) {
-        this.fibService = fibService;
-    }
-
-    public FibRpcService getFibRpcService() {
-        return fibService;
+    public void start() {
+        LOG.info("{} start", getClass().getSimpleName());
+        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
-    public VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
-        return this.vpnSubnetRouteHandler;
+    @Override
+    protected InstanceIdentifier<VpnInterface> getWildCardPath() {
+        return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
     }
 
     @Override
-    public void close() throws Exception {
-        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");
+    protected VpnInterfaceManager getDataTreeChangeListener() {
+        return VpnInterfaceManager.this;
     }
 
-    private void registerListener(final DataBroker db) {
-        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);
-        }
-    }
 
     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> getInterfaceListenerPath() {
         return InstanceIdentifier.create(InterfacesState.class)
@@ -251,11 +193,12 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     @Override
     public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
         LOG.trace("VPN Interface add event - key: {}, value: {}" ,identifier, vpnInterface );
+        LOG.info("VPN Interface add event - intfName {}" ,vpnInterface.getName());
         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
         final String interfaceName = key.getName();
 
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
-                InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
+                InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
         if(interfaceState != null){
             try{
                 final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
@@ -265,35 +208,15 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                         new Callable<List<ListenableFuture<Void>>>() {
                             @Override
                             public List<ListenableFuture<Void>> call() throws Exception {
-                                WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
-                                WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
-                                                           WriteTransaction writeInvTxn = broker.newWriteOnlyTransaction();
+                                WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
+                                WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
+                                WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
                                 processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false, writeConfigTxn, writeOperTxn, writeInvTxn);
-                                CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
-                                try {
-                                    futures.get();
-                                } catch (InterruptedException | ExecutionException e) {
-                                    LOG.error("Error adding oper data for interface {} to vpn {} on dpn {}", interfaceName,
-                                            vpnInterface.getVpnInstanceName(), dpnId);
-                                    throw new RuntimeException(e.getMessage());
-                                }
-                                futures = writeConfigTxn.submit();
-                                try {
-                                    futures.get();
-                                } catch (InterruptedException | ExecutionException e) {
-                                                                       LOG.error("Error adding config data for interface {} to vpn {} on dpn {}", interfaceName,
-                                        vpnInterface.getVpnInstanceName(), dpnId);
-                                                                       throw new RuntimeException(e.getMessage());
-                                                               }
-                                                               futures = writeInvTxn.submit();
-                                                               try {
-                                                                       futures.get();
-                                                               } catch (InterruptedException | ExecutionException e) {
-                                                                       LOG.error("Error adding inventory/flow data for interface {} to vpn {} on dpn {}", interfaceName,
-                                        vpnInterface.getVpnInstanceName(), dpnId);
-                                                                       throw new RuntimeException(e.getMessage());   
-                                                               }
-                                                               return null;
+                                List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                                futures.add(writeOperTxn.submit());
+                                futures.add(writeConfigTxn.submit());
+                                futures.add(writeInvTxn.submit());
+                                return futures;
                             }
                         });
             }catch (Exception e){
@@ -309,19 +232,19 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                          final int lPortTag, boolean isInterfaceUp,
                                          WriteTransaction writeConfigTxn,
                                          WriteTransaction writeOperTxn,
-                                                                                WriteTransaction writeInvTxn) {
+                                         WriteTransaction writeInvTxn) {
 
         final String interfaceName = vpnInterface.getName();
         if (!isInterfaceUp) {
             final String vpnName = vpnInterface.getVpnInstanceName();
             LOG.info("Binding vpn service to interface {} ", interfaceName);
-            long vpnId = VpnUtil.getVpnId(broker, vpnName);
+            long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
             if (vpnId == VpnConstants.INVALID_ID) {
                 LOG.trace("VpnInstance to VPNId mapping is not yet available, bailing out now.");
                 return;
             }
             boolean waitForVpnInterfaceOpRemoval = false;
-            VpnInterface opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
+            VpnInterface opVpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, vpnInterface.getName());
             if (opVpnInterface != null ) {
                 String opVpnName = opVpnInterface.getVpnInstanceName();
                 String primaryInterfaceIp = null;
@@ -330,7 +253,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
                     // back to back
                     // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
-                    List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(broker, interfaceName);
+                    List<Adjacency> adjs = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker, interfaceName);
                     if (adjs == null) {
                         LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
                         return;
@@ -348,8 +271,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     }
                     // Get the rd of the vpn instance
                     String rd = getRouteDistinguisher(opVpnName);
-                                       rd =  (rd == null) ? opVpnName : rd;
-                    VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
+                    rd =  (rd == null) ? opVpnName : rd;
+                    VrfEntry vrf = VpnUtil.getVrfEntry(dataBroker, rd, primaryInterfaceIp);
                     if (vrf != null) {
                         LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
                         return;
@@ -370,7 +293,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
             // FIB didn't get a chance yet to clean up this VPNInterface
             // Let us give it a chance here !
-            LOG.info("VPN Interface {} waiting for FIB to clean up! ", interfaceName);
+            LOG.info("Trying to add VPN Interface {}, but waiting for FIB to clean up! ", interfaceName);
             try {
                 Runnable notifyTask = new VpnNotifyTask();
                 vpnIntfMap.put(interfaceName, notifyTask);
@@ -384,7 +307,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 vpnIntfMap.remove(interfaceName);
             }
 
-            opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
+            opVpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, interfaceName);
             if (opVpnInterface != null) {
                 LOG.error("VPN Interface {} removal by FIB did not complete on time, bailing addition ...", interfaceName);
                 return;
@@ -422,7 +345,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 //        public List<ListenableFuture<Void>> call() throws Exception {
 //            // If another renderer(for eg : CSS) needs to be supported, check can be performed here
 //            // to call the respective helpers.
-//            WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
+//            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
 //            updateDpnDbs(dpnId, vpnName, interfaceName, addToDpn, writeTxn);
 //            List<ListenableFuture<Void>> futures = new ArrayList<>();
 //            futures.add(writeTxn.submit());
@@ -460,7 +383,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 //         */
 //        @Override
 //        public void onSuccess(List<Void> voids) {
-//            WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
+//            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
 //            bindService(dpnId, vpnName, interfaceName, lPortTag, writeTxn);
 //            processVpnInterfaceAdjacencies(dpnId, vpnName, interfaceName, writeTxn);
 //            writeTxn.submit();
@@ -482,13 +405,15 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 //    }
 
 
+
+
     private void advertiseAdjacenciesForVpnToBgp(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier,
                                                  VpnInterface intf) {
         //Read NextHops
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+        Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
 
-        String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
+        String rd = VpnUtil.getVpnRd(dataBroker, intf.getVpnInstanceName());
         if (rd == null) {
             LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
                     intf.getName(), intf.getVpnInstanceName());
@@ -504,7 +429,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} in vpn {} with rd {} ", intf.getName(),
                 intf.getVpnInstanceName(), rd);
 
-        String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+        String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
         if (nextHopIp == null){
             LOG.trace("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} is null, returning", intf.getName());
             return;
@@ -533,9 +458,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
         //Read NextHops
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+        Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
 
-        String rd = VpnUtil.getVpnRd(broker, intf.getVpnInstanceName());
+        String rd = VpnUtil.getVpnRd(dataBroker, intf.getVpnInstanceName());
         if (rd == null) {
             LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
                     intf.getName(), intf.getVpnInstanceName());
@@ -568,8 +493,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    private void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
-        long vpnId = VpnUtil.getVpnId(broker, vpnName);
+    public void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String interfaceName, boolean add) {
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
         if (dpId == null) {
             dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, interfaceName);
         }
@@ -581,39 +506,66 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    private void bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag,
-                             WriteTransaction writeConfigTxn, WriteTransaction writeInvTxn) {
-        int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
-        long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
-
-        int instructionKey = 0;
-        List<Instruction> instructions = new ArrayList<Instruction>();
-
-        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(MetaDataUtil.getVpnIdMetadata(vpnId),
-                MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
-        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_FIB_TABLE, ++instructionKey));
-
-        BoundServices
-                serviceInfo =
-                InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
-                        NwConstants.L3VPN_SERVICE_INDEX, priority,
-                        NwConstants.COOKIE_VM_INGRESS_TABLE, instructions);
-        writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-                InterfaceUtils.buildServiceId(vpnInterfaceName, NwConstants.L3VPN_SERVICE_INDEX), serviceInfo, true);
-        makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW, writeInvTxn);
-        makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW, writeInvTxn);
+    private void bindService(BigInteger dpId, final String vpnInstanceName, final String vpnInterfaceName,
+                             int lPortTag, WriteTransaction writeConfigTxn, WriteTransaction writeInvTxn) {
+        final int priority = VpnConstants.DEFAULT_FLOW_PRIORITY;
+        final long vpnId = VpnUtil.getVpnId(dataBroker, vpnInstanceName);
+
+        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+        dataStoreCoordinator.enqueueJob(vpnInterfaceName,
+                new Callable<List<ListenableFuture<Void>>>() {
+                    @Override
+                    public List<ListenableFuture<Void>> call() throws Exception {
+                        WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+                        int instructionKey = 0;
+                        List<Instruction> instructions = new ArrayList<Instruction>();
+
+                        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(
+                                MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID, ++instructionKey));
+                        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.L3_GW_MAC_TABLE, ++instructionKey));
+
+                        BoundServices
+                                serviceInfo =
+                                InterfaceUtils.getBoundServices(String.format("%s.%s.%s", "vpn",vpnInstanceName, vpnInterfaceName),
+                                        ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX), priority,
+                                        NwConstants.COOKIE_VM_INGRESS_TABLE, instructions);
+                        writeTxn.put(LogicalDatastoreType.CONFIGURATION,
+                                InterfaceUtils.buildServiceId(vpnInterfaceName, ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)), serviceInfo, true);
+                        List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                        futures.add(writeTxn.submit());
+                        return futures;
+                    }
+                });
+        setupGwMacIfExternalVpn(dpId, vpnInterfaceName, vpnId, writeInvTxn, NwConstants.ADD_FLOW);
+    }
 
+    private void setupGwMacIfExternalVpn(BigInteger dpnId, String interfaceName, long vpnId,
+            WriteTransaction writeInvTxn, int addOrRemove) {
+        InstanceIdentifier<VpnIds> vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
+        Optional<VpnIds> vpnIdsOptional = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
+        if (vpnIdsOptional.isPresent() && vpnIdsOptional.get().isExternalVpn()) {
+            Optional<String> gwMacAddressOptional = InterfaceUtils.getMacAddressForInterface(dataBroker, interfaceName);
+            if (!gwMacAddressOptional.isPresent()) {
+                LOG.error("Failed to get gwMacAddress for interface {}", interfaceName);
+                return;
+            }
+            String gwMacAddress = gwMacAddressOptional.get();
+            FlowEntity flowEntity = VpnUtil.buildL3vpnGatewayFlow(dpnId, gwMacAddress, vpnId);
+            if (addOrRemove == NwConstants.ADD_FLOW) {
+                mdsalManager.addFlowToTx(flowEntity, writeInvTxn);
+            } else if (addOrRemove == NwConstants.DEL_FLOW) {
+                mdsalManager.removeFlowToTx(flowEntity, writeInvTxn);
+            }
+        }
     }
 
-    private void processVpnInterfaceAdjacencies(BigInteger dpnId, String vpnName, String interfaceName,
+    protected void processVpnInterfaceAdjacencies(BigInteger dpnId, String vpnName, String interfaceName,
                                                 WriteTransaction writeConfigTxn,
                                                 WriteTransaction writeOperTxn) {
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
         // Read NextHops
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+        Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
 
         if (adjacencies.isPresent()) {
             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
@@ -622,13 +574,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             // Get the rd of the vpn instance
             String rd = getRouteDistinguisher(vpnName);
 
-            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
             if (nextHopIp == null){
                 LOG.error("NextHop for interface {} is null", interfaceName);
                 return;
             }
 
-            List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+            List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
 
             LOG.trace("NextHops for interface {} are {}", interfaceName, nextHops);
             for (Adjacency nextHop : nextHops) {
@@ -636,6 +588,10 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                         VpnUtil.getNextHopLabelKey((rd == null) ? vpnName
                                 : rd, prefix));
+                if (label == VpnConstants.INVALID_LABEL) {
+                    LOG.error("Unable to fetch label from Id Manager. Bailing out of processing add/update of vpn interface {} for vpn {}", interfaceName, vpnName);
+                    return;
+                }
                 List<String> adjNextHop = nextHop.getNextHopIpList();
                 value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
                         (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
@@ -646,7 +602,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     writeOperTxn.merge(
                             LogicalDatastoreType.OPERATIONAL,
                             VpnUtil.getPrefixToInterfaceIdentifier(
-                                    VpnUtil.getVpnId(broker, vpnName), prefix),
+                                    VpnUtil.getVpnId(dataBroker, vpnName), prefix),
                             VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix), true);
                 } else {
                     //Extra route adjacency
@@ -664,115 +620,114 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             VpnInterface opInterface = VpnUtil.getVpnInterface(interfaceName, vpnName, aug, dpnId, Boolean.FALSE);
             InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
             writeOperTxn.put(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, true);
-            long vpnId = VpnUtil.getVpnId(broker, vpnName);
+            long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
 
             for (Adjacency nextHop : aug.getAdjacency()) {
                 long label = nextHop.getLabel();
-                List<String> nextHopList = new ArrayList<>(nextHop.getNextHopIpList());
                 if (rd != null) {
-                    addToLabelMapper(label, dpnId, nextHop.getIpAddress(), nextHopList, vpnId,
+                    addToLabelMapper(label, dpnId, nextHop.getIpAddress(), Arrays.asList(nextHopIp), vpnId,
                             interfaceName, null,false, rd, writeOperTxn);
                     addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label, writeConfigTxn);
                     //TODO: ERT - check for VPNs importing my route
-                    for (VpnInstance vpn : vpnsToImportRoute) {
-                        String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
+                    for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
+                        String vpnRd = vpn.getVrfId();
                         if (vpnRd != null) {
                             LOG.debug("Exporting route with rd {} prefix {} nexthop {} label {} to VPN {}", vpnRd, nextHop.getIpAddress(), nextHopIp, label, vpn);
-                            fibManager.addOrUpdateFibEntry(broker, vpnRd, nextHop.getIpAddress(), Arrays.asList(nextHopIp), (int) label,
+                            fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), Arrays.asList(nextHopIp), (int) label,
                                     RouteOrigin.SELF_IMPORTED, writeConfigTxn);
                         }
                     }
                 } else {
                     // ### add FIB route directly
-                    fibManager.addOrUpdateFibEntry(broker, vpnName, nextHop.getIpAddress(), Arrays.asList(nextHopIp),
+                    fibManager.addOrUpdateFibEntry(dataBroker, vpnName, nextHop.getIpAddress(), Arrays.asList(nextHopIp),
                             (int) label, RouteOrigin.STATIC, writeConfigTxn);
                 }
             }
         }
     }
 
-    private List<VpnInstance> getVpnsImportingMyRoute(final String vpnName) {
-        List<VpnInstance> vpnsToImportRoute = new ArrayList<>();
+    private List<VpnInstanceOpDataEntry> getVpnsImportingMyRoute(final String vpnName) {
+        List<VpnInstanceOpDataEntry> vpnsToImportRoute = new ArrayList<>();
 
-        InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
-                .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
-        Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-        final VpnInstance vpnInstance;
-        if (optVpnInstance.isPresent()) {
-            vpnInstance = optVpnInstance.get();
-        } else {
-            LOG.debug("Could not retrieve vpn instance {} to check for vpns importing the routes", vpnName);
+        final String vpnRd = VpnUtil.getVpnRd(dataBroker, vpnName);
+        final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker, vpnRd);
+        if (vpnInstanceOpDataEntry == null) {
+            LOG.debug("Could not retrieve vpn instance op data for {} to check for vpns importing the routes", vpnName);
             return vpnsToImportRoute;
         }
 
-        Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
+        Predicate<VpnInstanceOpDataEntry> excludeVpn = new Predicate<VpnInstanceOpDataEntry>() {
             @Override
-            public boolean apply(VpnInstance input) {
+            public boolean apply(VpnInstanceOpDataEntry input) {
+                if (input.getVpnInstanceName() == null) {
+                    LOG.error("Received vpn instance without identity");
+                    return false;
+                }
                 return !input.getVpnInstanceName().equals(vpnName);
             }
         };
 
-        Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
+        Predicate<VpnInstanceOpDataEntry> matchRTs = new Predicate<VpnInstanceOpDataEntry>() {
             @Override
-            public boolean apply(VpnInstance input) {
-                Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ExportExtcommunity),
+            public boolean apply(VpnInstanceOpDataEntry input) {
+                Iterable<String> commonRTs = intersection(getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ExportExtcommunity),
                         getRts(input, VpnTarget.VrfRTType.ImportExtcommunity));
                 return Iterators.size(commonRTs.iterator()) > 0;
             }
         };
 
-        Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
+        Function<VpnInstanceOpDataEntry, String> toInstanceName = new Function<VpnInstanceOpDataEntry, String>() {
             @Override
-            public String apply(VpnInstance vpnInstance) {
+            public String apply(VpnInstanceOpDataEntry vpnInstance) {
                 //return vpnInstance.getVpnInstanceName();
-                return vpnInstance.getIpv4Family().getRouteDistinguisher();
+                return vpnInstance.getVrfId();
             }
         };
 
-        vpnsToImportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
+        vpnsToImportRoute = FluentIterable.from(VpnUtil.getAllVpnInstanceOpData(dataBroker)).
                 filter(excludeVpn).
                 filter(matchRTs).toList();
         return vpnsToImportRoute;
     }
 
-    private List<VpnInstance> getVpnsExportingMyRoute(final String vpnName) {
-        List<VpnInstance> vpnsToExportRoute = new ArrayList<>();
+    private List<VpnInstanceOpDataEntry> getVpnsExportingMyRoute(final String vpnName) {
+        List<VpnInstanceOpDataEntry> vpnsToExportRoute = new ArrayList<>();
 
-        InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
-                .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
-        Optional<VpnInstance> optVpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-        final VpnInstance vpnInstance;
-        if (optVpnInstance.isPresent()) {
-            vpnInstance = optVpnInstance.get();
-        } else {
-            LOG.debug("Could not retrieve vpn instance {} to check for vpns exporting the routes", vpnName);
+        String vpnRd = VpnUtil.getVpnRd(dataBroker, vpnName);
+        final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker, vpnRd);
+        if (vpnInstanceOpDataEntry == null) {
+            LOG.debug("Could not retrieve vpn instance op data for {} to check for vpns exporting the routes", vpnName);
             return vpnsToExportRoute;
         }
 
-        Predicate<VpnInstance> excludeVpn = new Predicate<VpnInstance>() {
+        Predicate<VpnInstanceOpDataEntry> excludeVpn = new Predicate<VpnInstanceOpDataEntry>() {
             @Override
-            public boolean apply(VpnInstance input) {
+            public boolean apply(VpnInstanceOpDataEntry input) {
+                if (input.getVpnInstanceName() == null) {
+                    LOG.error("Received vpn instance without identity");
+                    return false;
+                }
                 return !input.getVpnInstanceName().equals(vpnName);
             }
         };
 
-        Predicate<VpnInstance> matchRTs = new Predicate<VpnInstance>() {
+        Predicate<VpnInstanceOpDataEntry> matchRTs = new Predicate<VpnInstanceOpDataEntry>() {
             @Override
-            public boolean apply(VpnInstance input) {
-                Iterable<String> commonRTs = intersection(getRts(vpnInstance, VpnTarget.VrfRTType.ImportExtcommunity),
+            public boolean apply(VpnInstanceOpDataEntry input) {
+                Iterable<String> commonRTs = intersection(getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ImportExtcommunity),
                         getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
                 return Iterators.size(commonRTs.iterator()) > 0;
             }
         };
 
-        Function<VpnInstance, String> toInstanceName = new Function<VpnInstance, String>() {
+        Function<VpnInstanceOpDataEntry, String> toInstanceName = new Function<VpnInstanceOpDataEntry, String>() {
             @Override
-            public String apply(VpnInstance vpnInstance) {
+            public String apply(VpnInstanceOpDataEntry vpnInstance) {
                 return vpnInstance.getVpnInstanceName();
             }
         };
 
-        vpnsToExportRoute = FluentIterable.from(VpnUtil.getAllVpnInstance(broker)).
+        vpnsToExportRoute = FluentIterable.from(VpnUtil.getAllVpnInstanceOpData(dataBroker)).
                 filter(excludeVpn).
                 filter(matchRTs).toList();
         return vpnsToExportRoute;
@@ -788,25 +743,20 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         };
     }
 
-    private List<String> getRts(VpnInstance vpnInstance, VpnTarget.VrfRTType rtType) {
+    private List<String> getRts(VpnInstanceOpDataEntry vpnInstance, VpnTarget.VrfRTType rtType) {
         String name = vpnInstance.getVpnInstanceName();
         List<String> rts = new ArrayList<>();
-        VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
-        if (vpnConfig == null) {
-            LOG.trace("vpn config is not available for {}", name);
-            return rts;
-        }
-        VpnTargets targets = vpnConfig.getVpnTargets();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargets targets = vpnInstance.getVpnTargets();
         if (targets == null) {
             LOG.trace("vpn targets not available for {}", name);
             return rts;
         }
-        List<VpnTarget> vpnTargets = targets.getVpnTarget();
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget> vpnTargets = targets.getVpnTarget();
         if (vpnTargets == null) {
             LOG.trace("vpnTarget values not available for {}", name);
             return rts;
         }
-        for (VpnTarget target : vpnTargets) {
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget target : vpnTargets) {
             //TODO: Check for RT type is Both
             if(target.getVrfRTType().equals(rtType) ||
                     target.getVrfRTType().equals(VpnTarget.VrfRTType.Both)) {
@@ -816,7 +766,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
         return rts;
     }
-
+    
     private List<String> getExportRts(VpnInstance vpnInstance) {
         List<String> exportRts = new ArrayList<>();
         VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
@@ -831,111 +781,97 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         return exportRts;
     }
 
-    private void makeArpFlow(BigInteger dpId,short sIndex, int lPortTag, String vpnInterfaceName,
-                             long vpnId, ArpReplyOrRequest replyOrRequest, int addOrRemoveFlow,
-                             WriteTransaction writeConfigTxn){
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, MetaDataUtil.getVpnIdMetadata(vpnId));
-        BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
-                MetaDataUtil.METADATA_MASK_LPORT_TAG, MetaDataUtil.METADATA_MASK_VRFID);
-
-        // Matching Arp reply flows
-        matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_ARP }));
-        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-                metadata, metadataMask }));
-
-        matches.add(new MatchInfo(MatchFieldType.arp_op, new long[] { replyOrRequest.getArpOperation() }));
-
-        // Instruction to punt to controller
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[] {}));
-        actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
-                Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
-
-        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
-
-        // Install the flow entry in L3_INTERFACE_TABLE
-        String flowRef = VpnUtil.getFlowRef(dpId, NwConstants.L3_INTERFACE_TABLE,
-                NwConstants.ETHTYPE_ARP, lPortTag, replyOrRequest.getArpOperation());
-        FlowEntity flowEntity;
-        flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_INTERFACE_TABLE, flowRef,
-                NwConstants.DEFAULT_ARP_FLOW_PRIORITY, replyOrRequest.getName(), 0, 0,
-                VpnUtil.getCookieArpFlow(lPortTag), matches, instructions);
-
-        Flow flow = flowEntity.getFlowBuilder().build();
-        String flowId = flowEntity.getFlowId();
-        FlowKey flowKey = new FlowKey( new FlowId(flowId));
-        Node nodeDpn = buildDpnNode(dpId);
-
-        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
-
-        if (writeConfigTxn != null) {
-            if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
-                LOG.debug("Creating ARP Flow for interface {}", vpnInterfaceName);
-                writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
-            } else {
-                LOG.debug("Deleting ARP Flow for interface {}", vpnInterfaceName);
-                writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
-            }
-        } else {
-            if (addOrRemoveFlow == NwConstants.ADD_FLOW) {
-                LOG.debug("Creating ARP Flow for interface {}",vpnInterfaceName);
-                mdsalManager.installFlow(flowEntity);
-            } else {
-                LOG.debug("Deleting ARP Flow for interface {}",vpnInterfaceName);
-                mdsalManager.removeFlow(flowEntity);
-            }
-        }
-    }
-
-    //TODO: How to handle the below code, its a copy paste from MDSALManager.java
-    private Node buildDpnNode(BigInteger dpnId) {
-        NodeId nodeId = new NodeId("openflow:" + dpnId);
-        Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
-
-        return nodeDpn;
-    }
-
     private String getRouteDistinguisher(String vpnName) {
         InstanceIdentifier<VpnInstance> id = InstanceIdentifier.builder(VpnInstances.class)
                 .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
-        Optional<VpnInstance> vpnInstance = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-        String rd = "";
+        Optional<VpnInstance> vpnInstance = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        String rd = null;
         if(vpnInstance.isPresent()) {
             VpnInstance instance = vpnInstance.get();
-            VpnAfConfig config = instance.getIpv4Family();
+            org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig config = instance.getIpv4Family();
             rd = config.getRouteDistinguisher();
         }
         return rd;
     }
 
+    /**
+     * JobCallback class is used as a future callback for
+     * main and rollback workers to handle success and failure.
+     */
+    private class DpnEnterExitVpnWorker implements FutureCallback<List<Void>> {
+        BigInteger dpnId;
+        String vpnName;
+        String rd;
+        boolean entered;
+
+        public DpnEnterExitVpnWorker(BigInteger dpnId, String vpnName, String rd, boolean entered) {
+            this.entered = entered;
+            this.dpnId = dpnId;
+            this.vpnName = vpnName;
+            this.rd = rd;
+        }
+
+        /**
+         * @param voids
+         * This implies that all the future instances have returned success. -- TODO: Confirm this
+         */
+        @Override
+        public void onSuccess(List<Void> voids) {
+            if (entered) {
+                publishAddNotification(dpnId, vpnName, rd);
+            } else {
+                publishRemoveNotification(dpnId, vpnName, rd);
+            }
+        }
+
+        /**
+         *
+         * @param throwable
+         * This method is used to handle failure callbacks.
+         * If more retry needed, the retrycount is decremented and mainworker is executed again.
+         * After retries completed, rollbackworker is executed.
+         * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
+         */
+        @Override
+        public void onFailure(Throwable throwable) {
+            LOG.warn("Job: failed with exception: {}", throwable.getStackTrace());
+        }
+    }
+
     private void createOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
         String routeDistinguisher = getRouteDistinguisher(vpnName);
         String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
         Boolean newDpnOnVpn = Boolean.FALSE;
-               
+
         synchronized (vpnName.intern()) {
-            WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
+            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
             InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
-            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data
                     .entry.vpn.to.dpn.list.VpnInterfaces
                     vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
 
             if (dpnInVpn.isPresent()) {
+                VpnToDpnList vpnToDpnList = dpnInVpn.get();
+                List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
+                        .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = vpnToDpnList.getVpnInterfaces();
+                if (vpnInterfaces == null) {
+                    vpnInterfaces = new ArrayList<>();
+                }
+                vpnInterfaces.add(vpnInterface);
+                VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
+                vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
+
                 if (writeTxn != null) {
-                    writeTxn.put(LogicalDatastoreType.OPERATIONAL, id.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
-                                    .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
-                            new VpnInterfacesKey(intfName)), vpnInterface, true);
+                    writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
                 } else {
-                    VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
-                                    .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
-                            new VpnInterfacesKey(intfName)), vpnInterface);
+                    VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build());
+                }
+                /* If earlier state was inactive, it is considered new DPN coming back to the
+                 * same VPN
+                 */
+                if (vpnToDpnList.getDpnState() == VpnToDpnList.DpnState.Inactive) {
+                    newDpnOnVpn = Boolean.TRUE;
                 }
             } else {
                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
@@ -947,7 +883,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 if (writeTxn != null) {
                     writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
                 } else {
-                    VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build());
+                    VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build());
                 }
                 newDpnOnVpn = Boolean.TRUE;
             }
@@ -958,25 +894,23 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 LOG.error("Error adding to dpnToVpnList for vpn {} interface {} dpn {}", vpnName, intfName, dpnId);
                 throw new RuntimeException(e.getMessage());
             }
-             /*
-            * Informing the Fib only after writeTxn is submitted successfuly.
-            */
-            if (newDpnOnVpn) {
-                LOG.debug("Sending populateFib event for new dpn {} in VPN {}", dpnId, vpnName);
-                fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
-                publishAddNotification(dpnId, vpnName, rd);
-            }
+        }
+        /*
+         * Informing the Fib only after writeTxn is submitted successfuly.
+         */
+        if (newDpnOnVpn) {
+            LOG.debug("Sending populateFib event for new dpn {} in VPN {}", dpnId, vpnName);
+            fibManager.populateFibOnNewDpn(dpnId, vpnId, rd, new DpnEnterExitVpnWorker(dpnId, vpnName, rd, true /* entered */));
         }
     }
 
     private void removeOrUpdateVpnToDpnList(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
         Boolean lastDpnOnVpn = Boolean.FALSE;
-
+        String rd = VpnUtil.getVpnRd(dataBroker, vpnName);
         synchronized (vpnName.intern()) {
-            String rd = VpnUtil.getVpnRd(broker, vpnName);
             InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
-            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-            WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
+            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
             if (dpnInVpn.isPresent()) {
                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
                         .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
@@ -994,7 +928,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                             if (writeTxn != null) {
                                 writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
                             } else {
-                                VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build());
+                                VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build());
                             }
                             lastDpnOnVpn = Boolean.TRUE;
                         } else {
@@ -1007,7 +941,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                             .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
                                     new VpnInterfacesKey(intfName)));
                         } else {
-                            VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+                            VpnUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
                                     org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
                                             .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
                                     new VpnInterfacesKey(intfName)), VpnUtil.DEFAULT_CALLBACK);
@@ -1022,20 +956,19 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 LOG.error("Error removing from dpnToVpnList for vpn {} interface {} dpn {}", vpnName, intfName, dpnId);
                 throw new RuntimeException(e.getMessage());
             }
-            if (lastDpnOnVpn) {
-                LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
-                fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
-                publishRemoveNotification(dpnId, vpnName, rd);
-            }
         }
-    }  
+        if (lastDpnOnVpn) {
+            LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
+            fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
+        }
+    }
 
     void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
-        List<VpnInstance> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
-        for (VpnInstance vpn : vpnsToExportRoute) {
-            String rd = vpn.getIpv4Family().getRouteDistinguisher();
-            List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, vpn.getIpv4Family().getRouteDistinguisher());
-            WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
+        List<VpnInstanceOpDataEntry> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
+        for (VpnInstanceOpDataEntry vpn : vpnsToExportRoute) {
+            String rd = vpn.getVrfId();
+            List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(dataBroker, vpn.getVrfId());
+            WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
             if (vrfEntries != null) {
                 for (VrfEntry vrfEntry : vrfEntries) {
                     try {
@@ -1049,10 +982,10 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                         for (String nh : nextHops) {
                             if (route != null) {
                                 LOG.info("Importing subnet route fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
-                                importSubnetRouteForNewVpn(rd, prefix, nh, (int)label, route, writeConfigTxn);
+                                importSubnetRouteForNewVpn(vpnRd, prefix, nh, (int)label, route, writeConfigTxn);
                             } else {
                                 LOG.info("Importing fib entry rd {} prefix {} nexthop {} label {} to vpn {}", vpnRd, prefix, nh, label, vpn.getVpnInstanceName());
-                                fibManager.addOrUpdateFibEntry(broker, vpnRd, prefix, Arrays.asList(nh), (int)label,
+                                fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, prefix, Arrays.asList(nh), (int)label,
                                         RouteOrigin.SELF_IMPORTED, writeConfigTxn);
                             }
                         }
@@ -1062,7 +995,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 }
                 writeConfigTxn.submit();
             } else {
-                LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getIpv4Family().getRouteDistinguisher());
+                LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getVrfId());
             }
         }
     }
@@ -1070,7 +1003,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label, WriteTransaction writeConfigTxn) {
         try {
             LOG.info("ADD: Adding Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
-            fibManager.addOrUpdateFibEntry(broker, rd, prefix, Arrays.asList(nextHopIp), (int)label, RouteOrigin.STATIC, writeConfigTxn);
+            fibManager.addOrUpdateFibEntry(dataBroker, rd, prefix, Arrays.asList(nextHopIp), (int)label, RouteOrigin.STATIC, writeConfigTxn);
             bgpManager.advertisePrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label);
             LOG.info("ADD: Added Fib entry rd {} prefix {} nextHop {} label {}", rd, prefix, nextHopIp, label);
         } catch(Exception e) {
@@ -1078,21 +1011,17 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-
-    private InstanceIdentifier<VpnInterface> getWildCardPath() {
-        return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
-    }
-
     @Override
     public void remove( InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
         LOG.trace("Remove event - key: {}, value: {}" ,identifier, vpnInterface );
+        LOG.info("VPN Interface remove event - intfName {}" ,vpnInterface.getName());
         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
         final String interfaceName = key.getName();
 
         InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
-        final Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
+        final Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, interfaceId);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState =
-                InterfaceUtils.getInterfaceStateFromOperDS(broker, interfaceName);
+                InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
         if (optVpnInterface.isPresent()){
             BigInteger dpnId = BigInteger.ZERO;
             Boolean dpnIdRetrieved = Boolean.FALSE;
@@ -1119,35 +1048,15 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
-                            WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
-                            WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
-                            WriteTransaction writeInvTxn = broker.newWriteOnlyTransaction();
+                            WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
+                            WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
+                            WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
                             processVpnInterfaceDown(dpId, interfaceName, ifIndex, false, true, writeConfigTxn, writeOperTxn, writeInvTxn);
-                            CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
-                            try {
-                                futures.get();
-                            } catch (InterruptedException | ExecutionException e) {
-                                LOG.error("Error removing Oper data for interface {} from vpn {} on dpn {}", interfaceName,
-                                        vpnOpInterface.getVpnInstanceName(), dpId);
-                                throw new RuntimeException(e.getMessage());
-                            }
-                            futures = writeConfigTxn.submit();
-                            try {
-                                futures.get();
-                            } catch (InterruptedException | ExecutionException e) {
-                                LOG.error("Error removing Config data for interface {} from vpn {} on dpn {}", interfaceName,
-                                        vpnOpInterface.getVpnInstanceName(), dpId);
-                                throw new RuntimeException(e.getMessage());
-                            }
-                            futures = writeInvTxn.submit();
-                            try {
-                                futures.get();
-                            } catch (InterruptedException | ExecutionException e) {
-                                LOG.error("Error removing Inventory/Flow data for interface {} from vpn {} on dpn {}", interfaceName,
-                                        vpnOpInterface.getVpnInstanceName(), dpId);
-                                throw new RuntimeException(e.getMessage());
-                                                       }
-                            return null;
+                            List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                            futures.add(writeOperTxn.submit());
+                            futures.add(writeConfigTxn.submit());
+                            futures.add(writeInvTxn.submit());
+                            return futures;
                         }
                     });
 
@@ -1156,24 +1065,24 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    protected void processVpnInterfaceDown(BigInteger dpId, 
-                                                                                  String interfaceName, 
-                                                                                  int lPortTag, 
-                                                                                  boolean isInterfaceStateDown,
-                                           boolean isConfigRemoval, 
-                                                                                  WriteTransaction writeConfigTxn, 
-                                                                                  WriteTransaction writeOperTxn,
-                                                                                  WriteTransaction writeInvTxn) {
+    protected void processVpnInterfaceDown(BigInteger dpId,
+                                           String interfaceName,
+                                           int lPortTag,
+                                           boolean isInterfaceStateDown,
+                                           boolean isConfigRemoval,
+                                           WriteTransaction writeConfigTxn,
+                                           WriteTransaction writeOperTxn,
+                                           WriteTransaction writeInvTxn) {
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
         if (!isInterfaceStateDown) {
-            VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
+            VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, interfaceName);
             if(vpnInterface == null){
                 LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
                 return;
             }else{
                 final String vpnName = vpnInterface.getVpnInstanceName();
                 if(!vpnInterface.isScheduledForRemove()){
-                    VpnUtil.scheduleVpnInterfaceForRemoval(broker, interfaceName, dpId, vpnName, Boolean.TRUE, writeOperTxn);
+                    VpnUtil.scheduleVpnInterfaceForRemoval(dataBroker, interfaceName, dpId, vpnName, Boolean.TRUE, writeOperTxn);
                     removeAdjacenciesFromVpn(dpId, interfaceName, vpnInterface.getVpnInstanceName(), writeConfigTxn);
                     LOG.info("Unbinding vpn service from interface {} ", interfaceName);
                     unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown, isConfigRemoval, writeConfigTxn, writeInvTxn);
@@ -1185,7 +1094,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         } else {
             // Interface is retained in the DPN, but its Link Down.
             // Only withdraw the prefixes for this interface from BGP
-            VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
+            VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, interfaceName);
             if(vpnInterface == null){
                 LOG.info("Unable to withdraw adjacencies for vpn interface {} from BGP as it is not available in operational data store", interfaceName);
                 return;
@@ -1218,9 +1127,9 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         //Read NextHops
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+        Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
 
-        String rd = VpnUtil.getVpnRd(broker, vpnName);
+        String rd = VpnUtil.getVpnRd(dataBroker, vpnName);
         LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", interfaceName,
                 vpnName, rd);
         if (adjacencies.isPresent()) {
@@ -1232,7 +1141,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     List<String> nhList = new ArrayList<String>();
                     if (nextHop.getMacAddress() == null || nextHop.getMacAddress().isEmpty()) {
                         // This is either an extra-route (or) a learned IP via subnet-route
-                        String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+                        String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
                         if (nextHopIp == null || nextHopIp.isEmpty()) {
                             LOG.error("Unable to obtain nextHopIp for extra-route/learned-route in rd {} prefix {}",
                                     rd, nextHop.getIpAddress());
@@ -1247,29 +1156,29 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                         //this is an internal vpn - the rd is assigned to the vpn instance name;
                         //remove from FIB directly
                         for(String nh : nhList) {
-                            fibManager.removeOrUpdateFibEntry(broker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
+                            fibManager.removeOrUpdateFibEntry(dataBroker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
                         }
                     } else {
-                        List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+                        List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
                         for (String nh : nhList) {
                             //IRT: remove routes from other vpns importing it
                             removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
-                            for (VpnInstance vpn : vpnsToImportRoute) {
-                                String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
+                            for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
+                                String vpnRd = vpn.getVrfId();
                                 if (vpnRd != null) {
                                     LOG.info("Removing Exported route with rd {} prefix {} from VPN {}", vpnRd, nextHop.getIpAddress(), vpn.getVpnInstanceName());
-                                    fibManager.removeOrUpdateFibEntry(broker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
+                                    fibManager.removeOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
                                 }
                             }
                         }
                     }
                     String ip = nextHop.getIpAddress().split("/")[0];
-                    VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
+                    VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker,
                             vpnName, ip);
                     if (vpnPortipToPort != null && !vpnPortipToPort.isConfig()) {
                         LOG.trace("VpnInterfaceManager removing adjacency for Interface {} ip {} from VpnPortData Entry",
                                 vpnPortipToPort.getPortName(),ip);
-                        VpnUtil.removeVpnPortFixedIpToPort(broker, vpnName, ip);
+                        VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip);
                     }
                 }
             }
@@ -1277,26 +1186,36 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     }
 
 
-    private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
+    private void unbindService(BigInteger dpId, String vpnInstanceName, final String vpnInterfaceName,
                                int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval,
                                WriteTransaction writeConfigTxn, WriteTransaction writeInvTxn) {
+        short l3vpn_service_index = ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX);
         if (!isInterfaceStateDown && isConfigRemoval) {
-            writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION,
-                    InterfaceUtils.buildServiceId(vpnInterfaceName,
-                            NwConstants.L3VPN_SERVICE_INDEX));
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob(vpnInterfaceName,
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+                            writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
+                                    InterfaceUtils.buildServiceId(vpnInterfaceName,
+                                            ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)));
+
+                            List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                            futures.add(writeTxn.submit());
+                            return futures;
+                        }
+                    });
         }
-        long vpnId = VpnUtil.getVpnId(broker, vpnInstanceName);
-        makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW, writeInvTxn);
-        makeArpFlow(dpId, NwConstants.L3VPN_SERVICE_INDEX, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW, writeInvTxn);
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnInstanceName);
+        setupGwMacIfExternalVpn(dpId, vpnInterfaceName, vpnId, writeConfigTxn, NwConstants.DEL_FLOW);
     }
 
 
     private void removePrefixFromBGP(String rd, String prefix, String nextHop, WriteTransaction writeConfigTxn) {
         try {
             LOG.info("VPN WITHDRAW: Removing Fib Entry rd {} prefix {}", rd, prefix);
-            fibManager.removeOrUpdateFibEntry(broker, rd, prefix, nextHop, writeConfigTxn);
+            fibManager.removeOrUpdateFibEntry(dataBroker, rd, prefix, nextHop, writeConfigTxn);
             bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
             LOG.info("VPN WITHDRAW: Removed Fib Entry rd {} prefix {}", rd, prefix);
         } catch(Exception e) {
@@ -1307,16 +1226,19 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     @Override
     protected void update(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
         LOG.trace("Updating VPN Interface : key {},  original value={}, update value={}", identifier, original, update);
+        LOG.info("VPN Interface update event - intfName {}" ,update.getName());
         String oldVpnName = original.getVpnInstanceName();
         String newVpnName = update.getVpnInstanceName();
         BigInteger dpnId = update.getDpnId();
-        List<Adjacency> oldAdjs = original.getAugmentation(Adjacencies.class).getAdjacency();
-        List<Adjacency> newAdjs = update.getAugmentation(Adjacencies.class).getAdjacency();
-        if (oldAdjs == null) {
-            oldAdjs = new ArrayList<>();
+        List<Adjacency> oldAdjsList = new ArrayList<>();
+        List<Adjacency> newAdjsList = new ArrayList<>();
+        Adjacencies oldAdjs = original.getAugmentation(Adjacencies.class);
+        Adjacencies newAdjs = update.getAugmentation(Adjacencies.class);
+        if (oldAdjs != null) {
+            oldAdjsList = oldAdjs.getAdjacency();
         }
-        if (newAdjs == null) {
-            newAdjs = new ArrayList<>();
+        if (newAdjs != null) {
+            newAdjsList = newAdjs.getAdjacency();
         }
         //handles switching between <internal VPN - external VPN>
         if (!oldVpnName.equals(newVpnName)) {
@@ -1326,16 +1248,16 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
         //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);
+        if (!oldAdjsList.equals(newAdjsList)) {
+            for (Adjacency adj : newAdjsList) {
+                if (oldAdjsList.contains(adj)) {
+                    oldAdjsList.remove(adj);
                 } else {
                     // add new adjacency - right now only extra route will hit this path
-                    addNewAdjToVpnInterface(identifier, adj, dpnId);
+                    addNewAdjToVpnInterface(identifier, adj);
                 }
             }
-            for (Adjacency adj : oldAdjs) {
+            for (Adjacency adj : oldAdjsList) {
                 delAdjFromVpnInterface(identifier, adj, dpnId);
             }
         }
@@ -1400,7 +1322,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 lriBuilder.setVpnInterfaceName(vpnInterfaceName);
             }
             lriBuilder.setParentVpnRd(rd);
-            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, rd);
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker, rd);
             if (vpnInstanceOpDataEntry != null) {
                 List<String> vpnInstanceNames = Arrays.asList(vpnInstanceOpDataEntry.getVpnInstanceName());
                 lriBuilder.setVpnInstanceList(vpnInstanceNames);
@@ -1410,14 +1332,14 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             if (writeOperTxn != null) {
                 writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, lriIid, lri, true);
             } else {
-                VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
+                VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
             }
         } else {
             LOG.trace("Can't add entry to label map for lable {},dpnId is null", label);
         }
     }
 
-    public synchronized void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
+    public void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
                                                         long elantag, BigInteger dpnId, WriteTransaction writeTxn) {
         SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
         RouteOrigin origin = RouteOrigin.STATIC; // Only case when a route is considered as directly connected
@@ -1428,7 +1350,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nextHop, label, elantag);
 
         //TODO: What should be parentVpnId? Get it from RD?
-        long vpnId = VpnUtil.getVpnId(broker, vpnName);
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
         addToLabelMapper((long)label, dpnId, prefix, Arrays.asList(nextHop), vpnId, null, elantag, true, rd, null);
         List<VrfEntry> vrfEntryList = Arrays.asList(vrfEntry);
 
@@ -1442,24 +1364,24 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         if (writeTxn != null) {
             writeTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
         } else {
-            VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
+            VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
         }
 
-        List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+        List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
         if (vpnsToImportRoute.size() > 0) {
             VrfEntry importingVrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
                     .setLabel((long) label).setOrigin(RouteOrigin.SELF_IMPORTED.getValue())
                     .addAugmentation(SubnetRoute.class, route).build();
             List<VrfEntry> importingVrfEntryList = Arrays.asList(importingVrfEntry);
-            for (VpnInstance vpnInstance : vpnsToImportRoute) {
+            for (VpnInstanceOpDataEntry vpnInstance : vpnsToImportRoute) {
                 LOG.info("Exporting subnet route rd {} prefix {} nexthop {} label {} to vpn {}", rd, prefix, nextHop, label, vpnInstance.getVpnInstanceName());
-                String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
+                String importingRd = vpnInstance.getVrfId();
                 InstanceIdentifier<VrfTables> importingVrfTableId = InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(importingRd)).build();
                 VrfTables importingVrfTable = new VrfTablesBuilder().setRouteDistinguisher(importingRd).setVrfEntry(importingVrfEntryList).build();
                 if (writeTxn != null) {
                     writeTxn.merge(LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable, true);
                 } else {
-                    VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
+                    VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
                 }
             }
         }
@@ -1482,34 +1404,38 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         if (writeConfigTxn != null) {
             writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
         } else {
-            VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
+            VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
         }
     }
 
-    public synchronized void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
-        fibManager.removeOrUpdateFibEntry(broker, rd, prefix, null /* nextHopToRemove */, null);
-        List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
-        for (VpnInstance vpnInstance : vpnsToImportRoute) {
-            String importingRd = vpnInstance.getIpv4Family().getRouteDistinguisher();
+    public void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
+        fibManager.removeFibEntry(dataBroker, rd, prefix, null);
+        List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+        for (VpnInstanceOpDataEntry vpnInstance : vpnsToImportRoute) {
+            String importingRd = vpnInstance.getVrfId();
             LOG.info("Deleting imported subnet route rd {} prefix {} from vpn {}", rd, prefix, vpnInstance.getVpnInstanceName());
-            fibManager.removeOrUpdateFibEntry(broker, importingRd, prefix, null /* nextHopToRemove */, null);
+            fibManager.removeFibEntry(dataBroker, importingRd, prefix, null);
         }
     }
 
-    protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
+    protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
 
-        Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+        Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
 
         if (optVpnInterface.isPresent()) {
             VpnInterface currVpnIntf = optVpnInterface.get();
             String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
             String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
+            rd = (rd != null) ? rd : currVpnIntf.getVpnInstanceName();
             InstanceIdentifier<Adjacencies> adjPath = identifier.augmentation(Adjacencies.class);
-            Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, adjPath);
+            Optional<Adjacencies> optAdjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, adjPath);
             long label =
                     VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
-                            VpnUtil.getNextHopLabelKey((rd != null) ? rd : currVpnIntf.getVpnInstanceName(), prefix));
-
+                            VpnUtil.getNextHopLabelKey(rd, prefix));
+            if (label == 0) {
+                LOG.error("Unable to fetch label from Id Manager. Bailing out of adding new adjacency {} to vpn interface {} for vpn {}", adj.getIpAddress(), currVpnIntf.getName(), currVpnIntf.getVpnInstanceName());
+                return;
+            }
             List<Adjacency> adjacencies;
             if (optAdjacencies.isPresent()) {
                 adjacencies = optAdjacencies.get().getAdjacency();
@@ -1519,32 +1445,45 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             }
 
             adjacencies.add(new AdjacencyBuilder(adj).setLabel(label).setNextHopIpList(adj.getNextHopIpList())
-                    .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
-
+                    .setIpAddress(prefix).setMacAddress(adj.getMacAddress()).setKey(new AdjacencyKey(prefix)).build());
+            
             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
-            VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug, dpnId, currVpnIntf.isScheduledForRemove());
-
-            VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
-            for (String nh : adj.getNextHopIpList()) {
-                addExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(), (int) label,
-                        currVpnIntf.getName());
+            VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(), aug, currVpnIntf.getDpnId(), currVpnIntf.isScheduledForRemove());
+
+            VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
+            
+            if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
+                LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, currVpnIntf.getName(), currVpnIntf.getVpnInstanceName());
+                VpnUtil.syncUpdate( dataBroker,
+                        LogicalDatastoreType.OPERATIONAL,
+                        VpnUtil.getPrefixToInterfaceIdentifier(
+                                VpnUtil.getVpnId(dataBroker, currVpnIntf.getVpnInstanceName()), prefix),
+                        VpnUtil.getPrefixToInterface(currVpnIntf.getDpnId(), currVpnIntf.getName(), prefix));
+            }
+                      
+            if (adj.getNextHopIpList() != null) {
+                for (String nh : adj.getNextHopIpList()) {
+                    addExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(), (int) label,
+                            currVpnIntf.getName());
+                }
             }
         }
     }
 
     protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj, BigInteger dpnId) {
-        Optional<VpnInterface> optVpnInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
+        Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
 
         if (optVpnInterface.isPresent()) {
             VpnInterface currVpnIntf = optVpnInterface.get();
 
             InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-            Optional<Adjacencies> optAdjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
+            Optional<Adjacencies> optAdjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
             if (optAdjacencies.isPresent()) {
                 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
 
                 if (!adjacencies.isEmpty()) {
                     String rd = getRouteDistinguisher(currVpnIntf.getVpnInstanceName());
+                    rd = (rd != null) ? rd :currVpnIntf.getVpnInstanceName();
                     LOG.trace("Adjacencies are " + adjacencies);
                     Iterator<Adjacency> adjIt = adjacencies.iterator();
                     while (adjIt.hasNext()) {
@@ -1557,11 +1496,13 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                     currVpnIntf.getVpnInstanceName(),
                                     aug, dpnId, currVpnIntf.isScheduledForRemove());
 
-                            VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
+                            VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier, newVpnIntf);
 
-                            for (String nh : adj.getNextHopIpList()) {
-                                delExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(),
-                                        currVpnIntf.getName());
+                            if (adj.getNextHopIpList() != null) {
+                                for (String nh : adj.getNextHopIpList()) {
+                                    delExtraRoute(adj.getIpAddress(), nh, rd, currVpnIntf.getVpnInstanceName(),
+                                            currVpnIntf.getName());
+                                }
                             }
                             break;
                         }
@@ -1578,7 +1519,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
         //add extra route to vpn mapping; advertise with nexthop as tunnel ip
         VpnUtil.syncUpdate(
-                broker,
+                dataBroker,
                 LogicalDatastoreType.OPERATIONAL,
                 VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
                 VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
@@ -1586,7 +1527,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         BigInteger dpnId = null;
         if (intfName != null && !intfName.isEmpty()) {
             dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
-            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
             if (nextHopIp == null || nextHopIp.isEmpty()) {
                 LOG.error("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
                         intfName, destination);
@@ -1597,15 +1538,16 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         List<String> nextHopIpList = Arrays.asList(nextHop);
         if (rd != null) {
             /* Label mapper is required only for BGP VPN and not for Internal VPN */
-            addToLabelMapper((long) label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(broker, routerID),
+            addToLabelMapper((long) label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(dataBroker, routerID),
                     intfName, null, false, rd, null);
         }
 
         // TODO (eperefr): This is a limitation to be stated in docs. When configuring static route to go to
         // another VPN, there can only be one nexthop or, at least, the nexthop to the interVpnLink should be in
         // first place.
-        InterVpnLink interVpnLink = VpnUtil.getInterVpnLinkByEndpointIp(broker, nextHop);
-        if ( interVpnLink != null ) {
+        Optional<InterVpnLink> optInterVpnLink = InterVpnLinkUtil.getInterVpnLinkByEndpointIp(dataBroker, nextHop);
+        if ( optInterVpnLink.isPresent() ) {
+            InterVpnLink interVpnLink = optInterVpnLink.get();
             // If the nexthop is the endpoint of Vpn2, then prefix must be advertised to Vpn1 in DC-GW, with nexthops
             // pointing to the DPNs where Vpn1 is instantiated. LFIB in these DPNS must have a flow entry, with lower
             // priority, where if Label matches then sets the lportTag of the Vpn2 endpoint and goes to LportDispatcher
@@ -1615,24 +1557,28 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
             String dstVpnUuid = (nexthopIsVpn2) ? interVpnLink.getFirstEndpoint().getVpnUuid().getValue()
                     : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
-            String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
+            String dstVpnRd = VpnUtil.getVpnRd(dataBroker, dstVpnUuid);
             long newLabel = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                     VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
-            VpnUtil.leakRoute(broker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
+            if (newLabel == 0) {
+                LOG.error("Unable to fetch label from Id Manager. Bailing out of adding intervpnlink route for destination {}", destination);
+                return;
+            }
+            InterVpnLinkUtil.leakRoute(dataBroker, bgpManager, interVpnLink, srcVpnUuid, dstVpnUuid, destination, newLabel);
         } else {
             if (rd != null) {
                 addPrefixToBGP(rd, destination, nextHop, label, null);
             } else {
                 // ### add FIB route directly
-                fibManager.addOrUpdateFibEntry(broker, routerID, destination, Arrays.asList(nextHop), label, RouteOrigin.STATIC, null);
+                fibManager.addOrUpdateFibEntry(dataBroker, routerID, destination, Arrays.asList(nextHop), label, RouteOrigin.STATIC, null);
             }
         }
     }
-
     protected void delExtraRoute(String destination, String nextHop, String rd, String routerID, String intfName) {
         if (intfName != null && !intfName.isEmpty()) {
             BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, intfName);
-            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
+            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
             if (nextHopIp == null || nextHopIp.isEmpty()) {
                 LOG.warn("NextHop for interface {} is null / empty. Failed advertising extra route for prefix {}",
                         intfName, destination);
@@ -1644,184 +1590,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             removePrefixFromBGP(rd, destination, nextHop, null);
         } else {
             // ### add FIB route directly
-            fibManager.removeOrUpdateFibEntry(broker, routerID, destination, nextHop, null);
-        }
-    }
-
-    class VpnInterfaceOpListener extends org.opendaylight.genius.mdsalutil.AbstractDataChangeListener<VpnInterface> {
-
-        public VpnInterfaceOpListener() {
-            super(VpnInterface.class);
-        }
-
-        @Override
-        protected void remove(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface del) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            final String interfaceName = key.getName();
-            final String vpnName = del.getVpnInstanceName();
-            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
-                    new Callable<List<ListenableFuture<Void>>>() {
-                        @Override
-                        public List<ListenableFuture<Void>> call() throws Exception {
-                            WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
-                            postProcessVpnInterfaceRemoval(identifier, del, writeOperTxn);
-                            CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
-                            try {
-                                futures.get();
-                            } catch (InterruptedException | ExecutionException e) {
-                                LOG.error("Error handling removal of oper data for interface {} from vpn {}", interfaceName,
-                                        vpnName);
-                                throw new RuntimeException(e.getMessage());
-                            }
-                            return null;
-                        }
-                    });
-        }
-
-        private void postProcessVpnInterfaceRemoval(InstanceIdentifier<VpnInterface> identifier, VpnInterface del,
-                                                    WriteTransaction writeOperTxn) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            String interfaceName = key.getName();
-            String vpnName = del.getVpnInstanceName();
-
-            LOG.trace("VpnInterfaceOpListener removed: interface name {} vpnName {}", interfaceName, vpnName);
-            //decrement the vpn interface count in Vpn Instance Op Data
-            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
-                    .vpn.id.VpnInstance>
-                    id = VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnName);
-            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
-                    .VpnInstance> vpnInstance
-                    = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-
-            if (vpnInstance.isPresent()) {
-                String rd = null;
-                rd = vpnInstance.get().getVrfId();
-                //String rd = getRouteDistinguisher(del.getVpnInstanceName());
-
-                VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
-                LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} in Vpn Op Instance {}",
-                        interfaceName, rd, vpnName, vpnInstOp);
-
-                if (vpnInstOp != null) {
-                    // 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);
-                    List<Prefixes> prefixToInterface = new ArrayList<>();
-                    Optional<Prefixes> prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                            VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                    VpnUtil.getIpPrefix(adjacency.getIpAddress())));
-                    if (prefix.isPresent()) {
-                        prefixToInterface.add(prefix.get());
-                    }
-                    if (prefixToInterface.isEmpty()) {
-                        for (String nh : adjacency.getNextHopIpList()) {
-                            prefix = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                                    VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                            VpnUtil.getIpPrefix(nh)));
-                            if (prefix.isPresent())
-                                prefixToInterface.add(prefix.get());
-                        }
-                    }
-                    for (Prefixes pref : prefixToInterface) {
-                        if (writeOperTxn != null) {
-                            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                                    VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()));
-                        } else {
-                            VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-                                    VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()),
-                                    VpnUtil.DEFAULT_CALLBACK);
-                        }
-                        updateVpnToDpnMapping(pref.getDpnId(), del.getVpnInstanceName(), interfaceName, false /* delete */);
-                    }
-                }
-            } else {
-                LOG.error("rd not retrievable as vpninstancetovpnid for vpn {} is absent, trying rd as ", vpnName, vpnName);
-            }
-            notifyTaskIfRequired(interfaceName);
-        }
-
-        private void notifyTaskIfRequired(String intfName) {
-            Runnable notifyTask = vpnIntfMap.remove(intfName);
-            if (notifyTask == null) {
-                LOG.trace("VpnInterfaceOpListener update: No Notify Task queued for vpnInterface {}", intfName);
-                return;
-            }
-            executorService.execute(notifyTask);
-        }
-
-        @Override
-        protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
-                              final VpnInterface update) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            final String interfaceName = key.getName();
-
-            if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
-                return;
-            }
-
-            final String vpnName = update.getVpnInstanceName();
-            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
-                    new Callable<List<ListenableFuture<Void>>>() {
-                        @Override
-                        public List<ListenableFuture<Void>> call() throws Exception {
-                            postProcessVpnInterfaceUpdate(identifier, original, update);
-                            return null;
-                        }
-                    });
-        }
-
-        private void postProcessVpnInterfaceUpdate(InstanceIdentifier<VpnInterface> identifier, VpnInterface original,
-                                                   VpnInterface update) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            String interfaceName = key.getName();
-
-            //increment the vpn interface count in Vpn Instance Op Data
-            VpnInstanceOpDataEntry vpnInstOp = null;
-            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
-                    .vpn.id.VpnInstance>
-                    origId = VpnUtil.getVpnInstanceToVpnIdIdentifier(original.getVpnInstanceName());
-            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
-                    .VpnInstance> origVpnInstance
-                    = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, origId);
-
-            if (origVpnInstance.isPresent()) {
-                String rd = null;
-                rd = origVpnInstance.get().getVrfId();
-
-                vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
-                LOG.trace("VpnInterfaceOpListener updated: interface name {} original rd {} original vpnName {}",
-                        interfaceName, rd, original.getVpnInstanceName());
-
-                if (vpnInstOp != null) {
-                    Adjacency adjacency = original.getAugmentation(Adjacencies.class).getAdjacency().get(0);
-                    List<Prefixes> prefixToInterfaceList = new ArrayList<>();
-                    Optional<Prefixes> prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                            VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                    VpnUtil.getIpPrefix(adjacency.getIpAddress())));
-                    if (prefixToInterface.isPresent()) {
-                        prefixToInterfaceList.add(prefixToInterface.get());
-                    } else {
-                        for (String adj : adjacency.getNextHopIpList()) {
-                            prefixToInterface = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
-                                    VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-                                            VpnUtil.getIpPrefix(adj)));
-                            if (prefixToInterface.isPresent()) {
-                                prefixToInterfaceList.add(prefixToInterface.get());
-                            }
-                        }
-                    }
-                    for (Prefixes prefix : prefixToInterfaceList) {
-                        updateVpnToDpnMapping(prefix.getDpnId(), original.getVpnInstanceName(), interfaceName, false /* delete */);
-                    }
-                }
-            }
-            notifyTaskIfRequired(interfaceName);
-        }
-
-        @Override
-        protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
+            fibManager.removeOrUpdateFibEntry(dataBroker, routerID, destination, nextHop, null);
         }
     }
 
@@ -1880,7 +1649,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
 
-        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(dataBroker, LogicalDatastoreType
                 .OPERATIONAL, routerDpnListIdentifier);
         RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
         if (optionalRouterDpnList.isPresent()) {
@@ -1906,7 +1675,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             return;
         }
         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
-        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(dataBroker, LogicalDatastoreType
                 .OPERATIONAL, routerDpnListIdentifier);
         if (optionalRouterDpnList.isPresent()) {
             List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
@@ -1917,7 +1686,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                     if (writeOperTxn != null) {
                         writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
                     } else {
-                        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+                        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
                     }
                 } else {
                     if (writeOperTxn != null) {
@@ -1925,7 +1694,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                                 RouterInterfaces.class,
                                 new RouterInterfacesKey(vpnInterfaceName)));
                     } else {
-                        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
+                        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
                                 RouterInterfaces.class,
                                 new RouterInterfacesKey(vpnInterfaceName)));
                     }
@@ -1941,7 +1710,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             return;
         }
         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
-        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(broker, LogicalDatastoreType
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = VpnUtil.read(dataBroker, LogicalDatastoreType
                 .OPERATIONAL, routerDpnListIdentifier);
         if (optionalRouterDpnList.isPresent()) {
             List<RouterInterfaces> routerInterfaces = optionalRouterDpnList.get().getRouterInterfaces();
@@ -1958,58 +1727,11 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    public void addMIPAdjacency(String vpnName,String vpnInterface, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
-            .ns.yang.ietf.inet.types.rev130715.IpAddress prefix){
-
-        LOG.trace("Adding {} adjacency to VPN Interface {} ",prefix,vpnInterface);
-        InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
-        InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
-        String nextHopIpAddr = null;
-        String nextHopMacAddress = null;
-        String ip = prefix.getIpv4Address().getValue();
-        if (adjacencies.isPresent()) {
-            List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
-            ip = VpnUtil.getIpPrefix(ip);
-            for (Adjacency adjacs : adjacencyList) {
-                if (adjacs.getMacAddress() != null && !adjacs.getMacAddress().isEmpty()) {
-                    nextHopIpAddr = adjacs.getIpAddress();
-                    nextHopMacAddress = adjacs.getMacAddress();
-                    break;
-                }
-            }
-            if (nextHopMacAddress != null && ip != null) {
-                String rd = VpnUtil.getVpnRd(broker, vpnName);
-                long label =
-                        VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
-                                VpnUtil.getNextHopLabelKey((rd != null) ? rd : vpnName, ip));
-                String nextHopIp = nextHopIpAddr.split("/")[0];
-                Adjacency newAdj = new AdjacencyBuilder().setIpAddress(ip).setKey
-                        (new AdjacencyKey(ip)).setNextHopIpList(Arrays.asList(nextHopIp)).build();
-                adjacencyList.add(newAdj);
-                Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
-                VpnInterface newVpnIntf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(vpnInterface)).
-                        setName(vpnInterface).setVpnInstanceName(vpnName).addAugmentation(Adjacencies.class, aug).build();
-                VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
-                LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
-            }
-        }
-
-    }
-
-    public void removeMIPAdjacency(String vpnName, String vpnInterface, org.opendaylight.yang.gen.v1.urn.ietf.params
-            .xml.ns.yang.ietf.inet.types.rev130715.IpAddress prefix) {
-        String ip = VpnUtil.getIpPrefix(prefix.getIpv4Address().getValue());
-        LOG.trace("Removing {} adjacency from Old VPN Interface {} ",ip,vpnInterface);
-        InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
-        InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
-        Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
-        if (adjacencies.isPresent()) {
-            InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class).
-                    child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
-                    .child(Adjacency.class, new AdjacencyKey(ip)).build();
-            MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
-            LOG.trace("Successfully Deleted Adjacency into VpnInterface {}", vpnInterface);
+    void notifyTaskIfRequired(String intfName) {
+        Runnable notifyTask = vpnIntfMap.remove(intfName);
+        if (notifyTask == null) {
+            return;
         }
+        executorService.execute(notifyTask);
     }
 }