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 acdbf84960ead5fc7008c0b22702081138bdecd0..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.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.bgpmanager.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 com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.JdkFutureAdapters;
-
-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.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.netvirt.fib.rpc.rev160121.FibRpcService;
+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.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.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.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;
@@ -56,291 +119,181 @@ 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.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.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
-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.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-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, tunnelInterfaceStateListenerRegistration;
-    private final DataBroker broker;
+    private final DataBroker dataBroker;
     private final IBgpManager bgpManager;
-    private IFibManager fibManager;
-    private IMdsalApiManager mdsalManager;
-    private OdlInterfaceRpcService ifaceMgrRpcService;
-    private ItmRpcService itmProvider;
-    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 TunnelInterfaceStateListener tunnelInterfaceStateListener;
-    private VpnInterfaceOpListener vpnInterfaceOpListener;
-    private ArpNotificationHandler arpNotificationHandler;
-    private NotificationPublishService notificationPublishService;
-    private FibRpcService fibService;
-    protected enum UpdateRouteAction {
-        ADVERTISE_ROUTE, WITHDRAW_ROUTE
-    }
 
-    /**
-     * 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);
-        vpnInterfaceOpListener = new VpnInterfaceOpListener();
-        arpNotificationHandler = new ArpNotificationHandler(this, broker);
-        vpnSubnetRouteHandler = new VpnSubnetRouteHandler(broker, bgpManager, this);
-        tunnelInterfaceStateListener = new TunnelInterfaceStateListener(broker, this);
-        notificationService.registerNotificationListener(vpnSubnetRouteHandler);
-        notificationService.registerNotificationListener(arpNotificationHandler);
-        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 setITMProvider(ItmRpcService itmProvider) {
-        this.itmProvider = itmProvider;
-    }
-
-
-    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 VpnSubnetRouteHandler getVpnSubnetRouteHandler() {
-        return this.vpnSubnetRouteHandler;
+    public void start() {
+        LOG.info("{} start", getClass().getSimpleName());
+        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
     @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 InstanceIdentifier<VpnInterface> getWildCardPath() {
+        return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
     }
 
-    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);
-            tunnelInterfaceStateListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
-                    getTunnelInterfaceStateListenerPath(), tunnelInterfaceStateListener, DataChangeScope.SUBTREE);
-        } catch (final Exception e) {
-            LOG.error("VPN Service DataChange listener registration fail!", e);
-            throw new IllegalStateException("VPN Service registration Listener failed.", e);
-        }
+    @Override
+    protected VpnInterfaceManager getDataTreeChangeListener() {
+        return VpnInterfaceManager.this;
     }
 
-    private InstanceIdentifier<StateTunnelList> getTunnelInterfaceStateListenerPath() {
-        return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
-    }
 
     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)
-            .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
+                .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class);
     }
 
     @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);
-        String interfaceName = key.getName();
+        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){
-            BigInteger dpnId = BigInteger.ZERO;
             try{
-                dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
+                final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
+                final int ifIndex = interfaceState.getIfIndex();
+                DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                dataStoreCoordinator.enqueueJob("VPNINTERFACE-"+ interfaceName,
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() throws Exception {
+                                WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
+                                WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
+                                WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
+                                processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false, writeConfigTxn, writeOperTxn, writeInvTxn);
+                                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){
                 LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. ", interfaceName, e);
                 return;
             }
-            processVpnInterfaceUp(InterfaceUtils.getDpIdFromInterface(interfaceState), interfaceName,
-                                  interfaceState.getIfIndex(), false);
         } else {
             LOG.info("Handling addition of VPN interface {} skipped as interfaceState is not available", interfaceName);
         }
     }
 
-    protected void processVpnInterfaceUp(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceUp) {
+    protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface,
+                                         final int lPortTag, boolean isInterfaceUp,
+                                         WriteTransaction writeConfigTxn,
+                                         WriteTransaction writeOperTxn,
+                                         WriteTransaction writeInvTxn) {
 
-        VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(broker, interfaceName);
-        if(vpnInterface == null) {
-            LOG.info("Unable to process add/up for interface {} as it is not configured", interfaceName);
-            return;
-        }
+        final String interfaceName = vpnInterface.getName();
         if (!isInterfaceUp) {
-            String vpnName = vpnInterface.getVpnInstanceName();
+            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;
-            int numAdjs = 0;
-            VpnInterface opVpnInterface = null;
-            synchronized (interfaceName.intern()) {
-                opVpnInterface = VpnUtil.getOperationalVpnInterface(broker, vpnInterface.getName());
-                if (opVpnInterface != null ) {
-                    String opVpnName = opVpnInterface.getVpnInstanceName();
-                    String primaryInterfaceIp = null;
-                    if(opVpnName.equals(vpnName)) {
-                        // Please check if the primary VRF Entry does not exist for 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);
-                        if (adjs == null) {
-                            LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
-                            return;
-                        }
-                        numAdjs = adjs.size();
-                        for (Adjacency adj : adjs) {
-                            if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
-                                primaryInterfaceIp = adj.getIpAddress();
-                                break;
-                            }
-                        }
-                        if (primaryInterfaceIp == null) {
-                            LOG.info("VPN Interface {} addition failed as primary adjacency for this vpn interface could not be obtained", interfaceName);
-                            return;
+            VpnInterface opVpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, vpnInterface.getName());
+            if (opVpnInterface != null ) {
+                String opVpnName = opVpnInterface.getVpnInstanceName();
+                String primaryInterfaceIp = null;
+                if(opVpnName.equals(vpnName)) {
+                    // Please check if the primary VRF Entry does not exist for 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(dataBroker, interfaceName);
+                    if (adjs == null) {
+                        LOG.info("VPN Interface {} addition failed as adjacencies for this vpn interface could not be obtained", interfaceName);
+                        return;
+                    }
+                    for (Adjacency adj : adjs) {
+                        if (adj.getMacAddress() != null && !adj.getMacAddress().isEmpty()) {
+                            primaryInterfaceIp = adj.getIpAddress();
+                            break;
                         }
-                        // Get the rd of the vpn instance
-                        String rd = getRouteDistinguisher(opVpnName);
-                        VrfEntry vrf = VpnUtil.getVrfEntry(broker, rd, primaryInterfaceIp);
-                            if (vrf != null) {
-                                LOG.info("VPN Interface {} already provisioned , bailing out from here.", interfaceName);
-                                return;
-                            }
-                        waitForVpnInterfaceOpRemoval = true;
-                    } else {
-                        LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}",
-                             interfaceName, vpnName, opVpnName);
                     }
+                    if (primaryInterfaceIp == null) {
+                        LOG.info("VPN Interface {} addition failed as primary adjacency "
+                                + "for this vpn interface could not be obtained", interfaceName);
+                        return;
+                    }
+                    // Get the rd of the vpn instance
+                    String rd = getRouteDistinguisher(opVpnName);
+                    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;
+                    }
+                    waitForVpnInterfaceOpRemoval = true;
+                } else {
+                    LOG.info("vpn interface {} to go to configured vpn {}, but in operational vpn {}",
+                            interfaceName, vpnName, opVpnName);
                 }
-                if (!waitForVpnInterfaceOpRemoval) {
-                    // Add the VPNInterface and quit
-                    bindService(dpId, vpnName, interfaceName, lPortTag);
-                    updateDpnDbs(dpId, vpnName, interfaceName, true);
-                    processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
-                        vpnInterface);
-                    return;
-                }
+            }
+            if (!waitForVpnInterfaceOpRemoval) {
+                // Add the VPNInterface and quit
+                updateVpnToDpnMapping(dpId, vpnName, interfaceName, true /* add */);
+                bindService(dpId, vpnName, interfaceName, lPortTag, writeConfigTxn, writeInvTxn);
+                processVpnInterfaceAdjacencies(dpId, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
+                return;
             }
 
             // 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);
@@ -354,34 +307,113 @@ 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;
             }
             // VPNInterface got removed, proceed with Add
-            synchronized (interfaceName.intern()) {
-                bindService(dpId, vpnName, interfaceName, lPortTag);
-                updateDpnDbs(dpId, vpnName, interfaceName, true);
-                processVpnInterfaceAdjacencies(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
-                                               vpnInterface);
-            }
+            updateVpnToDpnMapping(dpId, vpnName, interfaceName, true /* add */);
+            bindService(dpId, vpnName, interfaceName, lPortTag, writeConfigTxn, writeInvTxn);
+            processVpnInterfaceAdjacencies(dpId, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
         } else {
-            synchronized (interfaceName.intern()) {
-                // Interface is retained in the DPN, but its Link Up.
-                // Advertise prefixes again for this interface to BGP
-                advertiseAdjacenciesForVpnToBgp(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
-                        vpnInterface);
-            }
+            // Interface is retained in the DPN, but its Link Up.
+            // Advertise prefixes again for this interface to BGP
+            advertiseAdjacenciesForVpnToBgp(dpId, VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName()),
+                    vpnInterface);
         }
     }
 
-    private void advertiseAdjacenciesForVpnToBgp(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
+
+//    private class UpdateDpnToVpnWorker implements Callable<List<ListenableFuture<Void>>> {
+//        BigInteger dpnId;
+//        String vpnName;
+//        String interfaceName;
+//        boolean addToDpn;
+//        int lPortTag;
+//
+//        public UpdateDpnToVpnWorker(BigInteger dpnId, String vpnName, String interfaceName,
+//                                    int lPortTag, boolean addToDpn) {
+//            this.dpnId= dpnId;
+//            this.vpnName = vpnName;
+//            this.interfaceName = interfaceName;
+//            this.lPortTag = lPortTag;
+//            this.addToDpn = addToDpn;
+//        }
+//
+//        @Override
+//        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 = dataBroker.newWriteOnlyTransaction();
+//            updateDpnDbs(dpnId, vpnName, interfaceName, addToDpn, writeTxn);
+//            List<ListenableFuture<Void>> futures = new ArrayList<>();
+//            futures.add(writeTxn.submit());
+//            ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+//            Futures.addCallback(listenableFuture,
+//                    new UpdateDpnToVpnCallback(dpnId, vpnName, interfaceName, lPortTag, addToDpn));
+//            return futures;
+//        }
+//    }
+//
+//
+//    /**
+//     * JobCallback class is used as a future callback for
+//     * main and rollback workers to handle success and failure.
+//     */
+//    private class UpdateDpnToVpnCallback implements FutureCallback<List<Void>> {
+//        BigInteger dpnId;
+//        String vpnName;
+//        String interfaceName;
+//        boolean addToDpn;
+//        int lPortTag;
+//
+//        public UpdateDpnToVpnCallback(BigInteger dpnId, String vpnName, String interfaceName,
+//                                      int lPortTag, boolean addToDpn) {
+//            this.dpnId= dpnId;
+//            this.vpnName = vpnName;
+//            this.interfaceName = interfaceName;
+//            this.lPortTag = lPortTag;
+//            this.addToDpn = addToDpn;
+//        }
+//
+//        /**
+//         * @param voids
+//         * This implies that all the future instances have returned success. -- TODO: Confirm this
+//         */
+//        @Override
+//        public void onSuccess(List<Void> voids) {
+//            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+//            bindService(dpnId, vpnName, interfaceName, lPortTag, writeTxn);
+//            processVpnInterfaceAdjacencies(dpnId, vpnName, interfaceName, writeTxn);
+//            writeTxn.submit();
+//        }
+//
+//        /**
+//         *
+//         * @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 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());
@@ -397,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;
@@ -426,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());
@@ -461,208 +493,241 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    private void updateDpnDbs(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);
         }
         if(!dpId.equals(BigInteger.ZERO)) {
             if(add)
-                updateMappingDbs(vpnId, dpId, interfaceName, vpnName);
+                createOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
             else
-                removeFromMappingDbs(vpnId, dpId, interfaceName, vpnName);
+                removeOrUpdateVpnToDpnList(vpnId, dpId, interfaceName, vpnName);
+        }
+    }
+
+    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 bindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName, int lPortTag) {
-        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(BigInteger.valueOf(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),
-                                            VpnConstants.L3VPN_SERVICE_IDENTIFIER, priority,
-                                            VpnConstants.COOKIE_VM_INGRESS_TABLE, instructions);
-        VpnUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                          InterfaceUtils.buildServiceId(vpnInterfaceName, VpnConstants.L3VPN_SERVICE_IDENTIFIER), serviceInfo);
-        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
-                    vpnId, ArpReplyOrRequest.REQUEST, NwConstants.ADD_FLOW);
-        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REPLY, NwConstants.ADD_FLOW);
+    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(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
 
-    }
+        if (adjacencies.isPresent()) {
+            List<Adjacency> nextHops = adjacencies.get().getAdjacency();
+            List<Adjacency> value = new ArrayList<>();
 
-    private void processVpnInterfaceAdjacencies(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier,
-                                                VpnInterface intf) {
-        String intfName = intf.getName();
-        synchronized (intfName) {
-            // Read NextHops
-            InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
-            Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
+            // Get the rd of the vpn instance
+            String rd = getRouteDistinguisher(vpnName);
 
-            if (adjacencies.isPresent()) {
-                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
-                List<Adjacency> value = new ArrayList<>();
+            String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
+            if (nextHopIp == null){
+                LOG.error("NextHop for interface {} is null", interfaceName);
+                return;
+            }
 
-                // Get the rd of the vpn instance
-                String rd = getRouteDistinguisher(intf.getVpnInstanceName());
+            List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
 
-                String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(broker, dpnId);
-                if (nextHopIp == null){
-                    LOG.error("NextHop for interface {} is null", intfName);
+            LOG.trace("NextHops for interface {} are {}", interfaceName, nextHops);
+            for (Adjacency nextHop : nextHops) {
+                String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
+                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<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(intf.getVpnInstanceName());
-                LOG.trace("NextHops for interface {} are {}", intfName, nextHops);
-                for (Adjacency nextHop : nextHops) {
-                    String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
-                    long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, VpnUtil
-                            .getNextHopLabelKey((rd == null) ? intf.getVpnInstanceName() : rd, prefix));
-                    List<String> adjNextHop = nextHop.getNextHopIpList();
-                    value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
-                            (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
-                            .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
-                    if (nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
-                        LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, intfName, intf.getVpnInstanceName());
-                        VpnUtil.syncUpdate(
-                                broker,
-                                LogicalDatastoreType.OPERATIONAL,
-                                VpnUtil.getPrefixToInterfaceIdentifier(
-                                        VpnUtil.getVpnId(broker, intf.getVpnInstanceName()), prefix),
-                                VpnUtil.getPrefixToInterface(dpnId, intf.getName(), prefix));
-                    } else {
-                        //Extra route adjacency
-                        // FIXME 4: To be fixed with VPNManager patch
-                        LOG.trace("Adding prefix {} and nexthopList {} as extra-route for vpn", nextHop.getIpAddress(), nextHop.getNextHopIpList(), intf.getVpnInstanceName() );
-                        VpnUtil.syncUpdate(
-                                broker,
-                                LogicalDatastoreType.OPERATIONAL,
-                                VpnUtil.getVpnToExtrarouteIdentifier(
-                                        (rd != null) ? rd : intf.getVpnInstanceName(), nextHop.getIpAddress()),
-                                VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIpList()));
-                    }
-
+                List<String> adjNextHop = nextHop.getNextHopIpList();
+                value.add(new AdjacencyBuilder(nextHop).setLabel(label).setNextHopIpList(
+                        (adjNextHop != null && !adjNextHop.isEmpty()) ? adjNextHop : Arrays.asList(nextHopIp))
+                        .setIpAddress(prefix).setKey(new AdjacencyKey(prefix)).build());
+
+                if (nextHop.getMacAddress() != null && !nextHop.getMacAddress().isEmpty()) {
+                    LOG.trace("Adding prefix {} to interface {} for vpn {}", prefix, interfaceName, vpnName);
+                    writeOperTxn.merge(
+                            LogicalDatastoreType.OPERATIONAL,
+                            VpnUtil.getPrefixToInterfaceIdentifier(
+                                    VpnUtil.getVpnId(dataBroker, vpnName), prefix),
+                            VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix), true);
+                } else {
+                    //Extra route adjacency
+                    LOG.trace("Adding prefix {} and nexthopList {} as extra-route for vpn", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName);
+                    writeOperTxn.merge(
+                            LogicalDatastoreType.OPERATIONAL,
+                            VpnUtil.getVpnToExtrarouteIdentifier(
+                                    (rd != null) ? rd : vpnName, nextHop.getIpAddress()),
+                            VpnUtil.getVpnToExtraroute(nextHop.getIpAddress(), nextHop.getNextHopIpList()), true);
                 }
+            }
 
-                Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
-                VpnInterface opInterface = VpnUtil.getVpnInterface(intfName, intf.getVpnInstanceName(), aug, dpnId, Boolean.FALSE);
-                InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(intfName);
-                VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
-                long vpnId = VpnUtil.getVpnId(broker, intf.getVpnInstanceName());
-                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,
-                                intfName, null,false, rd);
-                        addPrefixToBGP(rd, nextHop.getIpAddress(), nextHopIp, label);
-                        //TODO: ERT - check for VPNs importing my route
-                        for (VpnInstance vpn : vpnsToImportRoute) {
-                            String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
-                            if (vpnRd != null) {
-                                LOG.debug("Exporting route with rd {} prefix {} nexthop {} label {} to VPN {}", vpnRd, nextHop.getIpAddress(), nextHopIp, label, vpn);
-                                VpnUtil.addFibEntryToDS(broker, vpnRd, nextHop.getIpAddress(), nextHopIp, (int) label, RouteOrigin.SELF_IMPORTED);
-                            }
+            Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
+
+            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(dataBroker, vpnName);
+
+            for (Adjacency nextHop : aug.getAdjacency()) {
+                long label = nextHop.getLabel();
+                if (rd != null) {
+                    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 (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(dataBroker, vpnRd, nextHop.getIpAddress(), Arrays.asList(nextHopIp), (int) label,
+                                    RouteOrigin.SELF_IMPORTED, writeConfigTxn);
                         }
-                    } else {
-                        // ### add FIB route directly
-                        VpnUtil.addFibEntryToDS(broker, intf.getVpnInstanceName(), nextHop.getIpAddress(), nextHopIp,
-                                                (int) label, RouteOrigin.STATIC);
                     }
+                } else {
+                    // ### add FIB route directly
+                    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;
@@ -678,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)) {
@@ -706,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();
@@ -721,109 +781,194 @@ 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){
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lPortTag, ++sIndex, BigInteger.valueOf(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);
-
-        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);
-        }
-    }
-
     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 = "";
+                .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
+        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;
     }
 
-    private synchronized void updateMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
+    /**
+     * 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;
-        InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
-        Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, 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()) {
-            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);
-        } else {
-            VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-                                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                                    VpnUtil.getVpnInstanceOpDataBuilder(rd, vpnId, vpnName));
-            VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
-            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 =  new ArrayList<>();
-            vpnInterfaces.add(vpnInterface);
-            VpnUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
-                              vpnToDpnList.setVpnInterfaces(vpnInterfaces).build());
-
-            /**
-             * FIXME: DC Gateway tunnel should be built dynamically
-            //this is the first VM in this VPN on the DPN, may be a new DPN has come up,
-            //if tunnel to DC GW does not exist, create it
-            //if(!tunnelExists(dpnID, bgpManager.getDCGWIP()))
-            String dcGW = bgpManager.getDCGwIP();
-            if(dcGW != null && !dcGW.isEmpty())
-            {
-                LOG.debug("Building tunnel from DPN {} to DC GW {}", dpnId, dcGW);
-                itmProvider.buildTunnelFromDPNToDCGW(dpnId, new IpAddress(dcGW.toCharArray()));
-            }*/
-            fibManager.populateFibOnNewDpn(dpnId, vpnId, (rd == null) ? vpnName : rd);
-            publishAddNotification(dpnId, vpnName, rd);
-            //TODO: IRT - import local routes to vpn. check for the VPNs exporting the routes
-            //FIXME: do we need to handle here. since already routes are imported to this vpn
+        Boolean newDpnOnVpn = Boolean.FALSE;
+
+        synchronized (vpnName.intern()) {
+            WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+            InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
+            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, vpnToDpnListBuilder.build(), true);
+                } else {
+                    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
+                        .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = new ArrayList<>();
+                vpnInterfaces.add(vpnInterface);
+                VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
+                vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
+
+                if (writeTxn != null) {
+                    writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
+                } else {
+                    VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build());
+                }
+                newDpnOnVpn = Boolean.TRUE;
+            }
+            CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
+            try {
+                futures.get();
+            } catch (InterruptedException | ExecutionException e) {
+                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, 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()) {
+            InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
+            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();
+                org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
+                        currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
+
+                if (vpnInterfaces.remove(currVpnInterface)) {
+                    if (vpnInterfaces.isEmpty()) {
+                        List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
+                        if (ipAddresses == null || ipAddresses.isEmpty()) {
+                            VpnToDpnListBuilder dpnInVpnBuilder =
+                                    new VpnToDpnListBuilder(dpnInVpn.get())
+                                            .setDpnState(VpnToDpnList.DpnState.Inactive)
+                                            .setVpnInterfaces(null);
+                            if (writeTxn != null) {
+                                writeTxn.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
+                            } else {
+                                VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build());
+                            }
+                            lastDpnOnVpn = Boolean.TRUE;
+                        } else {
+                            LOG.warn("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}", vpnName, dpnId);
+                        }
+                    } else {
+                        if (writeTxn != null) {
+                            writeTxn.delete(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)));
+                        } else {
+                            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);
+                        }
+                    }
+                }
+            }
+            CheckedFuture<Void, TransactionCommitFailedException> futures = writeTxn.submit();
+            try {
+                futures.get();
+            } catch (InterruptedException | ExecutionException e) {
+                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, new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
         }
     }
 
     void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
-        List<VpnInstance> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
-        long vpnId = VpnUtil.getVpnId(broker, vpnName);
-        for (VpnInstance vpn : vpnsToExportRoute) {
-            String rd = vpn.getIpv4Family().getRouteDistinguisher();
-            long exportingVpnId = VpnUtil.getVpnId(broker, vpn.getVpnInstanceName());
-            List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, vpn.getIpv4Family().getRouteDistinguisher());
+        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 {
@@ -837,80 +982,47 @@ 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);
+                                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());
-                                VpnUtil.addFibEntryToDS(broker, vpnRd, prefix, nh, (int)label, RouteOrigin.SELF_IMPORTED);
+                                fibManager.addOrUpdateFibEntry(dataBroker, vpnRd, prefix, Arrays.asList(nh), (int)label,
+                                        RouteOrigin.SELF_IMPORTED, writeConfigTxn);
                             }
                         }
                     } catch (Exception e) {
                         LOG.error("Exception occurred while importing route with prefix {} label {} nexthop {} from vpn {} to vpn {}", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpn.getVpnInstanceName(), vpnName);
                     }
                 }
+                writeConfigTxn.submit();
             } else {
-                LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getIpv4Family().getRouteDistinguisher());
-            }
-        }
-    }
-
-    private synchronized void removeFromMappingDbs(long vpnId, BigInteger dpnId, String intfName, String vpnName) {
-        //TODO: Delay 'DPN' removal so that other services can cleanup the entries for this dpn
-        String rd = VpnUtil.getVpnRd(broker, vpnName);
-        InstanceIdentifier<VpnToDpnList> id = VpnUtil.getVpnToDpnListIdentifier(rd, dpnId);
-        Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-        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();
-            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
-                    currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
-
-            if (vpnInterfaces.remove(currVpnInterface)) {
-                if (vpnInterfaces.isEmpty()) {
-                    List<IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
-                    if (ipAddresses == null || ipAddresses.isEmpty()) {
-                        LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
-                        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id, VpnUtil.DEFAULT_CALLBACK);
-                        fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd);
-                        publishRemoveNotification(dpnId, vpnName, rd);
-                    } else {
-                        LOG.debug("vpn interfaces are empty but ip addresses are present for the vpn {} in dpn {}", vpnName, dpnId);
-                    }
-                } else {
-                    VpnUtil.delete(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)), VpnUtil.DEFAULT_CALLBACK);
-                }
+                LOG.info("No vrf entries to import from vpn {} with rd {}", vpn.getVpnInstanceName(), vpn.getVrfId());
             }
         }
     }
 
-    private void addPrefixToBGP(String rd, String prefix, String nextHopIp, long label) {
+    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);
-            bgpManager.addPrefix(rd, prefix, Arrays.asList(nextHopIp), (int)label, RouteOrigin.STATIC);
+            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) {
             LOG.error("Add prefix failed", e);
         }
     }
 
-
-    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);
-        String interfaceName = key.getName();
+        final String interfaceName = key.getName();
 
         InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
-        Optional<VpnInterface> existingVpnInterface = 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);
-        if(existingVpnInterface.isPresent()){
+                InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
+        if (optVpnInterface.isPresent()){
             BigInteger dpnId = BigInteger.ZERO;
             Boolean dpnIdRetrieved = Boolean.FALSE;
             if(interfaceState != null){
@@ -920,78 +1032,106 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 }catch (Exception e){
                     LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}. Fetching from vpn interface op data store. ", interfaceName, e);
                 }
+            } else {
+                LOG.error("Unable to retrieve interfaceState for interface {} , quitting ", interfaceName);
+                return;
             }
+            final VpnInterface vpnOpInterface = optVpnInterface.get();
             if(dpnIdRetrieved == Boolean.FALSE){
                 LOG.info("dpnId for {} has not been retrieved yet. Fetching from vpn interface operational DS", interfaceName);
-                dpnId = existingVpnInterface.get().getDpnId();
+                dpnId = vpnOpInterface.getDpnId();
             }
-            processVpnInterfaceDown(dpnId, interfaceName, interfaceState.getIfIndex(), false, true);
+            final int ifIndex = interfaceState.getIfIndex();
+            final BigInteger dpId = dpnId;
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
+                            WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
+                            WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
+                            processVpnInterfaceDown(dpId, interfaceName, ifIndex, false, true, writeConfigTxn, writeOperTxn, writeInvTxn);
+                            List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
+                            futures.add(writeOperTxn.submit());
+                            futures.add(writeConfigTxn.submit());
+                            futures.add(writeInvTxn.submit());
+                            return futures;
+                        }
+                    });
+
         }else{
             LOG.warn("VPN interface {} was unavailable in operational data store to handle remove event", interfaceName);
         }
     }
 
-    protected void processVpnInterfaceDown(BigInteger dpId, String interfaceName, int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval) {
+    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) {
-            synchronized (interfaceName.intern()) {
-                VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(broker, interfaceName);
-                if(vpnInterface == null){
-                    LOG.info("Unable to process delete/down for interface {} as it is not available in operational data store", interfaceName);
-                    return;
+            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(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);
                 }else{
-                    String vpnName = vpnInterface.getVpnInstanceName();
-                    if(!vpnInterface.isScheduledForRemove()){
-                        VpnUtil.updateVpnInterface(broker, vpnInterface.getName(), vpnInterface.getDpnId(), vpnInterface.getVpnInstanceName(), Boolean.TRUE);
-                        removeAdjacenciesFromVpn(dpId, identifier, vpnInterface);
-                        LOG.info("Unbinding vpn service from interface {} ", interfaceName);
-                        unbindService(dpId, vpnName, interfaceName, lPortTag, isInterfaceStateDown, isConfigRemoval);
-                    }else{
-                        LOG.info("Unbinding vpn service for interface {} has already been scheduled by a different event ", interfaceName);
-                        return;
-                    }
+                    LOG.info("Unbinding vpn service for interface {} has already been scheduled by a different event ", interfaceName);
+                    return;
                 }
             }
+        } else {
+            // Interface is retained in the DPN, but its Link Down.
+            // Only withdraw the prefixes for this interface from BGP
+            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;
+            }else {
+                withdrawAdjacenciesForVpnFromBgp(identifier, vpnInterface);
+            }
+        }
+    }
 
-            // FIB didn't get a chance yet to clean up this VPNInterface
-            // Let us give it a chance here !
-            LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
-            try {
-                Runnable notifyTask = new VpnNotifyTask();
-                vpnIntfMap.put(interfaceName, notifyTask);
-                synchronized (notifyTask) {
-                    try {
-                        notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
-                    } catch (InterruptedException e) {
-                    }
+    private void waitForFibToRemoveVpnPrefix(String interfaceName) {
+        // FIB didn't get a chance yet to clean up this VPNInterface
+        // Let us give it a chance here !
+        LOG.info("VPN Interface {} removal waiting for FIB to clean up ! ", interfaceName);
+        try {
+            Runnable notifyTask = new VpnNotifyTask();
+            vpnIntfMap.put(interfaceName, notifyTask);
+            synchronized (notifyTask) {
+                try {
+                    notifyTask.wait(VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS);
+                } catch (InterruptedException e) {
                 }
-            } finally {
-                vpnIntfMap.remove(interfaceName);
             }
-        } else {
-                synchronized (interfaceName.intern()) {
-                    // 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);
-                    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;
-                    }else {
-                        withdrawAdjacenciesForVpnFromBgp(identifier, vpnInterface);
-                    }
-                }
+        } finally {
+            vpnIntfMap.remove(interfaceName);
         }
-
     }
 
-    private void removeAdjacenciesFromVpn(BigInteger dpnId, final InstanceIdentifier<VpnInterface> identifier, VpnInterface intf) {
+    private void removeAdjacenciesFromVpn(final BigInteger dpnId, final String interfaceName, final String vpnName,
+                                          WriteTransaction writeConfigTxn) {
         //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, intf.getVpnInstanceName());
-        LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", intf.getName(),
-                intf.getVpnInstanceName(), rd);
+        String rd = VpnUtil.getVpnRd(dataBroker, vpnName);
+        LOG.trace("removeAdjacenciesFromVpn: For interface {} RD recovered for vpn {} as rd {}", interfaceName,
+                vpnName, rd);
         if (adjacencies.isPresent()) {
             List<Adjacency> nextHops = adjacencies.get().getAdjacency();
 
@@ -1001,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());
@@ -1012,34 +1152,33 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                         // This is a primary adjacency
                         nhList = nextHop.getNextHopIpList();
                     }
-                    if (rd.equals(intf.getVpnInstanceName())) {
+                    if (rd.equals(vpnName)) {
                         //this is an internal vpn - the rd is assigned to the vpn instance name;
                         //remove from FIB directly
                         for(String nh : nhList) {
-                            VpnUtil.removeFibEntryFromDS(broker, intf.getVpnInstanceName(), nextHop.getIpAddress(), nh);
+                            fibManager.removeOrUpdateFibEntry(dataBroker, vpnName, nextHop.getIpAddress(), nh, writeConfigTxn);
                         }
                     } else {
-
-                        List<VpnInstance> vpnsToImportRoute = getVpnsImportingMyRoute(intf.getVpnInstanceName());
-                        for (String nh : nextHop.getNextHopIpList()) {
+                        List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnName);
+                        for (String nh : nhList) {
                             //IRT: remove routes from other vpns importing it
-                            removePrefixFromBGP(rd, nextHop.getIpAddress(), nh);
-                            for (VpnInstance vpn : vpnsToImportRoute) {
-                                String vpnRd = vpn.getIpv4Family().getRouteDistinguisher();
+                            removePrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
+                            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());
-                                    VpnUtil.removeFibEntryFromDS(broker, vpnRd, nextHop.getIpAddress(), nh);
+                                    fibManager.removeOrUpdateFibEntry(dataBroker, vpnRd, nextHop.getIpAddress(), nh, writeConfigTxn);
                                 }
                             }
                         }
                     }
                     String ip = nextHop.getIpAddress().split("/")[0];
-                    VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
-                            intf.getVpnInstanceName(), ip);
+                    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, intf.getVpnInstanceName(), ip);
+                        VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip);
                     }
                 }
             }
@@ -1047,25 +1186,36 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
     }
 
 
-    private void unbindService(BigInteger dpId, String vpnInstanceName, String vpnInterfaceName,
-                               int lPortTag, boolean isInterfaceStateDown, boolean isConfigRemoval) {
+    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) {
-            MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION,
-                    InterfaceUtils.buildServiceId(vpnInterfaceName,
-                            VpnConstants.L3VPN_SERVICE_IDENTIFIER));
+            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, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
-                    vpnId, ArpReplyOrRequest.REQUEST, NwConstants.DEL_FLOW);
-        makeArpFlow(dpId, VpnConstants.L3VPN_SERVICE_IDENTIFIER, lPortTag, vpnInterfaceName,
-                vpnId, ArpReplyOrRequest.REPLY, NwConstants.DEL_FLOW);
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnInstanceName);
+        setupGwMacIfExternalVpn(dpId, vpnInterfaceName, vpnId, writeConfigTxn, NwConstants.DEL_FLOW);
     }
 
 
-    private void removePrefixFromBGP(String rd, String prefix, String nextHop) {
-        VpnUtil.removeFibEntryFromDS(broker, rd, prefix, nextHop);
+    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(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) {
@@ -1076,40 +1226,46 @@ 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)) {
             remove(identifier, original);
+            waitForFibToRemoveVpnPrefix(update.getName());
             add(identifier, update);
         }
         //handle both addition and removal of adjacencies
         //currently, new adjacency may be an extra route
-        if (!oldAdjs.equals(newAdjs)) {
-            for (Adjacency adj : newAdjs) {
-                if (oldAdjs.contains(adj)) {
-                    oldAdjs.remove(adj);
+        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);
             }
         }
     }
 
-    public void processArpRequest(IpAddress srcIP, PhysAddress srcMac, IpAddress targetIP, PhysAddress targetMac,String srcInterface){
+    public void processArpRequest(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715
+                                          .IpAddress srcIP, PhysAddress srcMac, org.opendaylight.yang.gen.v1.urn.ietf
+            .params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress targetIP, PhysAddress targetMac, String srcInterface){
         //Build ARP response with ARP requests TargetIp TargetMac as the Arp Response SrcIp and SrcMac
         SendArpResponseInput input = new SendArpResponseInputBuilder().setInterface(srcInterface)
                 .setDstIpaddress(srcIP).setDstMacaddress(srcMac).setSrcIpaddress(targetIP).setSrcMacaddress(targetMac).build();
@@ -1136,13 +1292,14 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         StringBuilder errorText = new StringBuilder();
         for(RpcError error : errors) {
             errorText.append(",").append(error.getErrorType()).append("-")
-                     .append(error.getMessage());
+                    .append(error.getMessage());
         }
         return errorText.toString();
     }
 
     private void addToLabelMapper(Long label, BigInteger dpnId, String prefix, List<String> nextHopIpList, Long vpnId,
-                                  String vpnInterfaceName, Long elanTag, boolean isSubnetRoute, String rd) {
+                                  String vpnInterfaceName, Long elanTag, boolean isSubnetRoute, String rd,
+                                  WriteTransaction writeOperTxn) {
         Preconditions.checkNotNull(label, "label cannot be null or empty!");
         Preconditions.checkNotNull(prefix, "prefix cannot be null or empty!");
         Preconditions.checkNotNull(vpnId, "vpnId cannot be null or empty!");
@@ -1165,33 +1322,36 @@ 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);
             }
             LabelRouteInfo lri = lriBuilder.build();
             LOG.trace("Adding route info to label map: {}", lri);
-            VpnUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, lriIid, lri);
+            if (writeOperTxn != null) {
+                writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, lriIid, lri, true);
+            } else {
+                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,
-                                                        long elantag, BigInteger dpnId) {
-
+    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
         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
-                                                 .setLabel((long)label).setOrigin(origin.getValue())
-                                                 .addAugmentation(SubnetRoute.class, route).build();
+                .setLabel((long)label).setOrigin(origin.getValue())
+                .addAugmentation(SubnetRoute.class, route).build();
 
         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);
-        addToLabelMapper((long)label, dpnId, prefix, Arrays.asList(nextHop), vpnId, null, elantag, true, rd);
+        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);
 
         InstanceIdentifierBuilder<VrfTables> idBuilder =
@@ -1201,26 +1361,34 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
                 setVrfEntry(vrfEntryList).build();
 
-        VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
+        if (writeTxn != null) {
+            writeTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
+        } else {
+            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())
+                    .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();
-                VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
+                if (writeTxn != null) {
+                    writeTxn.merge(LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable, true);
+                } else {
+                    VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, importingVrfTableId, importingVrfTable);
+                }
             }
         }
     }
 
     public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
-                                                        SubnetRoute route) {
+                                                        SubnetRoute route, WriteTransaction writeConfigTxn) {
 
         RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(Arrays.asList(nextHop))
@@ -1233,44 +1401,41 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).
                 setVrfEntry(vrfEntryList).build();
-        VpnUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
+        if (writeConfigTxn != null) {
+            writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew, true);
+        } else {
+            VpnUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
+        }
     }
 
-    public synchronized void deleteSubnetRouteFibEntryFromDS(String rd, String prefix, String vpnName){
-        VpnUtil.removeFibEntryFromDS(broker, rd, prefix, null /* nextHopToRemove */);
-        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());
-            VpnUtil.removeFibEntryFromDS(broker, importingRd, prefix, null);
+            fibManager.removeFibEntry(dataBroker, importingRd, prefix, null);
         }
     }
 
-    public synchronized void removeVrfFromDS(String rd) {
-        LOG.debug("Removing vrf table for rd {}", rd);
+    protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterface> identifier, Adjacency adj) {
 
-        InstanceIdentifierBuilder<VrfTables> idBuilder =
-                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
-        InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
-
-        VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, VpnUtil.DEFAULT_CALLBACK);
-
-    }
-
-    protected void addNewAdjToVpnInterface(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();
             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();
@@ -1279,34 +1444,46 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
                 adjacencies = new ArrayList<>();
             }
 
-
             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()) {
@@ -1316,14 +1493,16 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
                             Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencies);
                             VpnInterface newVpnIntf = VpnUtil.getVpnInterface(currVpnIntf.getName(),
-                                                                              currVpnIntf.getVpnInstanceName(),
-                                                                              aug, dpnId, currVpnIntf.isScheduledForRemove());
+                                    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;
                         }
@@ -1340,58 +1519,66 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
         //add extra route to vpn mapping; advertise with nexthop as tunnel ip
         VpnUtil.syncUpdate(
-            broker,
-            LogicalDatastoreType.OPERATIONAL,
-            VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
-            VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
+                dataBroker,
+                LogicalDatastoreType.OPERATIONAL,
+                VpnUtil.getVpnToExtrarouteIdentifier( (rd != null) ? rd : routerID, destination),
+                VpnUtil.getVpnToExtraroute(destination, Arrays.asList(nextHop)));
 
         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);
+                        intfName, destination);
                 return;
             }
             nextHop = nextHopIp;
         }
         List<String> nextHopIpList = Arrays.asList(nextHop);
-        addToLabelMapper((long)label, dpnId, destination, nextHopIpList, VpnUtil.getVpnId(broker, routerID),
-                intfName, null, false, rd);
+        if (rd != null) {
+            /* Label mapper is required only for BGP VPN and not for Internal VPN */
+            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
             // This is like leaking one of the Vpn2 routes towards Vpn1
             boolean nexthopIsVpn2 = ( interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nextHop) );
             String srcVpnUuid = (nexthopIsVpn2) ? interVpnLink.getSecondEndpoint().getVpnUuid().getValue()
-                                                : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
+                    : interVpnLink.getFirstEndpoint().getVpnUuid().getValue();
             String dstVpnUuid = (nexthopIsVpn2) ? interVpnLink.getFirstEndpoint().getVpnUuid().getValue()
-                                                : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
-            String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
+                    : interVpnLink.getSecondEndpoint().getVpnUuid().getValue();
+            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);
+                    VpnUtil.getNextHopLabelKey(dstVpnRd, destination));
+            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);
+                addPrefixToBGP(rd, destination, nextHop, label, null);
             } else {
                 // ### add FIB route directly
-                VpnUtil.addFibEntryToDS(broker, routerID, destination, nextHop, label, RouteOrigin.STATIC);
+                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);
@@ -1400,341 +1587,10 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
 
         if (rd != null) {
-            removePrefixFromBGP(rd, destination, nextHop);
+            removePrefixFromBGP(rd, destination, nextHop, null);
         } else {
             // ### add FIB route directly
-            VpnUtil.removeFibEntryFromDS(broker, routerID, destination, nextHop);
-        }
-    }
-
-    class VpnInterfaceOpListener extends AbstractDataChangeListener<VpnInterface> {
-
-        public VpnInterfaceOpListener() {
-            super(VpnInterface.class);
-        }
-
-        @Override
-        protected void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface del) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            String interfaceName = key.getName();
-            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) {
-                        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-                                       VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(), pref.getIpAddress()),
-                                       VpnUtil.DEFAULT_CALLBACK);
-                        synchronized (interfaceName.intern()) {
-                            updateDpnDbs(pref.getDpnId(), del.getVpnInstanceName(), interfaceName, false);
-                        }
-                    }
-//                    Long ifCnt = 0L;
-//                    //ifCnt = vpnInstOp.getVpnInterfaceCount();
-//                    LOG.trace("VpnInterfaceOpListener removed: interface name {} rd {} vpnName {} Intf count {}",
-//                            interfaceName, rd, vpnName, ifCnt);
-//                    if ((ifCnt != null) && (ifCnt > 0)) {
-//                        VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-//                                VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-//                                VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
-//                    }
-                }
-            } 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(InstanceIdentifier<VpnInterface> identifier, VpnInterface original, VpnInterface update) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            String interfaceName = key.getName();
-
-            if (original.getVpnInstanceName().equals(update.getVpnInstanceName())) {
-                return;
-            }
-
-            //increment the vpn interface count in Vpn Instance Op Data
-            //Long ifCnt = 0L;
-            VpnInstanceOpDataEntry vpnInstOp = null;
-//            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
-//                    updId = VpnUtil.getVpnInstanceToVpnIdIdentifier(update.getVpnInstanceName());
-//            Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> updVpnInstance
-//                    = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, updId);
-//
-//            if (updVpnInstance.isPresent()) {
-//                String rd = null;
-//                rd = updVpnInstance.get().getVrfId();
-//
-//                vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
-//
-//                if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
-//                    ifCnt = vpnInstOp.getVpnInterfaceCount();
-//                }
-//
-//                LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in updated Vpn Op Instance {}", interfaceName, rd, ifCnt);
-//
-//                VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-//                        VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-//                        VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
-//            }
-//
-            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());
-                            }
-                        }
-                    }
-//                        VpnUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-//                                VpnUtil.getPrefixToInterfaceIdentifier(vpnInstOp.getVpnId(),
-//                                        prefixToInterface.get().getIpAddress()),
-//                                VpnUtil.DEFAULT_CALLBACK);
-                    synchronized (interfaceName.intern()) {
-                        for (Prefixes prefix : prefixToInterfaceList) {
-                            updateDpnDbs(prefix.getDpnId(), original.getVpnInstanceName(), interfaceName, false);
-                        }
-                    }
-                }
-            }
-            notifyTaskIfRequired(interfaceName);
-//                if (vpnInstOp != null && vpnInstOp.getVpnInterfaceCount() != null) {
-//                    ifCnt = vpnInstOp.getVpnInterfaceCount();
-//                } else {
-//                    LOG.debug("VpnInterfaceOpListener update: Vpn interface count not recoverable from original, to handle update for rd {}", rd);
-//                    return;
-//                }
-//                LOG.trace("VpnInterfaceOpListener update: interface name {} rd {} interface count in original Vpn Op Instance {}", interfaceName, rd, ifCnt);
-//
-//                if (ifCnt > 0) {
-//                    VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-//                            VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-//                            VpnUtil.updateIntfCntInVpnInstOpData(ifCnt - 1, rd), VpnUtil.DEFAULT_CALLBACK);
-//                }
-//            }
-        }
-
-        @Override
-        protected void add(InstanceIdentifier<VpnInterface> identifier, VpnInterface add) {
-            final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
-            String interfaceName = key.getName();
-
-            //increment the vpn interface count in Vpn Instance Op Data
-//            Long ifCnt = 0L;
-//            String rd = getRouteDistinguisher(add.getVpnInstanceName());
-//            if(rd == null || rd.isEmpty()) rd = add.getVpnInstanceName();
-//            VpnInstanceOpDataEntry vpnInstOp = VpnUtil.getVpnInstanceOpData(broker, rd);
-//            if(vpnInstOp != null &&  vpnInstOp.getVpnInterfaceCount() != null) {
-//                ifCnt = vpnInstOp.getVpnInterfaceCount();
-//            }
-
-//            LOG.trace("VpnInterfaceOpListener add: interface name {} rd {} interface count in Vpn Op Instance {}", interfaceName, rd, ifCnt);
-
-//            VpnUtil.asyncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-//                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-//                    VpnUtil.updateIntfCntInVpnInstOpData(ifCnt + 1, rd), VpnUtil.DEFAULT_CALLBACK);
-
-
-        }
-    }
-
-    protected void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
-        BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
-        BigInteger destDpnId;
-        String srcTepIp =  String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
-        String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
-
-        InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
-        InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
-        Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
-        long tunTypeVal = 0, vpnId;
-
-        if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
-            tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
-        } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
-            tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
-        } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class){
-            tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
-        } else {
-            tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
-        }
-        LOG.trace("tunTypeVal is {}", tunTypeVal);
-
-        if (vpnInstances.isPresent()) {
-            List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
-            Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
-            LOG.trace("vpnInstIter {}", vpnInstIter);
-            while (vpnInstIter.hasNext()) {
-                VpnInstance vpnInstance = vpnInstIter.next();
-                LOG.trace("vpnInstance {}", vpnInstance);
-                vpnId = VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName());
-                try {
-                    VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
-                    LOG.trace("vpnConfig {}", vpnConfig);
-                    String rd = vpnConfig.getRouteDistinguisher();
-                    if (rd == null || rd.isEmpty()) {
-                        rd = vpnInstance.getVpnInstanceName();
-                        LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
-                    }
-                    InstanceIdentifier<VpnToDpnList> srcId =
-                        VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
-                    Optional<VpnToDpnList> srcDpnInVpn =
-                            VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, srcId);
-                    if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                        destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
-                        InstanceIdentifier<VpnToDpnList> destId =
-                                VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
-                        Optional<VpnToDpnList> destDpnInVpn =
-                                VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, destId);
-                        if (!(srcDpnInVpn.isPresent() &&
-                                destDpnInVpn.isPresent())) {
-                            LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
-                                    srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
-                            continue;
-                        }
-                    }
-                    if (srcDpnInVpn.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 = srcDpnInVpn.get().getVpnInterfaces();
-                        for (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 : vpnInterfaces) {
-                            InstanceIdentifier<VpnInterface> vpnIntfId =
-                                VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
-                            LOG.trace("vpnInterface {}", vpnInterface);
-                            InstanceIdentifier<Adjacencies> path =
-                                vpnIntfId.augmentation(Adjacencies.class);
-                            Optional<Adjacencies> adjacencies =
-                                VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
-                            LOG.trace("adjacencies {}", adjacencies);
-                            if (adjacencies.isPresent()) {
-                                List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
-                                Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
-
-                                while (adjacencyIterator.hasNext()) {
-                                    Adjacency adjacency = adjacencyIterator.next();
-                                    try {
-                                        if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
-                                            LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
-                                                     rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
-                                                     adjacency.getLabel());
-//                                            vrf = new VrfEntryBuilder().set
-                                            if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                                                fibManager.handleRemoteRoute(true,
-                                                        new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
-                                                        new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
-                                                        VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()),
-                                                        rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
-                                            }
-                                            if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
-                                                bgpManager.advertisePrefix( rd, adjacency.getIpAddress(),
-                                                                            adjacency.getNextHopIpList(),
-                                                                            adjacency.getLabel().intValue());
-                                                fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                                            }
-                                        }
-                                        else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
-                                            LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
-                                                     rd, adjacency.getIpAddress());
-                                            if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                                                fibManager.handleRemoteRoute(false, srcDpnId,
-                                                                new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
-                                                                vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
-                                            }
-                                            if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
-                                                bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
-                                                fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                                            }
-                                        }
-                                    } catch (Exception e) {
-                                        LOG.error("Exception when updating prefix {} in vrf {} to BGP",
-                                            adjacency.getIpAddress(), rd);
-                                    }
-                                }
-                            } else {
-                                LOG.trace("no adjacencies present for path {}.", path);
-                            }
-
-                        }
-                        // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
-                        //    fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
-                        // }
-                    } else {
-                        LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
-                    }
-                } catch (Exception e) {
-                    LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
-                }
-            }
-        } else {
-            LOG.trace("No vpn instances present.");
+            fibManager.removeOrUpdateFibEntry(dataBroker, routerID, destination, nextHop, null);
         }
     }
 
@@ -1776,16 +1632,16 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
     InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
         return InstanceIdentifier.builder(NeutronRouterDpns.class)
-            .child(RouterDpnList.class, new RouterDpnListKey(routerName))
-            .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
+                .child(RouterDpnList.class, new RouterDpnListKey(routerName))
+                .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
     }
 
     InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
         return InstanceIdentifier.builder(NeutronRouterDpns.class)
-            .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
+                .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
     }
 
-    protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+    protected void addToNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeOperTxn) {
         BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         if(dpId.equals(BigInteger.ZERO)) {
             LOG.warn("Could not retrieve dp id for interface {} to handle router {} association model", vpnInterfaceName, routerName);
@@ -1793,33 +1649,33 @@ 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()) {
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
-                    RouterInterfaces.class,  new RouterInterfacesKey(vpnInterfaceName)), routerInterface);
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
+                    RouterInterfaces.class, new RouterInterfacesKey(vpnInterfaceName)), routerInterface, true);
         } else {
-            MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-                    getRouterId(routerName),
-                    new RouterDpnListBuilder().setRouterId(routerName).build());
-            //VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
+            RouterDpnListBuilder builder = new RouterDpnListBuilder();
+            builder.setRouterId(routerName);
             DpnVpninterfacesListBuilder dpnVpnList = new DpnVpninterfacesListBuilder().setDpnId(dpId);
             List<RouterInterfaces> routerInterfaces =  new ArrayList<>();
             routerInterfaces.add(routerInterface);
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier,
-                    dpnVpnList.setRouterInterfaces(routerInterfaces).build());
+            builder.setDpnVpninterfacesList(Arrays.asList(dpnVpnList.build()));
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
+                    getRouterId(routerName),
+                    builder.build(), true);
         }
     }
 
-    protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName) {
+    protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, WriteTransaction writeOperTxn) {
         BigInteger dpId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         if(dpId.equals(BigInteger.ZERO)) {
             LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
             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();
@@ -1827,33 +1683,43 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
 
             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
                 if (routerInterfaces.isEmpty()) {
-                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+                    if (writeOperTxn != null) {
+                        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+                    } else {
+                        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+                    }
                 } else {
-                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
-                            RouterInterfaces.class,
-                            new RouterInterfacesKey(vpnInterfaceName)));
+                    if (writeOperTxn != null) {
+                        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
+                                RouterInterfaces.class,
+                                new RouterInterfacesKey(vpnInterfaceName)));
+                    } else {
+                        MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
+                                RouterInterfaces.class,
+                                new RouterInterfacesKey(vpnInterfaceName)));
+                    }
                 }
             }
         }
     }
 
-    protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,BigInteger dpId) {
+    protected void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName, BigInteger dpId,
+                                                  WriteTransaction writeOperTxn) {
         if(dpId.equals(BigInteger.ZERO)) {
             LOG.warn("Could not retrieve dp id for interface {} to handle router {} dissociation model", vpnInterfaceName, routerName);
             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();
             RouterInterfaces routerInterface = new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName)).setInterface(vpnInterfaceName).build();
-
             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
                 if (routerInterfaces.isEmpty()) {
-                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
                 } else {
-                    MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
+                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
                             RouterInterfaces.class,
                             new RouterInterfacesKey(vpnInterfaceName)));
                 }
@@ -1861,103 +1727,11 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         }
     }
 
-    public void addMIPAdjacency(String vpnName,String vpnInterface, 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) {
-                synchronized (vpnInterface.intern()) {
-                    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, 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()) {
-            synchronized (vpnInterface.intern()) {
-                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);
-        }
-    }
-
-    class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList>  {
-        public TunnelInterfaceStateListener(final DataBroker db, VpnInterfaceManager vpnIfMgr) {
-            super(StateTunnelList.class);
-        }
-
-
-        @Override
-        protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
-            LOG.trace("Tunnel deletion---- {}", del);
-            handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
-        }
-
-        @Override
-        protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
-            LOG.trace("Tunnel updation---- {}", update);
-            LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
-                    update.getTunnelInterfaceName(),
-                    fibManager.getTransportTypeStr(update.getTransportType().toString()),
-                    original.isTunnelState(), update.isTunnelState());
-                //withdraw all prefixes in all vpns for this dpn
-            boolean isTunnelUp = update.isTunnelState();
-                handlePrefixesForDPNs(update,isTunnelUp ?  UpdateRouteAction.ADVERTISE_ROUTE :
-                                                            UpdateRouteAction.WITHDRAW_ROUTE);
-        }
-
-        @Override
-        protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
-            LOG.trace("Tunnel addition---- {}", add);
-
-            if(!add.isTunnelState()) {
-                LOG.trace(  "Tunnel {} is not yet UP.",
-                            add.getTunnelInterfaceName());
-                return;
-            } else {
-                LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
-                        fibManager.getTransportTypeStr(add.getTransportType().toString()),
-                        add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
-                handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);
-            }
+    void notifyTaskIfRequired(String intfName) {
+        Runnable notifyTask = vpnIntfMap.remove(intfName);
+        if (notifyTask == null) {
+            return;
         }
+        executorService.execute(notifyTask);
     }
-
 }