fibmanager dead code removal
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / VrfEntryListener.java
old mode 100755 (executable)
new mode 100644 (file)
index b2b3095..540e06a
@@ -7,11 +7,14 @@
  */
 package org.opendaylight.netvirt.fibmanager;
 
+import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
 import static org.opendaylight.genius.mdsalutil.NWUtil.isIpv4Address;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -25,25 +28,35 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.annotation.Nullable;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-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.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.Datastore.Operational;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.TransactionAdapter;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NWUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
@@ -57,16 +70,20 @@ import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.batching.SubTransaction;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
+import org.opendaylight.serviceutils.upgrade.UpgradeState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
@@ -91,6 +108,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
+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.prefix.to._interface.vpn.ids.Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
@@ -114,11 +133,12 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     private static final int IPV4_ADDR_PREFIX_LENGTH = 32;
     private static final int LFIB_INTERVPN_PRIORITY = 15;
     public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
-    private static final int DJC_MAX_RETRIES = 3;
+    private static final int MAX_RETRIES = 3;
     private static final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
 
     private final DataBroker dataBroker;
     private final ManagedNewTransactionRunner txRunner;
+    private final RetryingManagedNewTransactionRunner retryingTxRunner;
     private final IMdsalApiManager mdsalManager;
     private final NexthopManager nextHopManager;
     private final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler;
@@ -129,6 +149,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     private final FibUtil fibUtil;
     private final InterVpnLinkCache interVpnLinkCache;
     private final List<AutoCloseable> closeables = new CopyOnWriteArrayList<>();
+    private final UpgradeState upgradeState;
+    private final DataTreeEventCallbackRegistrar eventCallbacks;
 
     @Inject
     public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
@@ -139,10 +161,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             final RouterInterfaceVrfEntryHandler routerInterfaceVrfEntryHandler,
                             final JobCoordinator jobCoordinator,
                             final FibUtil fibUtil,
-                            final InterVpnLinkCache interVpnLinkCache) {
+                            final InterVpnLinkCache interVpnLinkCache,
+                            final UpgradeState upgradeState,
+                            final DataTreeEventCallbackRegistrar eventCallbacks) {
         super(VrfEntry.class, VrfEntryListener.class);
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        this.retryingTxRunner = new RetryingManagedNewTransactionRunner(dataBroker, MAX_RETRIES);
         this.mdsalManager = mdsalApiManager;
         this.nextHopManager = nexthopManager;
         this.elanManager = elanManager;
@@ -152,6 +177,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         this.jobCoordinator = jobCoordinator;
         this.fibUtil = fibUtil;
         this.interVpnLinkCache = interVpnLinkCache;
+        this.upgradeState = upgradeState;
+        this.eventCallbacks = eventCallbacks;
     }
 
     @Override
@@ -204,15 +231,15 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
             LOG.info("EVPN flows need to be programmed.");
             EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
-                    nextHopManager, jobCoordinator, elanManager, fibUtil);
+                    nextHopManager, jobCoordinator, fibUtil, upgradeState, eventCallbacks);
             evpnVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
             closeables.add(evpnVrfEntryHandler);
             return;
         }
-        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+        RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
         if (routerInt != null) {
             // ping responder for router interfaces
-            routerInterfaceVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
+            routerInterfaceVrfEntryHandler.createFlows(vrfEntry, rd);
             return;
         }
         if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
@@ -238,15 +265,15 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
             LOG.info("EVPN flows to be deleted");
             EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
-                    nextHopManager, jobCoordinator, elanManager, fibUtil);
+                    nextHopManager, jobCoordinator, fibUtil, upgradeState, eventCallbacks);
             evpnVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
             closeables.add(evpnVrfEntryHandler);
             return;
         }
-        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+        RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
         if (routerInt != null) {
             // ping responder for router interfaces
-            routerInterfaceVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
+            routerInterfaceVrfEntryHandler.removeFlows(vrfEntry, rd);
             return;
         }
         if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
@@ -311,21 +338,34 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             //Update the used rds and vpntoextraroute containers only for the deleted nextHops.
             List<String> nextHopsRemoved = FibHelper.getNextHopListFromRoutePaths(original);
             nextHopsRemoved.removeAll(FibHelper.getNextHopListFromRoutePaths(update));
-            WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
-            nextHopsRemoved.parallelStream()
-                    .forEach(nextHopRemoved -> fibUtil.updateUsedRdAndVpnToExtraRoute(
-                            writeOperTxn, nextHopRemoved, rd, update.getDestPrefix()));
-            CheckedFuture<Void, TransactionCommitFailedException> operFuture = writeOperTxn.submit();
-            try {
-                operFuture.get();
-            } catch (InterruptedException | ExecutionException e) {
-                LOG.error("Exception encountered while submitting operational future for update vrfentry {}: "
-                        + "{}", update, e);
-            }
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            ListenableFuture<Void> configFuture =
+                txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, configTx ->
+                    futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx ->
+                        nextHopsRemoved.parallelStream()
+                            .forEach(nextHopRemoved -> {
+                                try {
+                                    fibUtil.updateUsedRdAndVpnToExtraRoute(
+                                        configTx, operTx, nextHopRemoved, rd, update.getDestPrefix());
+                                } catch (ExecutionException | InterruptedException e) {
+                                    throw new RuntimeException(e);
+                                }
+                            }))));
+            futures.add(configFuture);
+            Futures.addCallback(configFuture, new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(Void result) {
+                    createFibEntries(identifier, update);
+                    LOG.info("UPDATE: Updated static Fib Entry with rd {} prefix {} route-paths {}",
+                            rd, update.getDestPrefix(), update.getRoutePaths());
+                }
 
-            createFibEntries(identifier, update);
-            LOG.info("UPDATE: Updated static Fib Entry with rd {} prefix {} route-paths {}",
-                    rd, update.getDestPrefix(), update.getRoutePaths());
+                @Override
+                public void onFailure(Throwable throwable) {
+                    LOG.error("Exception encountered while submitting operational future for update vrfentry {}",
+                            update, throwable);
+                }
+            }, MoreExecutors.directExecutor());
             return;
         }
 
@@ -364,57 +404,66 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         }
         final Long vpnId = vpnInstance.getVpnId();
         final String rd = vrfTableKey.getRouteDistinguisher();
-        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+        SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
         if (subnetRoute != null) {
             final long elanTag = subnetRoute.getElantag();
             LOG.trace("SUBNETROUTE: createFibEntries: SubnetRoute augmented vrfentry found for rd {} prefix {}"
                     + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
             if (vpnToDpnList != null) {
-                jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), () -> {
-                    WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                    for (final VpnToDpnList curDpn : vpnToDpnList) {
-                        if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
-                            installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx);
-                            installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnId.longValue(),
-                                    vrfEntry, NwConstants.ADD_FLOW, tx);
-                        }
-                    }
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    futures.add(tx.submit());
-                    return futures;
-                });
+                jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
+                    () -> Collections.singletonList(
+                        txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                            for (final VpnToDpnList curDpn : vpnToDpnList) {
+                                if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+                                    installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx);
+                                    installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnId.longValue(),
+                                        vrfEntry, NwConstants.ADD_FLOW, tx);
+                                }
+                            }
+                        })));
             }
             return;
         }
+        // Get etherType value based on the IpPrefix address family type
+        int etherType;
+        try {
+            etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
+        } catch (IllegalArgumentException ex) {
+            LOG.error("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
+            return;
+        }
 
-        final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
+        final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry, etherType);
         if (!localDpnIdList.isEmpty() && vpnToDpnList != null) {
-            jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), () -> {
-                WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                    for (VpnToDpnList vpnDpn : vpnToDpnList) {
-                        if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
-                            if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
-                                try {
-                                    if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
-                                        bgpRouteVrfEntryHandler.createRemoteFibEntry(vpnDpn.getDpnId(),
-                                                vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry, tx, txnObjects);
-                                    } else {
-                                        createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
-                                                vrfTableKey.getRouteDistinguisher(), vrfEntry, tx);
+            jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
+                () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                    final ReentrantLock lock = lockFor(vpnInstance);
+                    lock.lock();
+                    try {
+                        for (VpnToDpnList vpnDpn : vpnToDpnList) {
+                            if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
+                                if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+                                    try {
+                                        if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
+                                            bgpRouteVrfEntryHandler.createRemoteFibEntry(vpnDpn.getDpnId(),
+                                                    vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry,
+                                                    TransactionAdapter.toWriteTransaction(tx),
+                                                    txnObjects);
+                                        } else {
+                                            createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
+                                                    vrfTableKey.getRouteDistinguisher(), vrfEntry, tx);
+                                        }
+                                    } catch (NullPointerException e) {
+                                        LOG.error("Failed to get create remote fib flows for prefix {} ",
+                                                vrfEntry.getDestPrefix(), e);
                                     }
-                                } catch (NullPointerException e) {
-                                    LOG.error("Failed to get create remote fib flows for prefix {} ",
-                                            vrfEntry.getDestPrefix(), e);
                                 }
                             }
                         }
+                    } finally {
+                        lock.unlock();
                     }
-                }
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                futures.add(tx.submit());
-                return futures;
-            }, DJC_MAX_RETRIES);
+                })), MAX_RETRIES);
         }
 
         Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
@@ -428,7 +477,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         // This is an static route that points to the other endpoint of an InterVpnLink
                         // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
                         installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
-                        installInterVpnRouteInLFib(interVpnLink, vpnUuid, vrfEntry);
+                        installInterVpnRouteInLFib(interVpnLink, vpnUuid, vrfEntry, etherType);
                     }
                 });
             }
@@ -457,7 +506,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
         if (!isPresentInList) {
             LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
-            List<String> vpnInstanceNames = lri.getVpnInstanceList();
+            List<String> vpnInstanceNames =
+                lri.getVpnInstanceList() != null ? new ArrayList<>(lri.getVpnInstanceList()) : new ArrayList<>();
             vpnInstanceNames.add(vpnInstanceName);
             builder.setVpnInstanceList(vpnInstanceNames);
             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build());
@@ -468,16 +518,27 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
-                                         final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx) {
-        Boolean wrTxPresent = true;
+            final long vpnId, final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
         if (tx == null) {
-            wrTxPresent = false;
-            tx = dataBroker.newWriteOnlyTransaction();
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                newTx -> installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, newTx)), LOG,
+                "Error installing subnet route in FIB");
+            return;
+        }
+        int etherType;
+        try {
+            etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
+        } catch (IllegalArgumentException ex) {
+            LOG.error("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
+            return;
         }
         FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
             List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-            synchronized (label.toString().intern()) {
-                LabelRouteInfo lri = getLabelRouteInfo(label);
+            final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
+            final ReentrantLock lock = lockFor(lriKey);
+            lock.lock();
+            try {
+                LabelRouteInfo lri = getLabelRouteInfo(lriKey);
                 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
 
                     if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
@@ -493,6 +554,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     LOG.debug("SUBNETROUTE: installSubnetRouteInFib: Fetched labelRouteInfo for label {} interface {}"
                             + " and got dpn {}", label, lri.getVpnInterfaceName(), lri.getDpnId());
                 }
+            } finally {
+                lock.unlock();
             }
         });
         final List<InstructionInfo> instructions = new ArrayList<>();
@@ -501,16 +564,14 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
         instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
         baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
-                NwConstants.ADD_FLOW, tx, null);
-
+                NwConstants.ADD_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
         if (vrfEntry.getRoutePaths() != null) {
             for (RoutePaths routePath : vrfEntry.getRoutePaths()) {
                 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
                     List<ActionInfo> actionsInfos = new ArrayList<>();
                     // reinitialize instructions list for LFIB Table
                     final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
-
-                    actionsInfos.add(new ActionPopMpls());
+                    actionsInfos.add(new ActionPopMpls(etherType));
                     LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
                     LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
                             MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
@@ -521,13 +582,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 }
             }
         }
-        if (!wrTxPresent) {
-            tx.submit();
-        }
     }
 
     private void installSubnetBroadcastAddrDropRule(final BigInteger dpnId, final String rd, final long vpnId,
-                                                    final VrfEntry vrfEntry, int addOrRemove, WriteTransaction tx) {
+            final VrfEntry vrfEntry, int addOrRemove, TypedWriteTransaction<Configuration> tx) {
         List<MatchInfo> matches = new ArrayList<>();
 
         LOG.debug("SUBNETROUTE: installSubnetBroadcastAddrDropRule: destPrefix {} rd {} vpnId {} dpnId {}",
@@ -570,13 +628,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         Node nodeDpn = FibUtil.buildDpnNode(dpnId);
 
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
 
         if (addOrRemove == NwConstants.ADD_FLOW) {
-            tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
+            tx.put(flowInstanceId,flow, true);
         } else {
-            tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+            tx.delete(flowInstanceId);
         }
     }
 
@@ -585,7 +643,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
      * LportDispatcher table (via table 80)
      */
     private void installInterVpnRouteInLFib(final InterVpnLinkDataComposite interVpnLink, final String vpnName,
-                                            final VrfEntry vrfEntry) {
+                                            final VrfEntry vrfEntry, int etherType) {
         // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
         // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
         // packet is commuted from Vpn2 to Vpn1.
@@ -596,7 +654,6 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             return;
         }
 
-        List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
         Optional<Long> optLportTag = interVpnLink.getEndpointLportTagByVpnName(vpnName);
         if (!optLportTag.isPresent()) {
             LOG.warn("Could not retrieve lportTag for VPN {} endpoint in InterVpnLink {}", vpnName, interVpnLinkName);
@@ -610,7 +667,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                       vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
             return;
         }
-        List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
+        List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls(etherType));
         List<InstructionInfo> instructions = Arrays.asList(
             new InstructionApplyActions(actionsInfos),
             new InstructionWriteMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
@@ -619,6 +676,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                          MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
             new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
         List<String> interVpnNextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
+        List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
 
         for (BigInteger dpId : targetDpns) {
             LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
@@ -703,47 +761,66 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         }
     }
 
-    private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
+    private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry, int etherType) {
         List<BigInteger> returnLocalDpnId = new ArrayList<>();
         String localNextHopIP = vrfEntry.getDestPrefix();
         Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, localNextHopIP);
         String vpnName = fibUtil.getVpnNameFromId(vpnId);
         if (localNextHopInfo == null) {
-            List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP);
-            List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
-                    vpnName, usedRds, localNextHopIP);
             boolean localNextHopSeen = false;
-            //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
-            for (Routes vpnExtraRoute : vpnExtraRoutes) {
-                String ipPrefix;
-                if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) {
-                    ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
-                } else {
-                    ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
+            List<Routes> vpnExtraRoutes = null;
+            //Synchronized to prevent missing bucket action due to race condition between refreshFib and
+            // add/updateFib threads on missing nexthop in VpnToExtraroutes
+            // FIXME: use an Identifier structure?
+            final ReentrantLock lock = JvmGlobalLocks.getLockForString(localNextHopIP + FibConstants.SEPARATOR + rd);
+            lock.lock();
+            try {
+                List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP);
+                vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
+                        vpnName, usedRds, localNextHopIP);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Creating Local fib entry with vpnName {} usedRds {} localNextHopIP {} vpnExtraRoutes {}",
+                            vpnName, usedRds, localNextHopIP, vpnExtraRoutes);
                 }
-                Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId,
-                    ipPrefix);
-                if (localNextHopInfoLocal != null) {
-                    localNextHopSeen = true;
-                    BigInteger dpnId =
-                            checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(),
-                                    vpnId, rd, vrfEntry, vpnId, vpnExtraRoute, vpnExtraRoutes);
-                    returnLocalDpnId.add(dpnId);
+
+                //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
+                for (Routes vpnExtraRoute : vpnExtraRoutes) {
+                    String ipPrefix;
+                    if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) {
+                        ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
+                    } else {
+                        ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
+                    }
+                    Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId,
+                            ipPrefix);
+                    if (localNextHopInfoLocal != null) {
+                        localNextHopSeen = true;
+                        BigInteger dpnId =
+                                checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(),
+                                        vpnId, rd, vrfEntry, vpnExtraRoute, vpnExtraRoutes, etherType);
+                        returnLocalDpnId.add(dpnId);
+                    }
                 }
+            } finally {
+                lock.unlock();
             }
             if (!localNextHopSeen && RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
                 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
                 if (optionalLabel.isPresent()) {
                     Long label = optionalLabel.get();
                     List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                    synchronized (label.toString().intern()) {
-                        LabelRouteInfo lri = getLabelRouteInfo(label);
+                    final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
+                    final ReentrantLock labelLock = lockFor(lriKey);
+                    labelLock.lock();
+                    try {
+                        LabelRouteInfo lri = getLabelRouteInfo(lriKey);
                         if (isPrefixAndNextHopPresentInLri(localNextHopIP, nextHopAddressList, lri)) {
                             Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
                                     fibUtil.getVpnInstanceOpData(rd);
                             if (vpnInstanceOpDataEntryOptional.isPresent()) {
                                 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
-                                if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
+                                if (lri.getVpnInstanceList() != null && lri.getVpnInstanceList().contains(
+                                       vpnInstanceName)) {
                                     localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
                                     localNextHopIP = lri.getPrefix();
                                 } else {
@@ -756,19 +833,19 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                         label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
                                 if (vpnExtraRoutes.isEmpty()) {
                                     BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
-                                            vpnId, rd, vrfEntry, lri.getParentVpnid(), null, vpnExtraRoutes);
+                                            vpnId, rd, vrfEntry, null, vpnExtraRoutes, etherType);
                                     returnLocalDpnId.add(dpnId);
                                 } else {
                                     for (Routes extraRoutes : vpnExtraRoutes) {
-                                        BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo,
-                                                localNextHopIP,
-                                                vpnId, rd, vrfEntry, lri.getParentVpnid(),
-                                                extraRoutes, vpnExtraRoutes);
+                                        BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
+                                                vpnId, rd, vrfEntry, extraRoutes, vpnExtraRoutes, etherType);
                                         returnLocalDpnId.add(dpnId);
                                     }
                                 }
                             }
                         }
+                    } finally {
+                        labelLock.unlock();
                     }
                 }
             }
@@ -777,7 +854,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             }
         } else {
             BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
-                    rd, vrfEntry, vpnId, /*routes*/ null, /*vpnExtraRoutes*/ null);
+                    rd, vrfEntry, /*routes*/ null, /*vpnExtraRoutes*/ null, etherType);
             if (dpnId != null) {
                 returnLocalDpnId.add(dpnId);
             }
@@ -787,8 +864,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
 
     private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
                                                 final Long vpnId, final String rd,
-                                                final VrfEntry vrfEntry, Long parentVpnId,
-                                                Routes routes, List<Routes> vpnExtraRoutes) {
+                                                final VrfEntry vrfEntry,
+                                                @Nullable Routes routes, @Nullable List<Routes> vpnExtraRoutes,
+                                                int etherType) {
         String vpnName = fibUtil.getVpnNameFromId(vpnId);
         if (localNextHopInfo != null) {
             long groupId;
@@ -804,33 +882,28 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
                 return dpnId;
             }
-            String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
+            if (!isVpnPresentInDpn(rd, dpnId)) {
+                LOG.error("checkCreateLocalFibEntry: The VPN with id {} rd {} is not available on dpn {}",
+                        vpnId, rd, dpnId.toString());
+                return BigInteger.ZERO;
+            }
             String interfaceName = localNextHopInfo.getVpnInterfaceName();
             String prefix = vrfEntry.getDestPrefix();
             String gwMacAddress = vrfEntry.getGatewayMacAddress();
             //The loadbalancing group is created only if the extra route has multiple nexthops
             //to avoid loadbalancing the discovered routes
-            if (vpnExtraRoutes != null) {
-                if (isIpv4Address(routes.getNexthopIpList().get(0))) {
-                    localNextHopIP = routes.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
-                } else {
-                    localNextHopIP = routes.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
-                }
+            if (RouteOrigin.STATIC.getValue().equals(vrfEntry.getOrigin()) && vpnExtraRoutes != null
+                    && routes != null) {
                 if (vpnExtraRoutes.size() > 1) {
-                    groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
-                            vpnExtraRoutes);
-                    localGroupId = nextHopManager.getLocalNextHopGroup(parentVpnId, localNextHopIP);
-                } else if (routes.getNexthopIpList().size() > 1) {
-                    groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
-                            vpnExtraRoutes);
-                    localGroupId = groupId;
+                    groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes);
+                    localGroupId = nextHopManager.getLocalSelectGroup(vpnId, vrfEntry.getDestPrefix());
                 } else {
-                    groupId = nextHopManager.getLocalNextHopGroup(parentVpnId, localNextHopIP);
+                    groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes);
                     localGroupId = groupId;
                 }
             } else {
-                groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, interfaceName, localNextHopIP, prefix,
-                        gwMacAddress, jobKey);
+                groupId = nextHopManager.createLocalNextHop(vpnId, dpnId, interfaceName, localNextHopIP, prefix,
+                        gwMacAddress);
                 localGroupId = groupId;
             }
             if (groupId == FibConstants.INVALID_GROUP_ID) {
@@ -843,43 +916,33 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             Collections.singletonList(new ActionGroup(groupId))));
             final List<InstructionInfo> lfibinstructions = Collections.singletonList(
                     new InstructionApplyActions(
-                            Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
+                            Arrays.asList(new ActionPopMpls(etherType), new ActionGroup(localGroupId))));
             java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
             List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-            jobCoordinator.enqueueJob(jobKey, () -> {
-                WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
-                        NwConstants.ADD_FLOW, tx, null);
-                if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(),
-                        vpnName, rd)) {
-                    optLabel.ifPresent(label -> {
-                        if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
-                            LOG.debug("Installing LFIB and tunnel table entry on dpn {} for interface {} with label "
-                                            + "{}, rd {}, prefix {}, nexthop {}", dpnId,
-                                    localNextHopInfo.getVpnInterfaceName(), optLabel, rd, vrfEntry.getDestPrefix(),
-                                    nextHopAddressList);
-                            makeLFibTableEntry(dpnId, label, lfibinstructions, DEFAULT_FIB_FLOW_PRIORITY,
-                                    NwConstants.ADD_FLOW, tx);
-                            // If the extra-route is reachable from VMs attached to the same switch,
-                            // then the tunnel table can point to the load balancing group.
-                            // If it is reachable from VMs attached to different switches,
-                            // then it should be pointing to one of the local group in order to avoid looping.
-                            if (vrfEntry.getRoutePaths().size() == 1) {
-                                makeTunnelTableEntry(dpnId, label, groupId, tx);
-                            } else {
+            String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
+            jobCoordinator.enqueueJob(jobKey,
+                () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                    baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
+                            NwConstants.ADD_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
+                    if (FibUtil.isBgpVpn(vpnName, rd)) {
+                        optLabel.ifPresent(label -> {
+                            if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
+                                LOG.debug(
+                                        "Installing LFIB and tunnel table entry on dpn {} for interface {} with label "
+                                                + "{}, rd {}, prefix {}, nexthop {}", dpnId,
+                                        localNextHopInfo.getVpnInterfaceName(), optLabel, rd, vrfEntry.getDestPrefix(),
+                                        nextHopAddressList);
+                                makeLFibTableEntry(dpnId, label, lfibinstructions, DEFAULT_FIB_FLOW_PRIORITY,
+                                        NwConstants.ADD_FLOW, tx);
                                 makeTunnelTableEntry(dpnId, label, localGroupId, tx);
+                            } else {
+                                LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported "
+                                                + "route. LFib and Terminating table entries will not be created.",
+                                        rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
                             }
-                        } else {
-                            LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported "
-                                            + "route. LFib and Terminating table entries will not be created.",
-                                    rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
-                        }
-                    });
-                }
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                futures.add(tx.submit());
-                return futures;
-            });
+                        });
+                    }
+                })));
             return dpnId;
         }
         LOG.error("localNextHopInfo received is null for prefix {} on rd {} on vpn {}", vrfEntry.getDestPrefix(), rd,
@@ -887,9 +950,21 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         return BigInteger.ZERO;
     }
 
+    private boolean isVpnPresentInDpn(String rd, BigInteger dpnId)  {
+        InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        return dpnInVpn.isPresent();
+    }
+
+    @Nullable
     private LabelRouteInfo getLabelRouteInfo(Long label) {
+        return getLabelRouteInfo(new LabelRouteInfoKey(label));
+    }
+
+    @Nullable
+    private LabelRouteInfo getLabelRouteInfo(LabelRouteInfoKey label) {
         InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
-            .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
+            .child(LabelRouteInfo.class, label).build();
         Optional<LabelRouteInfo> opResult = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
         if (opResult.isPresent()) {
             return opResult.get();
@@ -897,7 +972,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         return null;
     }
 
-    private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName, WriteTransaction tx) {
+    private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName,
+            @Nullable TypedWriteTransaction<Operational> tx) {
         if (lri == null) {
             return true;
         }
@@ -915,7 +991,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         if (vpnInstancesList.isEmpty()) {
             LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
             if (tx != null) {
-                tx.delete(LogicalDatastoreType.OPERATIONAL, lriId);
+                tx.delete(lriId);
             } else {
                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
             }
@@ -929,7 +1005,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
-                                      WriteTransaction tx) {
+                                      TypedWriteTransaction<Configuration> tx) {
         List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
 
         createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
@@ -939,7 +1015,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
-                                                WriteTransaction tx) {
+                                                TypedWriteTransaction<Configuration> tx) {
         List<MatchInfo> mkMatches = new ArrayList<>();
 
         LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
@@ -964,14 +1040,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
 
         Node nodeDpn = FibUtil.buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+            .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
             .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
             .child(Flow.class, flowKey).build();
-        tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),
-                WriteTransaction.CREATE_MISSING_PARENTS);
+        tx.put(flowInstanceId, flowbld.build(), CREATE_MISSING_PARENTS);
     }
 
-    private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
+    private void removeTunnelTableEntry(BigInteger dpId, long label, TypedWriteTransaction<Configuration> tx) {
         FlowEntity flowEntity;
         LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
         List<MatchInfo> mkMatches = new ArrayList<>();
@@ -985,10 +1060,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         Node nodeDpn = FibUtil.buildDpnNode(flowEntity.getDpnId());
         FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+            .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
             .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
 
-        tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        tx.delete(flowInstanceId);
         LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
     }
 
@@ -996,7 +1071,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         List<BigInteger> returnLocalDpnId = new ArrayList<>();
         Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
         String vpnName = fibUtil.getVpnNameFromId(vpnId);
-        boolean isExtraroute = false;
+        boolean shouldUpdateNonEcmpLocalNextHop = true;
         if (localNextHopInfo == null) {
             List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
             if (usedRds.size() > 1) {
@@ -1004,12 +1079,12 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         vrfEntry.getDestPrefix(), vpnName, rd);
                 return returnLocalDpnId;
             }
+            String vpnRd = !usedRds.isEmpty() ? usedRds.get(0) : rd;
             //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency
             //in the vpn
             Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
-                    vpnName, rd, vrfEntry.getDestPrefix());
+                    vpnName, vpnRd, vrfEntry.getDestPrefix());
             if (extraRouteOptional.isPresent()) {
-                isExtraroute = true;
                 Routes extraRoute = extraRouteOptional.get();
                 String ipPrefix;
                 if (isIpv4Address(extraRoute.getNexthopIpList().get(0))) {
@@ -1017,16 +1092,17 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 } else {
                     ipPrefix = extraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
                 }
+                if (extraRoute.getNexthopIpList().size() > 1) {
+                    shouldUpdateNonEcmpLocalNextHop = false;
+                }
                 localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, ipPrefix);
                 if (localNextHopInfo != null) {
                     String localNextHopIP = localNextHopInfo.getIpAddress();
-                    BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
-                            vpnId, rd, vrfEntry, isExtraroute, vpnId /*parentVpnId*/);
+                    BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, vpnName, vpnId, rd,
+                            vrfEntry, shouldUpdateNonEcmpLocalNextHop);
                     if (!dpnId.equals(BigInteger.ZERO)) {
                         LOG.trace("Deleting ECMP group for prefix {}, dpn {}", vrfEntry.getDestPrefix(), dpnId);
-                        nextHopManager.setupLoadBalancingNextHop(vpnId, dpnId,
-                                vrfEntry.getDestPrefix(), /*listBucketInfo*/ Collections.emptyList(),
-                                /*remove*/ false);
+                        nextHopManager.deleteLoadBalancingNextHop(vpnId, dpnId, vrfEntry.getDestPrefix());
                         returnLocalDpnId.add(dpnId);
                     }
                 } else {
@@ -1046,7 +1122,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         PrefixesBuilder prefixBuilder = new PrefixesBuilder();
                         prefixBuilder.setDpnId(lri.getDpnId());
                         BigInteger dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), nextHopAddressList.get(0),
-                                vpnId, rd, vrfEntry, isExtraroute, lri.getParentVpnid());
+                                vpnName, vpnId, rd, vrfEntry, shouldUpdateNonEcmpLocalNextHop);
                         if (!dpnId.equals(BigInteger.ZERO)) {
                             returnLocalDpnId.add(dpnId);
                         }
@@ -1057,8 +1133,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         } else {
             LOG.debug("Obtained prefix to interface for rd {} prefix {}", rd, vrfEntry.getDestPrefix());
             String localNextHopIP = localNextHopInfo.getIpAddress();
-            BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
-                vpnId, rd, vrfEntry, isExtraroute, vpnId /*parentVpnId*/);
+            BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, vpnName, vpnId, rd, vrfEntry,
+                    shouldUpdateNonEcmpLocalNextHop);
             if (!dpnId.equals(BigInteger.ZERO)) {
                 returnLocalDpnId.add(dpnId);
             }
@@ -1068,8 +1144,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     private BigInteger checkDeleteLocalFibEntry(Prefixes localNextHopInfo, final String localNextHopIP,
-                                                final Long vpnId, final String rd, final VrfEntry vrfEntry,
-                                                boolean isExtraroute, final Long parentVpnId) {
+            final String vpnName, final Long vpnId, final String rd, final VrfEntry vrfEntry,
+            boolean shouldUpdateNonEcmpLocalNextHop) {
         if (localNextHopInfo != null) {
             final BigInteger dpnId = localNextHopInfo.getDpnId();
             if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
@@ -1083,13 +1159,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 return dpnId;
             }
 
-            jobCoordinator.enqueueJob(FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId,
-                    vrfEntry.getDestPrefix()), () -> {
-                    WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+            jobCoordinator.enqueueJob(FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix()),
+                () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
                     baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
-                            NwConstants.DEL_FLOW, tx, null);
-                    if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(),
-                            vpnId, rd)) {
+                            NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
+                    if (FibUtil.isBgpVpn(vpnName, rd)) {
                         if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
                             FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
                                 makeLFibTableEntry(dpnId, label, null /* instructions */, DEFAULT_FIB_FLOW_PRIORITY,
@@ -1098,14 +1172,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             });
                         }
                     }
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    futures.add(tx.submit());
-                    return futures;
-                });
+                })));
             //TODO: verify below adjacency call need to be optimized (?)
             //In case of the removal of the extra route, the loadbalancing group is updated
-            if (!isExtraroute) {
-                baseVrfEntryHandler.deleteLocalAdjacency(dpnId, parentVpnId, localNextHopIP, vrfEntry.getDestPrefix());
+            if (shouldUpdateNonEcmpLocalNextHop) {
+                baseVrfEntryHandler.deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
             }
             return dpnId;
         }
@@ -1113,66 +1184,80 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, String rd,
-            final VrfEntry vrfEntry, WriteTransaction tx) {
-        Boolean wrTxPresent = true;
+            final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
         if (tx == null) {
-            wrTxPresent = false;
-            tx = dataBroker.newWriteOnlyTransaction();
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                newTx -> createRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, newTx)), LOG,
+                "Error creating remote FIB entry");
+            return;
         }
 
         String vpnName = fibUtil.getVpnNameFromId(vpnId);
-        LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
-                vrfEntry.getDestPrefix(), rd, remoteDpnId);
+        LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}", vrfEntry.getDestPrefix(), rd,
+                remoteDpnId);
 
-        List<AdjacencyResult> adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
-        if (adjacencyResults.isEmpty()) {
-            LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}",
-                    vrfEntry.getRoutePaths(), rd, remoteDpnId);
-            LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd);
+        if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) {
+            programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx);
             return;
         }
-
+        // Handling static VRF entries
         List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
-        List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
-                vpnName, usedRds, vrfEntry.getDestPrefix());
-        // create loadbalancing groups for extra routes only when the extra route is present behind
-        // multiple VMs
-        if (!vpnExtraRoutes.isEmpty() && (vpnExtraRoutes.size() > 1
-                || vpnExtraRoutes.get(0).getNexthopIpList().size() > 1)) {
-            List<InstructionInfo> instructions = new ArrayList<>();
-            // Obtain the local routes for this particular dpn.
-            java.util.Optional<Routes> routes = vpnExtraRoutes
-                    .stream()
-                    .filter(route -> {
-                        Prefixes prefixToInterface = fibUtil.getPrefixToInterface(vpnId,
-                                fibUtil.getIpPrefix(route.getNexthopIpList().get(0)));
-                        if (prefixToInterface == null) {
-                            return false;
-                        }
-                        return remoteDpnId.equals(prefixToInterface.getDpnId());
-                    }).findFirst();
-            long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
-                    routes.isPresent() ? routes.get() : null, vpnExtraRoutes);
-            if (groupId == FibConstants.INVALID_GROUP_ID) {
-                LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}",
-                        vrfEntry.getDestPrefix(), rd, remoteDpnId.toString());
-                return;
-            }
-            List<ActionInfo> actionInfos =
-                    Collections.singletonList(new ActionGroup(groupId));
-            instructions.add(new InstructionApplyActions(actionInfos));
-            baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions,
-                    NwConstants.ADD_FLOW, tx, null);
+        List<Routes> vpnExtraRoutes =
+                VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, vpnName, usedRds, vrfEntry.getDestPrefix());
+        if (!vpnExtraRoutes.isEmpty()) {
+            programRemoteFibWithLoadBalancingGroups(remoteDpnId, vpnId, rd, vrfEntry, vpnExtraRoutes);
         } else {
-            baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, null);
+            // Program in case of other static VRF entries like floating IPs
+            programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx);
         }
+    }
 
-        if (!wrTxPresent) {
-            tx.submit();
+    private void programRemoteFibWithLoadBalancingGroups(final BigInteger remoteDpnId, final long vpnId, String rd,
+            final VrfEntry vrfEntry, List<Routes> vpnExtraRoutes) {
+        // create loadbalancing groups for extra routes only when the extra route is
+        // present behind multiple VMs
+        // Obtain the local routes for this particular dpn.
+        java.util.Optional<Routes> routes = vpnExtraRoutes.stream().filter(route -> {
+            Prefixes prefixToInterface =
+                    fibUtil.getPrefixToInterface(vpnId, FibUtil.getIpPrefix(route.getNexthopIpList().get(0)));
+            if (prefixToInterface == null) {
+                return false;
+            }
+            return remoteDpnId.equals(prefixToInterface.getDpnId());
+        }).findFirst();
+        long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
+                routes.isPresent() ? routes.get() : null, vpnExtraRoutes);
+        if (groupId == FibConstants.INVALID_GROUP_ID) {
+            LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}", vrfEntry.getDestPrefix(), rd,
+                    remoteDpnId);
+            return;
         }
+        List<ActionInfo> actionInfos = Collections.singletonList(new ActionGroup(groupId));
+        List<InstructionInfo> instructions = Lists.newArrayList(new InstructionApplyActions(actionInfos));
+        String jobKey = FibUtil.getCreateRemoteNextHopJobKey(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
+        jobCoordinator.enqueueJob(jobKey,
+            () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(txn -> {
+                baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions,
+                        NwConstants.ADD_FLOW, txn, null);
+            })));
+
         LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
     }
 
+    private void programRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, String rd,
+            final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
+        List<AdjacencyResult> adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
+        if (adjacencyResults.isEmpty()) {
+            LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}", vrfEntry.getRoutePaths(), rd,
+                    remoteDpnId);
+            LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd);
+            return;
+        }
+        baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, TransactionAdapter.toWriteTransaction(tx),
+                rd, adjacencyResults, null);
+        LOG.debug("Successfully programmed FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
+    }
+
     protected void cleanUpOpDataForFib(Long vpnId, String primaryRd, final VrfEntry vrfEntry) {
     /* Get interface info from prefix to interface mapping;
         Use the interface info to get the corresponding vpn interface op DS entry,
@@ -1188,7 +1273,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
             String usedRd = usedRds.isEmpty() ? primaryRd : usedRds.get(0);
             Routes extraRoute = baseVrfEntryHandler.getVpnToExtraroute(vpnId, usedRd, vrfEntry.getDestPrefix());
-            if (extraRoute != null) {
+            if (extraRoute != null && extraRoute.getNexthopIpList() != null) {
                 for (String nextHopIp : extraRoute.getNexthopIpList()) {
                     LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
                     if (nextHopIp != null) {
@@ -1227,7 +1312,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     }
 
     private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
-                                          final VrfEntry vrfEntry, final Routes extraRoute) {
+                                          final VrfEntry vrfEntry, @Nullable final Routes extraRoute) {
 
         if (prefixInfo == null) {
             LOG.error("Cleanup VPN Data Failed as unable to find prefix Info for prefix {} VpnId {} rd {}",
@@ -1266,16 +1351,19 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         public List<ListenableFuture<Void>> call() {
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
-            return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
                 //First Cleanup LabelRouteInfo
                 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
                 LOG.debug("cleanupVpnInterfaceWorker: rd {} prefix {}", rd, prefixInfo.getIpAddress());
                 if (VrfEntry.EncapType.Mplsgre.equals(vrfEntry.getEncapType())) {
                     FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
                         List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                        synchronized (label.toString().intern()) {
-                            LabelRouteInfo lri = getLabelRouteInfo(label);
-                            if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
+                        final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
+                        final ReentrantLock lock = lockFor(lriKey);
+                        lock.lock();
+                        try {
+                            LabelRouteInfo lri = getLabelRouteInfo(lriKey);
+                            if (lri != null && Objects.equals(lri.getPrefix(), vrfEntry.getDestPrefix())
                                     && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
                                 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
                                         fibUtil.getVpnInstanceOpData(rd);
@@ -1293,6 +1381,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
                                         rd, vrfEntry.getDestPrefix()));
                             }
+                        } finally {
+                            lock.unlock();
                         }
                     });
                 }
@@ -1301,8 +1391,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 String vpnName = null;
 
                 if (Prefixes.PrefixCue.PhysNetFunc.equals(prefixInfo.getPrefixCue())) {
-                    /*Get vpnId for rd = networkId since op vpnInterface will be pointing to rd = networkId
-                    * */
+                    // Get vpnId for rd = networkId since op vpnInterface will be pointing to rd = networkId
                     Optional<String> vpnNameOpt = fibUtil.getVpnNameFromRd(vrfEntry.getParentVpnRd());
                     if (vpnNameOpt.isPresent()) {
                         vpnId = fibUtil.getVpnId(vpnNameOpt.get());
@@ -1310,9 +1399,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 }
                 if (optVpnName.isPresent()) {
                     vpnName = optVpnName.get();
-                    Optional<VpnInterfaceOpDataEntry> opVpnInterface = MDSALUtil
-                            .read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                                    fibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
+                    Optional<VpnInterfaceOpDataEntry> opVpnInterface = tx
+                            .read(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)).get();
                     if (opVpnInterface.isPresent()) {
                         long associatedVpnId = fibUtil.getVpnId(vpnName);
                         if (vpnId != associatedVpnId) {
@@ -1331,38 +1419,62 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     //Only one used Rd present in case of removal event
                     String usedRd = usedRds.get(0);
                     if (optVpnName.isPresent()) {
-                        tx.delete(LogicalDatastoreType.OPERATIONAL,
-                                baseVrfEntryHandler.getVpnToExtrarouteIdentifier(vpnName, usedRd,
+                        tx.delete(BaseVrfEntryHandler.getVpnToExtrarouteIdentifier(vpnName, usedRd,
                                         vrfEntry.getDestPrefix()));
-                        tx.delete(LogicalDatastoreType.CONFIGURATION,
-                                VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix()));
+                        txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, configTx ->
+                            configTx.delete(VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix())));
                     }
                 }
-                Optional<AdjacenciesOp> optAdjacencies =
-                    MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                                   FibUtil.getAdjListPathOp(ifName, vpnName));
-                int numAdj = 0;
-                if (optAdjacencies.isPresent()) {
-                    numAdj = optAdjacencies.get().getAdjacency().size();
-                }
-                //remove adjacency corr to prefix
-                if (numAdj > 1) {
-                    LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {} vpnName {}", vpnId,
-                             vrfEntry.getDestPrefix(), vpnName);
-                    tx.delete(LogicalDatastoreType.OPERATIONAL,
-                              FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
-                } else {
-                    //this is last adjacency (or) no more adjacency left for this vpn interface, so
-                    //clean up the vpn interface from DpnToVpn list
-                    LOG.info("Clean up vpn interface {} from dpn {} to vpn {} list.",
-                             ifName, prefixInfo.getDpnId(), rd);
-                    tx.delete(LogicalDatastoreType.OPERATIONAL,
-                              FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
-                }
+                handleAdjacencyAndVpnOpInterfaceDeletion(vrfEntry, ifName, vpnName, tx);
             }));
         }
     }
 
+    /**
+     * Check all the adjacency in VpnInterfaceOpData and decide whether to delete the entire interface or only adj.
+     * Remove Adjacency from VPNInterfaceOpData.
+     * if Adjacency != primary.
+     * if Adjacency == primary , then mark it for deletion.
+     * Remove entire VPNinterfaceOpData Entry.
+     * if sie of Adjacency <= 2 and all are marked for deletion , delete the entire VPNinterface Op entry.
+     * @param vrfEntry - VrfEntry removed
+     * @param ifName - Interface name from VRFentry
+     * @param vpnName - VPN name of corresponding VRF
+     * @param tx - ReadWrite Tx
+     */
+    private void handleAdjacencyAndVpnOpInterfaceDeletion(VrfEntry vrfEntry, String ifName, String vpnName,
+                                                          TypedReadWriteTransaction<Operational> tx)
+            throws ExecutionException, InterruptedException {
+        InstanceIdentifier<Adjacency> adjacencyIid =
+                FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix());
+        Optional<Adjacency> adjacencyOptional = tx.read(adjacencyIid).get();
+        if (adjacencyOptional.isPresent()) {
+            if (adjacencyOptional.get().getAdjacencyType() != Adjacency.AdjacencyType.PrimaryAdjacency) {
+                tx.delete(FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
+            } else {
+                tx.merge(adjacencyIid,
+                        new AdjacencyBuilder(adjacencyOptional.get()).setMarkedForDeletion(true).build());
+            }
+        }
+
+        Optional<AdjacenciesOp> optAdjacencies = tx.read(FibUtil.getAdjListPathOp(ifName, vpnName)).get();
+
+        if (!optAdjacencies.isPresent() || optAdjacencies.get().getAdjacency() == null) {
+            return;
+        }
+
+        @NonNull List<Adjacency> adjacencies = optAdjacencies.get().nonnullAdjacency();
+        if (adjacencies.size() <= 2
+                && adjacencies.stream().allMatch(adjacency ->
+                adjacency.getAdjacencyType() == Adjacency.AdjacencyType.PrimaryAdjacency
+                        && adjacency.isMarkedForDeletion() != null
+                        && adjacency.isMarkedForDeletion()
+        )) {
+            LOG.info("Clean up vpn interface {} to vpn {} list.", ifName, vpnName);
+            tx.delete(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
+        }
+    }
+
     private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
         final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
         final String rd = vrfTableKey.getRouteDistinguisher();
@@ -1384,7 +1496,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             vpnToDpnList = vpnInstance.getVpnToDpnList();
         }
 
-        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+        SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
         final java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
         List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
         String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
@@ -1394,24 +1506,29 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
             if (vpnToDpnList != null) {
                 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
-                    () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                        for (final VpnToDpnList curDpn : vpnToDpnList) {
-
-                            baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
-                                vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx, null);
-                            if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
-                                optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(), label, null,
+                    () -> Collections.singletonList(
+                        txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                            for (final VpnToDpnList curDpn : vpnToDpnList) {
+
+                                baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(),
+                                    vrfEntry, vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW,
+                                    TransactionAdapter.toWriteTransaction(tx), null);
+                                if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
+                                    optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(), label, null,
                                         DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx));
-                            }
+                                }
 
-                            installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnInstance.getVpnId(),
+                                installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnInstance.getVpnId(),
                                     vrfEntry, NwConstants.DEL_FLOW, tx);
-                        }
-                    })));
+                            }
+                        })));
             }
             optionalLabel.ifPresent(label -> {
-                synchronized (label.toString().intern()) {
-                    LabelRouteInfo lri = getLabelRouteInfo(label);
+                final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
+                final ReentrantLock lock = lockFor(lriKey);
+                lock.lock();
+                try {
+                    LabelRouteInfo lri = getLabelRouteInfo(lriKey);
                     if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
                         Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
                                 fibUtil.getVpnInstanceOpData(rd);
@@ -1433,6 +1550,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         LOG.trace("SUBNETROUTE: deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
                                 label, rd, vrfEntry.getDestPrefix());
                     }
+                } finally {
+                    lock.unlock();
                 }
             });
             return;
@@ -1447,7 +1566,6 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             Optional<Routes> extraRouteOptional;
             //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
             if (usedRds != null && !usedRds.isEmpty()) {
-                jobKey = FibUtil.getJobKeyForRdPrefix(usedRds.get(0), vrfEntry.getDestPrefix());
                 if (usedRds.size() > 1) {
                     LOG.error("The extra route prefix is still present in some DPNs");
                     return ;
@@ -1458,33 +1576,36 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             .getVpnExtraroutes(dataBroker, vpnName, usedRds.get(0), vrfEntry.getDestPrefix());
                 }
             } else {
-                jobKey = FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix());
                 extraRouteOptional = Optional.absent();
             }
 
-            jobCoordinator.enqueueJob(jobKey,
-                () -> {
-                    WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-
+            jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
+                () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
                     if (localDpnIdList.size() <= 0) {
                         for (VpnToDpnList curDpn : vpnToDpnList) {
                             baseVrfEntryHandler.deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
-                                vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
+                                vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional,
+                                TransactionAdapter.toWriteTransaction(tx));
                         }
                     } else {
                         for (BigInteger localDpnId : localDpnIdList) {
                             for (VpnToDpnList curDpn : vpnToDpnList) {
-                                if (!curDpn.getDpnId().equals(localDpnId)) {
+                                if (!Objects.equals(curDpn.getDpnId(), localDpnId)) {
                                     baseVrfEntryHandler.deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
-                                        vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
+                                        vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional,
+                                        TransactionAdapter.toWriteTransaction(tx));
                                 }
                             }
                         }
                     }
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    futures.add(tx.submit());
-                    return futures;
-                }, DJC_MAX_RETRIES);
+                    if (extraRouteOptional.isPresent()) {
+                        //Remove select groups only for extra-routes
+                        nextHopManager.removeNextHopPointer(nextHopManager
+                                .getRemoteSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix()));
+                        nextHopManager.removeNextHopPointer(nextHopManager
+                                .getLocalSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix()));
+                    }
+                })), MAX_RETRIES);
         }
 
         //The flow/group entry has been deleted from config DS; need to clean up associated operational
@@ -1512,12 +1633,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
 
     }
 
-    private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
-                                    int addOrRemove, WriteTransaction tx) {
-        Boolean wrTxPresent = true;
+    private void makeLFibTableEntry(BigInteger dpId, long label, @Nullable List<InstructionInfo> instructions,
+                                    int priority, int addOrRemove, TypedWriteTransaction<Configuration> tx) {
         if (tx == null) {
-            wrTxPresent = false;
-            tx = dataBroker.newWriteOnlyTransaction();
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                newTx -> makeLFibTableEntry(dpId, label, instructions, priority, addOrRemove, newTx)), LOG,
+                "Error making LFIB table entry");
+            return;
         }
 
         List<MatchInfo> matches = new ArrayList<>();
@@ -1535,16 +1657,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         FlowKey flowKey = new FlowKey(new FlowId(flowId));
         Node nodeDpn = FibUtil.buildDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+            .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
             .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
 
         if (addOrRemove == NwConstants.ADD_FLOW) {
-            tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, WriteTransaction.CREATE_MISSING_PARENTS);
+            tx.put(flowInstanceId, flow, CREATE_MISSING_PARENTS);
         } else {
-            tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
-        }
-        if (!wrTxPresent) {
-            tx.submit();
+            tx.delete(flowInstanceId);
         }
 
         LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
@@ -1554,77 +1673,87 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
                                     final FutureCallback<List<Void>> callback) {
         LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
-        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-        final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
-        final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
-        List<SubTransaction> txnObjects =  new ArrayList<>();
-        if (!vrfTable.isPresent()) {
-            LOG.info("populateFibOnNewDpn: dpn: {}: VRF Table not yet available for RD {}", dpnId, rd);
-            if (callback != null) {
-                List<ListenableFuture<Void>> futures = new ArrayList<>();
-                ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
-                Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
-            }
-            return;
-        }
-
         jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
             () -> {
+                InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+                final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
+                final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, id);
                 List<ListenableFuture<Void>> futures = new ArrayList<>();
-                synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                    WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                    for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-                        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-                        if (subnetRoute != null) {
-                            long elanTag = subnetRoute.getElantag();
-                            installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
-                            installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW, tx);
-                            continue;
-                        }
-                        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
-                        if (routerInt != null) {
-                            LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
-                                rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
-                            routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
-                                    routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
-                                    NwConstants.ADD_FLOW);
-                            continue;
-                        }
-                        //Handle local flow creation for imports
-                        if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
-                            java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
-                            if (optionalLabel.isPresent()) {
-                                List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                                LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
-                                if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
-                                    if (lri.getDpnId().equals(dpnId)) {
-                                        createLocalFibEntry(vpnId, rd, vrfEntry);
-                                        continue;
+                if (!vrfTable.isPresent()) {
+                    LOG.info("populateFibOnNewDpn: dpn: {}: VRF Table not yet available for RD {}", dpnId, rd);
+                    if (callback != null) {
+                        ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+                        Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
+                    }
+                    return futures;
+                }
+
+                final ReentrantLock lock = lockFor(vpnInstance);
+                lock.lock();
+                try {
+                    futures.add(retryingTxRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
+                        for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry()) {
+                            SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
+                            if (subnetRoute != null) {
+                                long elanTag = subnetRoute.getElantag();
+                                installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
+                                installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW,
+                                        tx);
+                                continue;
+                            }
+                            RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
+                            if (routerInt != null) {
+                                LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
+                                        rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
+                                routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
+                                        routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
+                                        NwConstants.ADD_FLOW);
+                                continue;
+                            }
+                            //Handle local flow creation for imports
+                            if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
+                                java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
+                                if (optionalLabel.isPresent()) {
+                                    List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
+                                    LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
+                                    if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
+                                        if (Objects.equals(lri.getDpnId(), dpnId)) {
+                                            try {
+                                                int etherType = NWUtil.getEtherTypeFromIpPrefix(
+                                                        vrfEntry.getDestPrefix());
+                                                createLocalFibEntry(vpnId, rd, vrfEntry, etherType);
+                                            } catch (IllegalArgumentException ex) {
+                                                LOG.warn("Unable to get etherType for IP Prefix {}",
+                                                        vrfEntry.getDestPrefix());
+                                            }
+                                            continue;
+                                        }
                                     }
                                 }
                             }
-                        }
-
-                        boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
-                                vrfEntry, dpnId);
-                        if (shouldCreateRemoteFibEntry) {
-                            LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}",
+                            boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
                                     vrfEntry, dpnId);
-                            if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
-                                bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
-                                        vrfTable.get().getRouteDistinguisher(), vrfEntry, tx, txnObjects);
-                            } else {
-                                createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
-                                        vrfEntry, tx);
+                            if (shouldCreateRemoteFibEntry) {
+                                LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}", vrfEntry, dpnId);
+                                if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
+                                    List<SubTransaction> txnObjects =  new ArrayList<>();
+                                    bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
+                                            vrfTable.get().getRouteDistinguisher(), vrfEntry,
+                                            TransactionAdapter.toWriteTransaction(tx), txnObjects);
+                                } else {
+                                    createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
+                                            vrfEntry, tx);
+                                }
                             }
                         }
+                    }));
+                    if (callback != null) {
+                        ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+                        Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
                     }
-                    //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
-                    futures.add(tx.submit());
-                }
-                if (callback != null) {
-                    ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
-                    Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
+                } finally {
+                    lock.unlock();
                 }
                 return futures;
             });
@@ -1640,18 +1769,18 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
         if (vrfTable.isPresent()) {
             jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
-                () -> {
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                        WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
-                        vrfTable.get().getVrfEntry().stream()
+                () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                    final ReentrantLock lock = lockFor(vpnInstance);
+                    lock.lock();
+                    try {
+                        vrfTable.get().nonnullVrfEntry().stream()
                             .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
                             .forEach(bgpRouteVrfEntryHandler.getConsumerForCreatingRemoteFib(dpnId, vpnId,
-                                        rd, remoteNextHopIp, vrfTable, writeCfgTxn, txnObjects));
-                        futures.add(writeCfgTxn.submit());
+                                rd, remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx), txnObjects));
+                    } finally {
+                        lock.unlock();
                     }
-                    return futures;
-                });
+                })));
         }
     }
 
@@ -1670,8 +1799,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         }
 
         jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, localDpnId),
-            () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                synchronized (vpnInstance.getVpnInstanceName().intern()) {
+            () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                final ReentrantLock lock = lockFor(vpnInstance);
+                lock.lock();
+                try {
                     VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
                     VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
                     if (vrfEntry == null) {
@@ -1704,14 +1835,16 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         //Is this fib route an extra route? If yes, get the nexthop which would be
                         //an adjacency in the vpn
                         Optional<Routes> extraRouteOptional = Optional.absent();
-                        if (usedRds.size() != 0) {
+                        if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC && usedRds.size() != 0) {
                             extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
                                     fibUtil.getVpnNameFromId(vpnInstance.getVpnId()),
                                     usedRds.get(0), vrfEntry.getDestPrefix());
                         }
                         baseVrfEntryHandler.deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry,
-                                extraRouteOptional, tx);
+                                extraRouteOptional, TransactionAdapter.toWriteTransaction(tx));
                     }
+                } finally {
+                    lock.unlock();
                 }
             })));
     }
@@ -1719,99 +1852,117 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
     public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
                                  final FutureCallback<List<Void>> callback) {
         LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
-        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-        final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
-        List<SubTransaction> txnObjects =  new ArrayList<>();
-        final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
         jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
             () -> {
+                InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+                final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
+                List<SubTransaction> txnObjects =  new ArrayList<>();
+                final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, id);
                 List<ListenableFuture<Void>> futures = new ArrayList<>();
                 if (vrfTable.isPresent()) {
-                    synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                        for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                    final ReentrantLock lock = lockFor(vpnInstance);
+                    lock.lock();
+                    try {
+                        futures.add(retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                            String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
+                            for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry()) {
+                                /* parentRd is only filled for external PNF cases where the interface on the external
+                                 * network VPN are used to cleanup the flows. For all other cases, use "rd" for
+                                 * #fibUtil.isInterfacePresentInDpn().
+                                * */
+                                String parentRd = vrfEntry.getParentVpnRd() != null ? vrfEntry.getParentVpnRd()
+                                        : rd;
                                 /* Handle subnet routes here */
-                            SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-                            if (subnetRoute != null) {
-                                LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
-                                        + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
-                                baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
-                                        NwConstants.DEL_FLOW, tx, null);
-                                List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
-                                if (routePaths != null) {
-                                    for (RoutePaths routePath : routePaths) {
-                                        makeLFibTableEntry(dpnId, routePath.getLabel(), null,
-                                                DEFAULT_FIB_FLOW_PRIORITY,
-                                                NwConstants.DEL_FLOW, tx);
-                                        LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {} for"
-                                                + " rd {} prefix {}", routePath.getLabel(), rd,
-                                                vrfEntry.getDestPrefix());
+                                SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
+                                if (subnetRoute != null && !fibUtil
+                                        .isInterfacePresentInDpn(parentRd, dpnId)) {
+                                    LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
+                                            + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
+                                    baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
+                                            NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
+                                    List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
+                                    if (routePaths != null) {
+                                        for (RoutePaths routePath : routePaths) {
+                                            makeLFibTableEntry(dpnId, routePath.getLabel(), null,
+                                                    DEFAULT_FIB_FLOW_PRIORITY,
+                                                    NwConstants.DEL_FLOW, tx);
+                                            LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {}"
+                                                    + " for rd {} prefix {}", routePath.getLabel(), rd,
+                                                    vrfEntry.getDestPrefix());
+                                        }
                                     }
+                                    installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
+                                            NwConstants.DEL_FLOW, tx);
+                                    continue;
+                                }
+                                // ping responder for router interfaces
+                                RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
+                                if (routerInt != null) {
+                                    LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
+                                            rd, routerInt.getUuid(), routerInt.getIpAddress(),
+                                            routerInt.getMacAddress());
+                                    routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
+                                            routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
+                                            NwConstants.DEL_FLOW);
+                                    continue;
                                 }
-                                installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
-                                        NwConstants.DEL_FLOW, tx);
-                                continue;
-                            }
-                            // ping responder for router interfaces
-                            RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
-                            if (routerInt != null) {
-                                LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
-                                    rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
-                                routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
-                                        routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
-                                        NwConstants.DEL_FLOW);
-                                continue;
-                            }
 
-                            //Handle local flow deletion for imports
-                            if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
-                                java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
-                                if (optionalLabel.isPresent()) {
-                                    List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
-                                    LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
-                                    if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
-                                        if (lri.getDpnId().equals(dpnId)) {
+                                //Handle local flow deletion for imports
+                                if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
+                                    java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
+                                    if (optionalLabel.isPresent()) {
+                                        List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
+                                        LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
+                                        if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList,
+                                                lri) && Objects.equals(lri.getDpnId(), dpnId)) {
                                             deleteLocalFibEntry(vpnId, rd, vrfEntry);
-                                            continue;
                                         }
                                     }
                                 }
-                            }
 
-                            // Passing null as we don't know the dpn
-                            // to which prefix is attached at this point
-                            List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
-                                    vrfEntry.getDestPrefix());
-                            String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
-                            Optional<Routes> extraRouteOptional;
-                            //Is this fib route an extra route? If yes, get the nexthop which would be
-                            //an adjacency in the vpn
-                            if (usedRds != null && !usedRds.isEmpty()) {
-                                if (usedRds.size() > 1) {
-                                    LOG.error("The extra route prefix is still present in some DPNs");
-                                    return futures;
-                                } else {
-                                    extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
-                                            usedRds.get(0), vrfEntry.getDestPrefix());
+                                // Passing null as we don't know the dpn
+                                // to which prefix is attached at this point
+                                List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
+                                        vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
+                                Optional<Routes> extraRouteOptional;
+                                //Is this fib route an extra route? If yes, get the nexthop which would be
+                                //an adjacency in the vpn
+                                if (usedRds != null && !usedRds.isEmpty()) {
+                                    if (usedRds.size() > 1) {
+                                        LOG.error("The extra route prefix is still present in some DPNs");
+                                        return;
+                                    } else {
+                                        extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
+                                                usedRds.get(0), vrfEntry.getDestPrefix());
 
+                                    }
+                                } else {
+                                    extraRouteOptional = Optional.absent();
+                                }
+                                if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
+                                    bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId,
+                                        vrfTable.get().key(), vrfEntry, extraRouteOptional,
+                                        TransactionAdapter.toWriteTransaction(tx), txnObjects);
+                                } else {
+                                    if (subnetRoute == null || !fibUtil
+                                            .isInterfacePresentInDpn(parentRd, dpnId)) {
+                                        baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId,
+                                            vrfTable.get().key(), vrfEntry, extraRouteOptional,
+                                            TransactionAdapter.toWriteTransaction(tx));
+                                    }
                                 }
-                            } else {
-                                extraRouteOptional = Optional.absent();
-                            }
-                            if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
-                                bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
-                                        vrfEntry, extraRouteOptional, tx, txnObjects);
-                            } else {
-                                baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
-                                        vrfEntry, extraRouteOptional, tx);
                             }
-                        }
-                        futures.add(tx.submit());
+                        }));
+                    } finally {
+                        lock.unlock();
                     }
                     if (callback != null) {
                         ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
                         Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
                     }
+                } else {
+                    LOG.error("cleanUpDpnForVpn: No vrf table found for rd {} vpnId {} dpn {}", rd, vpnId, dpnId);
                 }
                 return futures;
             });
@@ -1830,16 +1981,19 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         if (vrfTable.isPresent()) {
             jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
                 () -> {
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    synchronized (vpnInstance.getVpnInstanceName().intern()) {
-                        WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
-                        vrfTable.get().getVrfEntry().stream()
-                            .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
-                            .forEach(bgpRouteVrfEntryHandler.getConsumerForDeletingRemoteFib(dpnId, vpnId, rd,
-                                remoteNextHopIp, vrfTable, writeCfgTxn, txnObjects));
-                        futures.add(writeCfgTxn.submit());
+                    final ReentrantLock lock = lockFor(vpnInstance);
+                    lock.lock();
+                    try {
+                        return Collections.singletonList(
+                            txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                                tx -> vrfTable.get().nonnullVrfEntry().stream()
+                                    .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
+                                    .forEach(bgpRouteVrfEntryHandler.getConsumerForDeletingRemoteFib(dpnId, vpnId,
+                                        remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx),
+                                        txnObjects))));
+                    } finally {
+                        lock.unlock();
                     }
-                    return futures;
                 });
         }
     }
@@ -1860,6 +2014,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 + tableMiss + FLOWID_PREFIX;
     }
 
+    @Nullable
     private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
         InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
             .child(VrfTables.class, new VrfTablesKey(rd))
@@ -1892,7 +2047,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         optNextHop.ifPresent(nextHop -> {
             String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
             FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-            Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
+            Flow flow = new FlowBuilder().withKey(flowKey).setId(new FlowId(flowRef))
                     .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
 
             LOG.trace("Removing flow in FIB table for interVpnLink {} key {}", interVpnLinkName, flowRef);
@@ -1909,19 +2064,20 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         optLabel.ifPresent(label -> {
             LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
 
-            WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-            for (BigInteger dpId : targetDpns) {
-                LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
-                          vrfEntry.getDestPrefix(), label, dpId, interVpnLinkName);
-                makeLFibTableEntry(dpId, label, /*instructions*/null, LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);
-            }
-            tx.submit();
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                for (BigInteger dpId : targetDpns) {
+                    LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
+                            vrfEntry.getDestPrefix(), label, dpId, interVpnLinkName);
+                    makeLFibTableEntry(dpId, label, /*instructions*/null, LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW,
+                            tx);
+                }
+            }), LOG, "Error removing flows");
         });
     }
 
-    private boolean isPrefixAndNextHopPresentInLri(String prefix,
+    private static boolean isPrefixAndNextHopPresentInLri(String prefix,
             List<String> nextHopAddressList, LabelRouteInfo lri) {
-        return lri != null && lri.getPrefix().equals(prefix)
+        return lri != null && Objects.equals(lri.getPrefix(), prefix)
                 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));
     }
 
@@ -1941,4 +2097,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         }
         return true;
     }
+
+    private static ReentrantLock lockFor(final VpnInstanceOpDataEntry vpnInstance) {
+        // FIXME: use vpnInstance.key() instead?
+        return JvmGlobalLocks.getLockForString(vpnInstance.getVpnInstanceName());
+    }
+
+    private static ReentrantLock lockFor(LabelRouteInfoKey label) {
+        return JvmGlobalLocks.getLockFor(label);
+    }
 }