Close All MDSAL read transcations
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInterfaceManager.java
index 62b2180aff323232918b48173ac7b2c16f069894..02eb7b86cf48f3691142725db0ab41fa9274ba8e 100755 (executable)
@@ -11,7 +11,6 @@ import static java.util.Collections.emptyList;
 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.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -24,20 +23,23 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import javax.annotation.Nullable;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
@@ -56,6 +58,7 @@ import org.opendaylight.genius.mdsalutil.NWUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.infrautils.caches.CacheProvider;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -92,7 +95,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
@@ -220,12 +222,17 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
     private boolean canHandleNewVpnInterface(final InstanceIdentifier<VpnInterface> identifier,
                           final VpnInterface vpnInterface, String vpnName) {
-        synchronized (vpnName.intern()) {
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+        lock.lock();
+        try {
             if (isVpnInstanceReady(vpnName)) {
                 return true;
             }
             addToUnprocessedVpnInterfaces(identifier, vpnInterface, vpnName);
             return false;
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -233,8 +240,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void addVpnInterface(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
                              final @Nullable List<Adjacency> oldAdjs, final @Nullable List<Adjacency> newAdjs) {
-        for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
-                Collections.<VpnInstanceNames>emptyList())) {
+        for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
             String vpnName = vpnInterfaceVpnInstance.getVpnName();
             addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
         }
@@ -283,6 +289,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
                         // (the inventory tx goes in last)
                         List<ListenableFuture<Void>> futures = new ArrayList<>();
+                        //set of prefix used, as entry in prefix-to-interface datastore
+                        // is prerequisite for refresh Fib to avoid race condition leading to
+                        // missing remote next hop in bucket actions on bgp-vpn delete
+                        Set<String> prefixListForRefreshFib = new HashSet<>();
                         ListenableFuture<Void> confFuture =
                             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
                                 confTx -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
@@ -293,7 +303,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                     + " on dpn {}",
                                                 vpnInterface.getName(), vpnName, vpnInterface.getDpnId());
                                             processVpnInterfaceUp(dpnId, vpnInterface, primaryRd, ifIndex, false,
-                                                confTx, operTx, invTx, interfaceState, vpnName);
+                                                confTx, operTx, invTx, interfaceState, vpnName,
+                                                prefixListForRefreshFib);
                                             if (oldAdjs != null && !oldAdjs.equals(newAdjs)) {
                                                 LOG.info("addVpnInterface: Adjacency changed upon VPNInterface {}"
                                                     + " Update for swapping VPN {} case.", interfaceName, vpnName);
@@ -305,7 +316,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                             if (!isBgpVpnInternetVpn
                                                                 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
                                                                 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier,
-                                                                    primaryRd, adj, dpnId, operTx, confTx, invTx);
+                                                                    primaryRd, adj, dpnId, operTx, confTx, invTx,
+                                                                    prefixListForRefreshFib);
                                                             }
                                                         }
                                                     }
@@ -319,6 +331,9 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                 }
                                             }
                                         })))));
+                        Futures.addCallback(confFuture,
+                            new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+                            MoreExecutors.directExecutor());
                         futures.add(confFuture);
                         Futures.addCallback(confFuture, new PostVpnInterfaceWorker(interfaceName, true, "Config"),
                             MoreExecutors.directExecutor());
@@ -365,8 +380,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             TypedWriteTransaction<Configuration> writeConfigTxn,
             TypedWriteTransaction<Operational> writeOperTxn,
             TypedReadWriteTransaction<Configuration> writeInvTxn,
-            Interface interfaceState,
-            final String vpnName) throws ExecutionException, InterruptedException {
+            Interface interfaceState, final String vpnName,
+            Set<String> prefixListForRefreshFib) throws ExecutionException, InterruptedException {
         final String interfaceName = vpnInterface.getName();
         Optional<VpnInterfaceOpDataEntry> optOpVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(interfaceName,
                 vpnName);
@@ -430,7 +445,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         null/*ipAddressSourceValuePair*/,
                         true /* add */);
                 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
-                        vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+                        vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
                 if (!isBgpVpnInternetVpn) {
                     vpnUtil.bindService(vpnName, interfaceName, false /*isTunnelInterface*/);
                 }
@@ -479,7 +494,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     null/*ipAddressSourceValuePair*/,
                     true /* add */);
             processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
-                    vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+                    vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
             if (!isBgpVpnInternetVpn) {
                 vpnUtil.bindService(vpnName, interfaceName, false/*isTunnelInterface*/);
             }
@@ -506,7 +521,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
                     return;
                 }
-                List<Adjacency> adjacencies = requireNonNullElse(optAdjacencies.get().getAdjacency(), emptyList());
+                List<Adjacency> adjacencies = optAdjacencies.get().nonnullAdjacency();
                 for (Adjacency adjacency : adjacencies) {
                     if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
                         continue;
@@ -516,7 +531,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         continue;
                     }
                     addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
-                            dpId, writeOperTxn, writeConfigTxn, writeInvTxn);
+                            dpId, writeOperTxn, writeConfigTxn, writeInvTxn, prefixListForRefreshFib);
                 }
             } catch (ReadFailedException e) {
                 LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
@@ -695,11 +710,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removed Fib Entry rd {}"
                                     + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
                                     interfaceName, vpnName);
-                        } else {
+                        } else if (nextHop.getNextHopIpList() != null) {
                             // Perform similar operation as interface delete event for extraroutes.
                             String allocatedRd = nextHop.getVrfId();
-                            for (String nh : requireNonNullElse(nextHop.getNextHopIpList(),
-                                    Collections.<String>emptyList())) {
+                            for (String nh : nextHop.getNextHopIpList()) {
                                 deleteExtraRouteFromCurrentAndImportingVpns(
                                     vpnName, nextHop.getIpAddress(), nh, allocatedRd, interfaceName, writeConfigTxn,
                                     writeOperTx);
@@ -720,7 +734,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                   TypedWriteTransaction<Configuration> writeConfigTxn,
                                                   TypedWriteTransaction<Operational> writeOperTxn,
                                                   TypedReadWriteTransaction<Configuration> writeInvTxn,
-                                                  Interface interfaceState)
+                                                  Interface interfaceState, Set<String> prefixListForRefreshFib)
             throws ExecutionException, InterruptedException {
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
         // Read NextHops
@@ -768,7 +782,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(l3vni);
         VrfEntry.EncapType encapType = isL3VpnOverVxLan ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
         VpnPopulator registeredPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
-        List<Adjacency> nextHops = (adjacencies != null) ? adjacencies.getAdjacency() : emptyList();
+        List<Adjacency> nextHops = adjacencies != null ? adjacencies.getAdjacency() : emptyList();
         List<Adjacency> value = new ArrayList<>();
         for (Adjacency nextHop : nextHops) {
             String rd = primaryRd;
@@ -788,7 +802,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
                         + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
 
-                Prefixes prefixes = (intfnetworkUuid != null)
+                Prefixes prefixes = intfnetworkUuid != null
                     ? VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, intfnetworkUuid ,networkType,
                             segmentationId, prefixCue) :
                     VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, prefixCue);
@@ -844,7 +858,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 //Extra route adjacency
                 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
                 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
-                synchronized (vpnPrefixKey.intern()) {
+                // FIXME: separate this out somehow?
+                final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
+                lock.lock();
+                try {
                     java.util.Optional<String> rdToAllocate = vpnUtil
                             .allocateRdForExtraRouteAndUpdateUsedRdsMap(vpnId, null, prefix, vpnName,
                                     nextHop.getNextHopIpList().get(0), dpnId);
@@ -856,6 +873,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         LOG.error("processVpnInterfaceAdjacencies: No rds to allocate extraroute {}", prefix);
                         continue;
                     }
+                } finally {
+                    lock.unlock();
                 }
                 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} and nextHopList {} as extra-route for vpn{}"
                         + " interface {} on dpn {}", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName,
@@ -864,8 +883,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             // Please note that primary adjacency will use a subnet-gateway-mac-address that
             // can be different from the gateway-mac-address within the VRFEntry as the
             // gateway-mac-address is a superset.
-            RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
-                    : RouteOrigin.STATIC;
+            RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
             L3vpnInput input = new L3vpnInput().setNextHop(nextHop).setRd(rd).setVpnName(vpnName)
                 .setInterfaceName(interfaceName).setNextHopIp(nextHopIp).setPrimaryRd(primaryRd)
                 .setSubnetGatewayMacAddress(vpnInterfaceSubnetGwMacAddress).setRouteOrigin(origin);
@@ -879,8 +897,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             }
             if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
                 vpnManager.addExtraRoute(vpnName, nextHop.getIpAddress(), nextHop.getNextHopIpList().get(0), rd,
-                        vpnName, l3vni, origin,
-                        interfaceName, operationalAdjacency, encapType, writeConfigTxn);
+                    vpnName, l3vni, origin, interfaceName, operationalAdjacency, encapType, prefixListForRefreshFib,
+                    writeConfigTxn);
             }
             value.add(operationalAdjacency);
         }
@@ -896,8 +914,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         for (Adjacency nextHop : aug.getAdjacency()) {
             // Adjacencies other than primary Adjacencies are handled in the addExtraRoute call above.
             if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
-                RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
-                        : RouteOrigin.STATIC;
+                RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
                 input.setNextHop(nextHop).setRd(nextHop.getVrfId()).setRouteOrigin(origin);
                 registeredPopulator.populateFib(input, writeConfigTxn);
             }
@@ -1180,29 +1197,28 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                 }
                                 String prefix = vrfEntry.getDestPrefix();
                                 String gwMac = vrfEntry.getGatewayMacAddress();
-                                requireNonNullElse(vrfEntry.getRoutePaths(),
-                                    Collections.<RoutePaths>emptyList()).forEach(routePath -> {
-                                        String nh = routePath.getNexthopAddress();
-                                        int label = routePath.getLabel().intValue();
-                                        if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
-                                            vrfEntry.getOrigin()))) {
-                                            LOG.info(
-                                                "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
-                                                    + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
-                                                vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
-                                            fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
-                                                Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
-                                                0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
-                                                confTx);
-                                        } else {
-                                            LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
-                                                    + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
-                                                vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
-                                            SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
-                                            importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
-                                                confTx);
-                                        }
-                                    });
+                                vrfEntry.nonnullRoutePaths().forEach(routePath -> {
+                                    String nh = routePath.getNexthopAddress();
+                                    int label = routePath.getLabel().intValue();
+                                    if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
+                                        vrfEntry.getOrigin()))) {
+                                        LOG.info(
+                                            "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
+                                                + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
+                                            vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
+                                        fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
+                                            Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
+                                            0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
+                                            confTx);
+                                    } else {
+                                        LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
+                                                + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
+                                            vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
+                                        SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
+                                        importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
+                                            confTx);
+                                    }
+                                });
                             } catch (RuntimeException e) {
                                 LOG.error("getNextHopAddressList: Exception occurred while importing route with rd {}"
                                         + " prefix {} routePaths {} to vpn {} vpnRd {}", vpn.getVrfId(),
@@ -1222,8 +1238,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         LOG.trace("Received VpnInterface remove event: vpnInterface={}", vpnInterface);
         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
         final String interfaceName = key.getName();
-        for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
-                Collections.<VpnInstanceNames>emptyList())) {
+        for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
             String vpnName = vpnInterfaceVpnInstance.getVpnName();
             removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
         }
@@ -1315,7 +1330,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                         interfaceName, vpnInterface.getDpnId(), vpnName);
                             })))));
                 futures.add(configFuture);
-                Futures.addCallback(configFuture, new PostVpnInterfaceWorker(interfaceName, false, "Config"));
+                Futures.addCallback(configFuture, new PostVpnInterfaceWorker(
+                        interfaceName, false, "Config"), MoreExecutors.directExecutor());
                 return futures;
             }, DJC_MAX_RETRIES);
     }
@@ -1373,6 +1389,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
             Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                     LogicalDatastoreType.OPERATIONAL, path);
+            boolean isNonPrimaryAdjIp = Boolean.FALSE;
             String primaryRd = vpnUtil.getVpnRd(vpnName);
             LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
                     interfaceName, dpnId, vpnName, primaryRd);
@@ -1392,6 +1409,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         List<String> nhList;
                         if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
                             nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
+                            isNonPrimaryAdjIp = Boolean.TRUE;
                         } else {
                             // This is a primary adjacency
                             nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
@@ -1400,7 +1418,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     interfaceName, writeInvTxn);
                         }
                         if (!nhList.isEmpty()) {
-                            if (Objects.equals(rd, vpnName)) {
+                            if (Objects.equals(primaryRd, vpnName)) {
                                 //this is an internal vpn - the rd is assigned to the vpn instance name;
                                 //remove from FIB directly
                                 nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
@@ -1419,12 +1437,24 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     }
                     String ip = nextHop.getIpAddress().split("/")[0];
                     LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
-                    if (vpnVipToPort != null) {
+                    if (vpnVipToPort != null && vpnVipToPort.getPortName().equals(interfaceName)) {
                         vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
                         LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
                                  + " for Interface {} ip {} on dpn {} for vpn {}",
                                 vpnVipToPort.getPortName(), ip, dpnId, vpnName);
                     }
+                    // Remove the MIP-IP from VpnPortIpToPort.
+                    if (isNonPrimaryAdjIp) {
+                        VpnPortipToPort persistedIp = vpnUtil.getVpnPortipToPort(vpnName, ip);
+                        if (persistedIp != null && persistedIp.isLearntIp()
+                                && persistedIp.getPortName().equals(interfaceName)) {
+                            VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
+                            LOG.info(
+                                    "removeAdjacenciesFromVpn: Learnt-IP: {} interface {} of vpn {} removed "
+                                            + "from VpnPortipToPort",
+                                    persistedIp.getPortFixedip(), persistedIp.getPortName(), vpnName);
+                        }
+                    }
                     VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
                     if (vpnPortipToPort != null) {
                         VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
@@ -1455,7 +1485,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
             LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
                     nextHop, vpnName, interfaceName, dpnId);
-            synchronized (vpnNamePrefixKey.intern()) {
+            // FIXME: separate this out somehow?
+            final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnNamePrefixKey);
+            lock.lock();
+            try {
                 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
                         prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
                     //If extra-route is present behind at least one VM, then do not remove or update
@@ -1465,6 +1498,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 }
                 fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
                         writeConfigTxn);
+            } finally {
+                lock.unlock();
             }
             LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
                             + " nexthop {} for interface {} on dpn {} for internal vpn {}",
@@ -1546,6 +1581,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         LOG.trace("Received VpnInterface update event: original={}, update={}", original, update);
         LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}", update.getName(),
                 update.getDpnId(), original.getVpnInstanceNames(), update.getVpnInstanceNames());
+        if (original.equals(update)) {
+            LOG.info("update: original {} update {} are same. No update required.", original, update);
+            return;
+        }
         final String vpnInterfaceName = update.getName();
         final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
@@ -1568,13 +1607,13 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
                                                            VpnInterface original, VpnInterface update,
                                                            List<ListenableFuture<Void>> futures) {
-        boolean isVpnInstanceUpdate = Boolean.FALSE;
+        boolean isVpnInstanceUpdate = false;
         final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
         final String interfaceName = key.getName();
-        List<String> oldVpnList = vpnUtil.getVpnListForVpnInterface(original);
+        List<String> oldVpnList = VpnUtil.getVpnListForVpnInterface(original);
         List<String> oldVpnListCopy = new ArrayList<>();
         oldVpnListCopy.addAll(oldVpnList);
-        List<String> newVpnList = vpnUtil.getVpnListForVpnInterface(update);
+        List<String> newVpnList = VpnUtil.getVpnListForVpnInterface(update);
         List<String> newVpnListCopy = new ArrayList<>();
         newVpnListCopy.addAll(newVpnList);
 
@@ -1620,10 +1659,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
              *
              *
              */
-            isVpnInstanceUpdate = Boolean.TRUE;
+            isVpnInstanceUpdate = true;
             if (VpnUtil.isDualRouterVpnUpdate(oldVpnListCopy, newVpnListCopy)) {
                 if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
-                        && (oldVpnList.size() == 1 && newVpnList.size() == 0)) {
+                        && oldVpnList.size() == 1 && newVpnList.isEmpty()) {
                     //Identify the external BGP-VPN Instance and pass that value as newVpnList
                     List<String> externalBgpVpnList = new ArrayList<>();
                     for (String newVpnName : newVpnListCopy) {
@@ -1640,7 +1679,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             externalBgpVpnList, oldVpnListCopy, futures);
 
                 } else if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
-                        && (oldVpnList.size() == 0 && newVpnList.size() == 1)) {
+                        && oldVpnList.isEmpty() && newVpnList.size() == 1) {
                     //Identify the router VPN Instance and pass that value as oldVpnList
                     List<String> routerVpnList = new ArrayList<>();
                     for (String newVpnName : newVpnListCopy) {
@@ -1674,10 +1713,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                          List<String> newVpnList, List<String> oldVpnListCopy,
                                          List<ListenableFuture<Void>> futures) {
         final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
-        final List<Adjacency> oldAdjs = (origAdjs != null && origAdjs.getAdjacency() != null)
+        final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency() != null
                 ? origAdjs.getAdjacency() : new ArrayList<>();
         final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
-        final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
+        final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency() != null
                 ? updateAdjs.getAdjacency() : new ArrayList<>();
 
         boolean isOldVpnRemoveCallExecuted = false;
@@ -1741,68 +1780,72 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 != null ? updateAdjs.getAdjacency() : new ArrayList<>();
 
         final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
-        for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(update.getVpnInstanceNames(),
-                Collections.<VpnInstanceNames>emptyList())) {
+        for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames()) {
             String newVpnName = vpnInterfaceVpnInstance.getVpnName();
             List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
             List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
             String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
             if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
                 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
-                futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
-                    futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
-                        InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
+                //set of prefix used as entry in prefix-to-interface datastore
+                // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
+                // in bucket actions on bgp-vpn delete
+                Set<String> prefixListForRefreshFib = new HashSet<>();
+                ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+                    confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
+                        operTx -> {
+                            InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
                                 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
-                        LOG.info("VPN Interface update event - intfName {} onto vpnName {} running config-driven",
-                                update.getName(), newVpnName);
-                        //handle both addition and removal of adjacencies
-                        //currently, new adjacency may be an extra route
-                        boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
-                        if (!oldAdjs.equals(newAdjs)) {
-                            for (Adjacency adj : copyNewAdjs) {
-                                if (copyOldAdjs.contains(adj)) {
-                                    copyOldAdjs.remove(adj);
-                                } else {
-                                    // add new adjacency
-                                    if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
-                                        addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
-                                                dpnId, operTx, confTx, confTx);
+                            LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
+                                    update.getName(), newVpnName);
+                            //handle both addition and removal of adjacencies
+                            // currently, new adjacency may be an extra route
+                            boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
+                            if (!oldAdjs.equals(newAdjs)) {
+                                for (Adjacency adj : copyNewAdjs) {
+                                    if (copyOldAdjs.contains(adj)) {
+                                        copyOldAdjs.remove(adj);
+                                    } else {
+                                        // add new adjacency
+                                        if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+                                            addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
+                                                    dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
+                                        }
+                                        LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
+                                            + " added to vpn interface {} on vpn {} dpnId {}",
+                                            adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
+                                            adj.getSubnetId(), update.getName(), newVpnName, dpnId);
                                     }
-                                    LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} added to"
-                                                    + " vpn interface {} on vpn {} dpnId {}",
-                                            adj.getIpAddress(), adj.getNextHopIpList(),
-                                            adj.getLabel(), adj.getSubnetId(), update.getName(),
-                                            newVpnName, dpnId);
                                 }
-                            }
-                            for (Adjacency adj : copyOldAdjs) {
-                                if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
-                                    if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
+                                for (Adjacency adj : copyOldAdjs) {
+                                    if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+                                        if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
                                             && !adj.isPhysNetworkFunc()) {
-                                        delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
-                                                operTx, confTx);
-                                        //remove FIB entry
-                                        String vpnRd = vpnUtil.getVpnRd(newVpnName);
-                                        LOG.debug("update: remove prefix {} from the FIB and BGP entry "
+                                            delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
+                                                confTx);
+                                            //remove FIB entry
+                                            String vpnRd = vpnUtil.getVpnRd(newVpnName);
+                                            LOG.debug("update: remove prefix {} from the FIB and BGP entry "
                                                 + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
-                                        //remove BGP entry
-                                        fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
-                                        if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
-                                            bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
-                                        }
-                                    } else {
-                                        delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
+                                            //remove BGP entry
+                                            fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
+                                            if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
+                                                bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
+                                            }
+                                        } else {
+                                            delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
                                                 operTx, confTx);
+                                        }
                                     }
-                                }
-                                LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
-                                                + " vpn interface {} on vpn {}", adj.getIpAddress(), adj
-                                                .getNextHopIpList(),
+                                    LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
+                                        + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
                                         adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
+                                }
                             }
-                        }
-                    }));
-                }));
+                        })));
+                Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+                    MoreExecutors.directExecutor());
+                futures.add(configTxFuture);
                 for (ListenableFuture<Void> future : futures) {
                     ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
                             update.getName(), update.getVpnInstanceNames());
@@ -1816,19 +1859,21 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     private void updateLabelMapper(Long label, List<String> nextHopIpList) {
+        final String labelStr = Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!")
+                .toString();
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(labelStr);
+        lock.lock();
         try {
-            Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!");
-            synchronized (label.toString().intern()) {
-                InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
-                        .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
-                Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                        LogicalDatastoreType.OPERATIONAL, lriIid);
-                if (opResult.isPresent()) {
-                    LabelRouteInfo labelRouteInfo =
-                            new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
-                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
-                            labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
-                }
+            InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
+                    .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
+            Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                LogicalDatastoreType.OPERATIONAL, lriIid);
+            if (opResult.isPresent()) {
+                LabelRouteInfo labelRouteInfo =
+                        new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
+                    labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
             }
             LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
                     nextHopIpList);
@@ -1838,6 +1883,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         } catch (TransactionCommitFailedException e) {
             LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
                     nextHopIpList);
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -1865,7 +1912,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                            Adjacency adj, BigInteger dpnId,
                                            TypedWriteTransaction<Operational> writeOperTxn,
                                            TypedWriteTransaction<Configuration> writeConfigTxn,
-                                           TypedReadWriteTransaction<Configuration> writeInvTxn)
+                                           TypedReadWriteTransaction<Configuration> writeInvTxn,
+                                           Set<String> prefixListForRefreshFib)
             throws ExecutionException, InterruptedException {
         String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
         String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
@@ -1900,17 +1948,20 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             currVpnIntf.getName());
                     if (interfaceState != null) {
                         processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
-                                currVpnIntf.getName(),
-                                vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+                            currVpnIntf.getName(), vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState,
+                            prefixListForRefreshFib);
                     }
                 }
                 if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
                         && adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
-                    RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
+                    RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.LearntIp ? RouteOrigin.DYNAMIC
                             : RouteOrigin.STATIC;
                     String nh = adj.getNextHopIpList().get(0);
                     String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
-                    synchronized (vpnPrefixKey.intern()) {
+                    // FIXME: separate out to somehow?
+                    final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
+                    lock.lock();
+                    try {
                         java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
                                 vpnId, null, prefix, vpnName, nh, dpnId);
                         if (rdToAllocate.isPresent()) {
@@ -1919,7 +1970,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             int label = operationalAdjacency.getLabel().intValue();
                             vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
                                     currVpnIntf.getVpnInstanceName(), l3vni, origin,
-                                    currVpnIntf.getName(), operationalAdjacency, encapType, writeConfigTxn);
+                                    currVpnIntf.getName(), operationalAdjacency, encapType,
+                                    prefixListForRefreshFib, writeConfigTxn);
                             LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
                                             + " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
                                     vpnName, label, currVpnIntf.getName(), dpnId);
@@ -1940,14 +1992,15 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                             vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
                                             .ifPresent(
                                                 rds -> vpnManager.addExtraRoute(
-                                                        vpnUtil.getVpnName(vpn.getVpnId()),
-                                                        adj.getIpAddress(), nh, rds,
-                                                        currVpnIntf.getVpnInstanceName(), l3vni,
-                                                        RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(),
-                                                        opAdjacency, encapType, writeConfigTxn));
+                                                        vpnUtil.getVpnName(vpn.getVpnId()), adj.getIpAddress(),
+                                                        nh, rds, currVpnIntf.getVpnInstanceName(), l3vni,
+                                                        RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), opAdjacency,
+                                                        encapType, prefixListForRefreshFib, writeConfigTxn));
                                 }
                             });
                         }
+                    } finally {
+                        lock.unlock();
                     }
                 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
                     LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
@@ -2022,6 +2075,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         for (Adjacency adjacency : adjacencies) {
                             if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
                                 String rd = adjacency.getVrfId();
+                                InstanceIdentifier<Adjacency> adjIdentifier = VpnUtil
+                                        .getVpnInterfaceOpDataEntryAdjacencyIdentifier(currVpnIntf.getName(),
+                                                currVpnIntf.getVpnInstanceName(), adj.getIpAddress());
+                                LOG.debug("delAdjFromVpnInterface: adjIdentifier {}", adjIdentifier);
+                                writeOperTxn.delete(adjIdentifier);
                                 if (adj.getNextHopIpList() != null) {
                                     for (String nh : adj.getNextHopIpList()) {
                                         deleteExtraRouteFromCurrentAndImportingVpns(
@@ -2104,12 +2162,12 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
                         + " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
                         macAddress);
-                return;
+            } else {
+                LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
+                                + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}",
+                        interfaceName, primaryRd, vpnName);
             }
         }
-        LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
-                + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}", interfaceName,
-                primaryRd, vpnName);
     }
 
     protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
@@ -2117,7 +2175,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
         String rd = vpnUtil.getVpnRd(vpnName);
         if (adjs != null) {
-            List<Adjacency> adjsList = requireNonNullElse(adjs.getAdjacency(), emptyList());
+            List<Adjacency> adjsList = adjs.nonnullAdjacency();
             for (Adjacency adj : adjsList) {
                 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
                     String primaryInterfaceIp = adj.getIpAddress();
@@ -2125,7 +2183,6 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
                     LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
                             + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
-                    return;
                 }
             }
         } else {
@@ -2167,7 +2224,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
-        synchronized (vpnInstanceName.intern()) {
+        // FIXME: separate out to somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnInstanceName);
+        lock.lock();
+        try {
             ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
                     unprocessedVpnInterfaces.get(vpnInstanceName);
             if (vpnInterfaces != null) {
@@ -2185,24 +2245,30 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             } else {
                 LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
             }
+        } finally {
+            lock.unlock();
         }
     }
 
     private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
             VpnInterface vpnInterface) {
-        synchronized (VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface).intern()) {
+        // FIXME: use VpnInstanceNamesKey perhaps? What about nulls?
+        final String firstVpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface);
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(firstVpnName);
+        lock.lock();
+        try {
             ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
-                unprocessedVpnInterfaces.get(VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+                    unprocessedVpnInterfaces.get(firstVpnName);
             if (vpnInterfaces != null) {
                 if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
                     LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
-                            + "unprocessed list", vpnInterface.getName(),
-                            VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+                            + "unprocessed list", vpnInterface.getName(), firstVpnName);
                 }
             } else {
-                LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}",
-                        VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+                LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}", firstVpnName);
             }
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -2292,8 +2358,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
                         return;
                     }
-                    List<Adjacency> operationVpnAdjacencies = requireNonNullElse(vpnInterfaceOptional.get()
-                            .augmentation(AdjacenciesOp.class).getAdjacency(), emptyList());
+                    List<Adjacency> operationVpnAdjacencies = vpnInterfaceOptional.get()
+                            .augmentation(AdjacenciesOp.class).nonnullAdjacency();
                     // Due to insufficient rds,  some of the extra route wont get processed when it is added.
                     // The unprocessed adjacencies will be present in config vpn interface DS but will be missing
                     // in operational DS. These unprocessed adjacencies will be handled below.
@@ -2312,12 +2378,21 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
                                         List<ListenableFuture<Void>> futures = new ArrayList<>();
                                         futures.add(
-                                            txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
-                                                futures.add(
+                                            txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
+                                                //set of prefix used, as entry in prefix-to-interface datastore
+                                                // is prerequisite for refresh Fib to avoid race condition leading
+                                                // to missing remote next hop in bucket actions on bgp-vpn delete
+                                                Set<String> prefixListForRefreshFib = new HashSet<>();
+                                                ListenableFuture<Void> configTxFuture =
                                                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
                                                         confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
-                                                            primaryRd, adjacency, vpnInterfaceOptional.get()
-                                                                .getDpnId(), operTx, confTx, confTx)))));
+                                                            primaryRd, adjacency, vpnInterfaceOptional.get().getDpnId(),
+                                                                operTx, confTx, confTx, prefixListForRefreshFib));
+                                                Futures.addCallback(configTxFuture,
+                                                    new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+                                                    MoreExecutors.directExecutor());
+                                                futures.add(configTxFuture);
+                                            }));
                                         return futures;
                                     } else {
                                         return emptyList();
@@ -2364,4 +2439,26 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             }
         }
     }
+
+    private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
+        private final String primaryRd;
+        private final Set<String> prefixListForRefreshFib;
+
+        VpnInterfaceCallBackHandler(String primaryRd, Set<String> prefixListForRefreshFib) {
+            this.primaryRd = primaryRd;
+            this.prefixListForRefreshFib = prefixListForRefreshFib;
+        }
+
+        @Override
+        public void onSuccess(Void voidObj) {
+            prefixListForRefreshFib.forEach(prefix -> {
+                fibManager.refreshVrfEntry(primaryRd, prefix);
+            });
+        }
+
+        @Override
+        public void onFailure(Throwable throwable) {
+            LOG.debug("write Tx config operation failed", throwable);
+        }
+    }
 }