MRI version bumpup for Aluminium
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInterfaceManager.java
index 6fc437a9fee7799bdb1457a4ee1d50b93888df0f..bc996c6075581197dfb221f453c9e2396a5a8a07 100755 (executable)
@@ -8,11 +8,9 @@
 package org.opendaylight.netvirt.vpnmanager;
 
 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 com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterators;
 import com.google.common.util.concurrent.FutureCallback;
@@ -20,36 +18,30 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 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.Optional;
 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.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;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 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.TransactionAdapter;
 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
 import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
@@ -57,9 +49,14 @@ 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.Executors;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
@@ -71,10 +68,7 @@ import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
 import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
@@ -93,13 +87,9 @@ 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.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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
-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.Adjacency.AdjacencyType;
-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.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
@@ -113,16 +103,28 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency.AdjacencyType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
-public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInterface, VpnInterfaceManager> {
+public class VpnInterfaceManager extends AbstractAsyncDataTreeChangeListener<VpnInterface> {
 
     private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
     private static final short DJC_MAX_RETRIES = 3;
@@ -162,7 +164,9 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                final JobCoordinator jobCoordinator,
                                final CacheProvider cacheProvider,
                                final VpnUtil vpnUtil) {
-        super(VpnInterface.class, VpnInterfaceManager.class);
+        super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class),
+                Executors.newListeningSingleThreadExecutor("VpnInterfaceManager", LOG));
 
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
@@ -181,16 +185,15 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         vpnInstanceOpDataEntryCache = new InstanceIdDataObjectCache<>(VpnInstanceOpDataEntry.class, dataBroker,
                 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(
                         VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class).build(), cacheProvider);
+        start();
     }
 
     public Runnable isNotifyTaskQueued(String intfName) {
         return vpnIntfMap.remove(intfName);
     }
 
-    @PostConstruct
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
-        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
     @Override
@@ -198,34 +201,31 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     public void close() {
         super.close();
         vpnInstanceOpDataEntryCache.close();
-    }
-
-    @Override
-    protected InstanceIdentifier<VpnInterface> getWildCardPath() {
-        return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
-    }
-
-    @Override
-    protected VpnInterfaceManager getDataTreeChangeListener() {
-        return VpnInterfaceManager.this;
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
     @Override
     public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
         LOG.trace("Received VpnInterface add event: vpnInterface={}", vpnInterface);
         LOG.info("add: intfName {} onto vpnName {}", vpnInterface.getName(),
-                VpnHelper.getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
+                VpnHelper.getVpnInterfaceVpnInstanceNamesString(
+                        new ArrayList<VpnInstanceNames>(vpnInterface.getVpnInstanceNames().values())));
         addVpnInterface(identifier, vpnInterface, null, null);
     }
 
     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,7 +233,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 : vpnInterface.nonnullVpnInstanceNames()) {
+        for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames().values()) {
             String vpnName = vpnInterfaceVpnInstance.getVpnName();
             addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
         }
@@ -276,7 +276,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
             if (interfaceState != null) {
                 try {
-                    final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
+                    final Uint64 dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
                     final int ifIndex = interfaceState.getIfIndex();
                     jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName, () -> {
                         // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
@@ -368,7 +368,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     // "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
     // see comments below.
     @SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
-    protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface, final String primaryRd,
+    protected void processVpnInterfaceUp(final Uint64 dpId, VpnInterface vpnInterface, final String primaryRd,
             final int lportTag, boolean isInterfaceUp,
             TypedWriteTransaction<Configuration> writeConfigTxn,
             TypedWriteTransaction<Operational> writeOperTxn,
@@ -383,8 +383,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         if (!isInterfaceUp) {
             LOG.info("processVpnInterfaceUp: Binding vpn service to interface {} onto dpn {} for vpn {}",
                      interfaceName, dpId, vpnName);
-            long vpnId = vpnUtil.getVpnId(vpnName);
-            if (vpnId == VpnConstants.INVALID_ID) {
+            Uint32 vpnId = vpnUtil.getVpnId(vpnName);
+            if (VpnConstants.INVALID_ID.equals(vpnId)) {
                 LOG.warn("processVpnInterfaceUp: VpnInstance to VPNId mapping not available for VpnName {}"
                         + " processing vpninterface {} on dpn {}, bailing out now.", vpnName, interfaceName,
                         dpId);
@@ -511,11 +511,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 Optional<Adjacencies> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                         LogicalDatastoreType.CONFIGURATION, path);
                 if (!optAdjacencies.isPresent()) {
-                    LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
+                    LOG.trace("No config adjacencyKeyAdjacencyMap present for vpninterface {}", vpnInterface);
                     return;
                 }
-                List<Adjacency> adjacencies = optAdjacencies.get().nonnullAdjacency();
-                for (Adjacency adjacency : adjacencies) {
+                Map<AdjacencyKey, Adjacency> adjacencyKeyAdjacencyMap = optAdjacencies.get().nonnullAdjacency();
+                for (Adjacency adjacency : adjacencyKeyAdjacencyMap.values()) {
                     if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
                         continue;
                     }
@@ -526,14 +526,14 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
                             dpId, writeOperTxn, writeConfigTxn, writeInvTxn, prefixListForRefreshFib);
                 }
-            } catch (ReadFailedException e) {
+            } catch (InterruptedException | ExecutionException e) {
                 LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
                         interfaceName, vpnName, primaryRd, dpId);
             }
         }
     }
 
-    private void processExternalVpnInterface(String interfaceName, String vpnName, BigInteger dpId,
+    private void processExternalVpnInterface(String interfaceName, String vpnName, Uint64 dpId,
         int lportTag, int addOrRemove) {
         Uuid extNetworkId;
         try {
@@ -557,17 +557,19 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 + " for vpn {}", routerIds, interfaceName, dpId, vpnName);
         for (Uuid routerId : routerIds) {
             String routerName = routerId.getValue();
-            BigInteger primarySwitch = vpnUtil.getPrimarySwitchForRouter(routerName);
+            Uint64 primarySwitch = vpnUtil.getPrimarySwitchForRouter(routerName);
             if (Objects.equals(primarySwitch, dpId)) {
                 Routers router = vpnUtil.getExternalRouter(routerName);
                 if (router != null) {
                     if (addOrRemove == NwConstants.ADD_FLOW) {
                         vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
-                                VpnUtil.getIpsListFromExternalIps(router.getExternalIps()), router.getExtGwMacAddress(),
+                                VpnUtil.getIpsListFromExternalIps(new ArrayList<ExternalIps>(router
+                                                .getExternalIps().values())), router.getExtGwMacAddress(),
                                 dpId, interfaceName, lportTag);
                     } else {
                         vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
-                                VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
+                                VpnUtil.getIpsListFromExternalIps(new ArrayList<ExternalIps>(router
+                                        .getExternalIps().values())),
                                 dpId, interfaceName, lportTag);
                     }
                 } else {
@@ -581,7 +583,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void advertiseAdjacenciesForVpnToBgp(final String rd, BigInteger dpnId,
+    private void advertiseAdjacenciesForVpnToBgp(final String rd, Uint64 dpnId,
                                                  final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
                                                   String vpnName, String interfaceName) {
         if (rd == null) {
@@ -612,20 +614,20 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                     LogicalDatastoreType.OPERATIONAL, path);
             if (adjacencies.isPresent()) {
-                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
-                if (nextHops != null && !nextHops.isEmpty()) {
+                Map<AdjacencyKey, Adjacency> nextHopsMap = adjacencies.get().getAdjacency();
+                if (nextHopsMap != null && !nextHopsMap.isEmpty()) {
                     LOG.debug("advertiseAdjacenciesForVpnToBgp:  NextHops are {} for interface {} on dpn {} for vpn {}"
-                            + " rd {}", nextHops, interfaceName, dpnId, vpnName, rd);
+                            + " rd {}", nextHopsMap, interfaceName, dpnId, vpnName, rd);
                     VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(rd);
-                    long l3vni = vpnInstanceOpData.getL3vni();
+                    Uint32 l3vni = vpnInstanceOpData.getL3vni();
                     VrfEntry.EncapType encapType = VpnUtil.isL3VpnOverVxLan(l3vni)
                             ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
-                    for (Adjacency nextHop : nextHops) {
+                    for (Adjacency nextHop : nextHopsMap.values()) {
                         if (nextHop.getAdjacencyType() == AdjacencyType.ExtraRoute) {
                             continue;
                         }
                         String gatewayMac = null;
-                        long label = 0;
+                        Uint32 label = Uint32.ZERO;
                         if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
                             final VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(
                                     vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
@@ -638,7 +640,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Adding Fib Entry rd {} prefix {}"
                                     + " nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
                             bgpManager.advertisePrefix(rd, nextHop.getMacAddress(), nextHop.getIpAddress(), nextHopIp,
-                                    encapType, (int)label, l3vni, 0 /*l2vni*/,
+                                    encapType, label, l3vni, Uint32.ZERO /*l2vni*/,
                                     gatewayMac);
                             LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Added Fib Entry rd {} prefix {}"
                                             + " nexthop {} label {} for interface {} on dpn {} for vpn {}", rd,
@@ -651,7 +653,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     }
                 }
             }
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to read data store for interface {} dpn {} nexthop {}"
                     + "vpn {} rd {}", interfaceName, dpnId, nextHopIp, vpnName, rd);
         }
@@ -679,21 +681,21 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         }
         LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", interfaceName,
                vpnName, rd);
-        Optional<AdjacenciesOp> adjacencies = Optional.absent();
+        Optional<AdjacenciesOp> adjacencies = Optional.empty();
         try {
             adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     path);
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to read data store for interface {} vpn {}",
                     interfaceName, vpnName);
         }
         if (adjacencies.isPresent()) {
-            List<Adjacency> nextHops = adjacencies.get().getAdjacency();
+            Map<AdjacencyKey, Adjacency> nextHopsMap = adjacencies.get().getAdjacency();
 
-            if (nextHops != null && !nextHops.isEmpty()) {
+            if (nextHopsMap != null && !nextHopsMap.isEmpty()) {
                 LOG.trace("withdrawAdjacenciesForVpnFromBgp: NextHops are {} for interface {} in vpn {} rd {}",
-                        nextHops, interfaceName, vpnName, rd);
-                for (Adjacency nextHop : nextHops) {
+                        nextHopsMap, interfaceName, vpnName, rd);
+                for (Adjacency nextHop : nextHopsMap.values()) {
                     try {
                         if (nextHop.getAdjacencyType() != AdjacencyType.ExtraRoute) {
                             LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removing Fib Entry rd {}"
@@ -722,8 +724,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void processVpnInterfaceAdjacencies(BigInteger dpnId, final int lportTag, String vpnName,
-                                                  String primaryRd, String interfaceName, final long vpnId,
+    protected void processVpnInterfaceAdjacencies(Uint64 dpnId, final int lportTag, String vpnName,
+                                                  String primaryRd, String interfaceName, final Uint32 vpnId,
                                                   TypedWriteTransaction<Configuration> writeConfigTxn,
                                                   TypedWriteTransaction<Operational> writeOperTxn,
                                                   TypedReadWriteTransaction<Configuration> writeInvTxn,
@@ -731,11 +733,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             throws ExecutionException, InterruptedException {
         InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
         // Read NextHops
-        Optional<VpnInterface> vpnInteface = Optional.absent();
+        Optional<VpnInterface> vpnInteface = Optional.empty();
         try {
             vpnInteface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
             LogicalDatastoreType.CONFIGURATION, identifier);
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("processVpnInterfaceAdjacencies: Failed to read data store for interface {} vpn {} rd {}"
                     + "dpn {}", interfaceName, vpnName, primaryRd, dpnId);
         }
@@ -746,16 +748,17 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         if (vpnInteface.isPresent()) {
             intfnetworkUuid = vpnInteface.get().getNetworkId();
             networkType = vpnInteface.get().getNetworkType();
-            segmentationId = vpnInteface.get().getSegmentationId();
+            segmentationId = vpnInteface.get().getSegmentationId().toJava();
             adjacencies = vpnInteface.get().augmentation(Adjacencies.class);
             if (adjacencies == null) {
                 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, null/*adjacencies*/, lportTag,
-                        null/*gwMac*/, writeOperTxn);
+                        null/*gwMac*/,  null/*gatewayIp*/, writeOperTxn);
                 return;
             }
         }
         // Get the rd of the vpn instance
         String nextHopIp = null;
+        String gatewayIp = null;
         try {
             nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
         } catch (Exception e) {
@@ -768,16 +771,17 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             LOG.debug("processVpnInterfaceAdjacencies: NextHop for interface {} on dpn {} in vpn {} is {}",
                     interfaceName, dpnId, vpnName, nhList);
         }
-        Optional<String> gwMac = Optional.absent();
+        Optional<String> gwMac = Optional.empty();
         String vpnInterfaceSubnetGwMacAddress = null;
         VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
-        Long l3vni = vpnInstanceOpData.getL3vni();
+        Uint32 l3vni = vpnInstanceOpData.getL3vni() != null ? vpnInstanceOpData.getL3vni() : Uint32.ZERO;
         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();
+        Map<AdjacencyKey, Adjacency> nextHopsMap = adjacencies != null ? adjacencies.getAdjacency()
+                : Collections.<AdjacencyKey, Adjacency>emptyMap();
         List<Adjacency> value = new ArrayList<>();
-        for (Adjacency nextHop : nextHops) {
+        for (Adjacency nextHop : nextHopsMap.values()) {
             String rd = primaryRd;
             String nexthopIpValue = nextHop.getIpAddress().split("/")[0];
             if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet
@@ -792,18 +796,18 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
                 Prefixes.PrefixCue prefixCue = nextHop.isPhysNetworkFunc()
                         ? Prefixes.PrefixCue.PhysNetFunc : Prefixes.PrefixCue.None;
-                LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
-                        + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
+                LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHopsMap {} "
+                        + "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);
-                writeOperTxn.merge(VpnUtil.getPrefixToInterfaceIdentifier(
-                        vpnUtil.getVpnId(vpnName), prefix), prefixes, true);
+                writeOperTxn.mergeParentStructureMerge(VpnUtil.getPrefixToInterfaceIdentifier(
+                        vpnUtil.getVpnId(vpnName), prefix), prefixes);
                 final Uuid subnetId = nextHop.getSubnetId();
 
-                String gatewayIp = nextHop.getSubnetGatewayIp();
+                gatewayIp = nextHop.getSubnetGatewayIp();
                 if (gatewayIp == null) {
                     Optional<String> gatewayIpOptional = vpnUtil.getVpnSubnetGatewayIp(subnetId);
                     if (gatewayIpOptional.isPresent()) {
@@ -845,13 +849,16 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         subnetId, interfaceName, vpnName);
                     gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
                 }
-                LOG.info("processVpnInterfaceAdjacencies: Added prefix {} to interface {} with nextHops {} on dpn {}"
+                LOG.info("processVpnInterfaceAdjacencies: Added prefix {} to interface {} with nextHopsMap {} on dpn {}"
                         + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
             } else {
                 //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);
@@ -863,6 +870,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,
@@ -871,8 +880,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);
@@ -894,31 +902,30 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
         AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
         addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, aug, lportTag,
-                gwMac.isPresent() ? gwMac.get() : null, writeOperTxn);
+                gwMac.isPresent() ? gwMac.get() : null, gatewayIp, writeOperTxn);
 
-        L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni).setPrimaryRd(primaryRd)
-                .setGatewayMac(gwMac.orNull()).setInterfaceName(interfaceName)
+        L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni.longValue()).setPrimaryRd(primaryRd)
+                .setGatewayMac(gwMac.orElse(null)).setInterfaceName(interfaceName)
                 .setVpnName(vpnName).setDpnId(dpnId).setEncapType(encapType);
 
-        for (Adjacency nextHop : aug.getAdjacency()) {
+        for (Adjacency nextHop : aug.getAdjacency().values()) {
             // 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);
             }
         }
     }
 
-    private void addVpnInterfaceToOperational(String vpnName, String interfaceName, BigInteger dpnId, AdjacenciesOp aug,
-                                              long lportTag, String gwMac,
+    private void addVpnInterfaceToOperational(String vpnName, String interfaceName, Uint64 dpnId, AdjacenciesOp aug,
+                                              long lportTag, String gwMac, String gwIp,
                                               TypedWriteTransaction<Operational> writeOperTxn) {
         VpnInterfaceOpDataEntry opInterface =
-              VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac);
+              VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac, gwIp);
         InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId = VpnUtil
             .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
-        writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
+        writeOperTxn.mergeParentStructurePut(interfaceId, opInterface);
         LOG.info("addVpnInterfaceToOperational: Added VPN Interface {} on dpn {} vpn {} to operational datastore",
                 interfaceName, dpnId, vpnName);
     }
@@ -931,40 +938,41 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                            TypedWriteTransaction<Operational> writeOperTxn) {
 
         String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
-        BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
+        Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
         AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
-        List<Adjacency> adjList =
-            adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency() : emptyList();
-        if (adjList.isEmpty()) {
+        Map<AdjacencyKey, Adjacency> keyAdjacencyMap =
+            adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency()
+                    : Collections.<AdjacencyKey, Adjacency>emptyMap();
+        if (keyAdjacencyMap.isEmpty()) {
             LOG.trace("updateVpnInterfaceOnTepAdd: Adjacencies are empty for vpnInterface {} on dpn {}",
                     vpnInterface, srcDpnId);
             return;
         }
         String prefix = null;
-        long label = 0;
         List<Adjacency> value = new ArrayList<>();
-        boolean isNextHopAddReqd = false;
+        boolean isFibNextHopAddReqd = false;
         String vpnName = vpnInterface.getVpnInstanceName();
-        long vpnId = vpnUtil.getVpnId(vpnName);
+        Uint32 vpnId = vpnUtil.getVpnId(vpnName);
         String primaryRd = vpnUtil.getPrimaryRd(vpnName);
         LOG.info("updateVpnInterfaceOnTepAdd: AdjacencyList for interface {} on dpn {} vpn {} is {}",
                 vpnInterface.getName(), vpnInterface.getDpnId(),
-                vpnInterface.getVpnInstanceName(), adjList);
-        for (Adjacency adj : adjList) {
+                vpnInterface.getVpnInstanceName(), keyAdjacencyMap);
+        for (Adjacency adj : keyAdjacencyMap.values()) {
             String rd = adj.getVrfId();
             rd = rd != null ? rd : vpnName;
             prefix = adj.getIpAddress();
-            label = adj.getLabel();
+            Uint32 label = adj.getLabel();
             List<String> nhList = Collections.singletonList(srcTepIp);
             List<String> nextHopList = adj.getNextHopIpList();
             // If TEP is added , update the nexthop of primary adjacency.
             // Secondary adj nexthop is already pointing to primary adj IP address.
-            if (nextHopList == null || nextHopList.isEmpty()) {
-                isNextHopAddReqd = true;
-            }
-
             if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
                 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
+                if (nextHopList != null && !nextHopList.isEmpty()) {
+                    /* everything right already */
+                } else {
+                    isFibNextHopAddReqd = true;
+                }
             } else {
                 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
                 if (!vrfEntryOptional.isPresent()) {
@@ -973,19 +981,19 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
                 if (!nhList.contains(srcTepIp)) {
                     nhList.add(srcTepIp);
-                    isNextHopAddReqd = true;
+                    isFibNextHopAddReqd = true;
                 }
                 value.add(adj);
             }
 
-            if (isNextHopAddReqd) {
+            if (isFibNextHopAddReqd) {
                 updateLabelMapper(label, nhList);
                 LOG.info("updateVpnInterfaceOnTepAdd: Updated label mapper : label {} dpn {} prefix {} nexthoplist {}"
                         + " vpn {} vpnid {} rd {} interface {}", label, srcDpnId , prefix, nhList,
                         vpnInterface.getVpnInstanceName(), vpnId, rd, vpnInterface.getName());
                 // Update the VRF entry with nextHop
-                fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
-                        label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
+                fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp, label, true,
+                        writeConfigTxn);
 
                 //Get the list of VPN's importing this route(prefix) .
                 // Then update the VRF entry with nhList
@@ -993,8 +1001,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
                     String vpnRd = vpn.getVrfId();
                     if (vpnRd != null) {
-                        fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
-                            srcTepIp, label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
+                        fibManager.updateRoutePathForFibEntry(vpnRd, prefix, srcTepIp, label, true,
+                                writeConfigTxn);
                         LOG.info("updateVpnInterfaceOnTepAdd: Exported route with rd {} prefix {} nhList {} label {}"
                                 + " interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix, nhList, label,
                             vpnInterface.getName(), srcDpnId, vpnName,
@@ -1006,7 +1014,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 try {
                     if (!rd.equalsIgnoreCase(vpnName)) {
                         bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, nhList,
-                                VrfEntry.EncapType.Mplsgre, (int)label, 0 /*evi*/, 0 /*l2vni*/,
+                                VrfEntry.EncapType.Mplsgre, label, Uint32.ZERO /*evi*/, Uint32.ZERO /*l2vni*/,
                                 null /*gatewayMacAddress*/);
                     }
                     LOG.info("updateVpnInterfaceOnTepAdd: Advertised rd {} prefix {} nhList {} label {}"
@@ -1025,7 +1033,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 .addAugmentation(AdjacenciesOp.class, aug).build();
         InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
                 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
-        writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
+        writeOperTxn.mergeParentStructurePut(interfaceId, opInterface);
         LOG.info("updateVpnInterfaceOnTepAdd: interface {} updated successully on tep add on dpn {} vpn {}",
                 vpnInterface.getName(), srcDpnId, vpnName);
 
@@ -1039,14 +1047,14 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                               TypedWriteTransaction<Operational> writeOperTxn) {
 
         AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
-        List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency() : new ArrayList<>();
+        List<Adjacency> adjList = adjacencies != null ? new ArrayList<Adjacency>(adjacencies.getAdjacency().values())
+                : new ArrayList<>();
         String prefix = null;
-        long label = 0;
         boolean isNextHopRemoveReqd = false;
         String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
-        BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
+        Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
         String vpnName = vpnInterface.getVpnInstanceName();
-        long vpnId = vpnUtil.getVpnId(vpnName);
+        Uint32 vpnId = vpnUtil.getVpnId(vpnName);
         String primaryRd = vpnUtil.getVpnRd(vpnName);
         if (adjList != null) {
             List<Adjacency> value = new ArrayList<>();
@@ -1059,7 +1067,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 rd = rd != null ? rd : vpnName;
                 prefix = adj.getIpAddress();
                 List<String> nextHopList = adj.getNextHopIpList();
-                label = adj.getLabel();
+                Uint32 label = adj.getLabel();
                 if (nextHopList != null && !nextHopList.isEmpty()) {
                     isNextHopRemoveReqd = true;
                 }
@@ -1087,8 +1095,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             prefix, nhList, vpnName,
                             vpnId, rd, vpnInterface.getName());
                     // Update the VRF entry with removed nextHop
-                    fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
-                            label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
+                    fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp, label, false,
+                            writeConfigTxn);
 
                     //Get the list of VPN's importing this route(prefix) .
                     // Then update the VRF entry with nhList
@@ -1096,8 +1104,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
                         String vpnRd = vpn.getVrfId();
                         if (vpnRd != null) {
-                            fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
-                                srcTepIp, label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
+                            fibManager.updateRoutePathForFibEntry(vpnRd, prefix, srcTepIp, label, false,
+                                    writeConfigTxn);
                             LOG.info("updateVpnInterfaceOnTepDelete: Exported route with rd {} prefix {} nhList {}"
                                     + " label {} interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix,
                                     nhList, label, vpnInterface.getName(), srcDpnId,
@@ -1128,23 +1136,30 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     .addAugmentation(AdjacenciesOp.class, aug).build();
             InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
                     VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
-            writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
+            writeOperTxn.mergeParentStructurePut(interfaceId, opInterface);
             LOG.info("updateVpnInterfaceOnTepDelete: interface {} updated successully on tep delete on dpn {} vpn {}",
                          vpnInterface.getName(), srcDpnId, vpnName);
         }
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
     private List<VpnInstanceOpDataEntry> getVpnsExportingMyRoute(final String vpnName) {
         List<VpnInstanceOpDataEntry> vpnsToExportRoute = new ArrayList<>();
-
+        final VpnInstanceOpDataEntry vpnInstanceOpDataEntry;
         String vpnRd = vpnUtil.getVpnRd(vpnName);
-        final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
-        if (vpnInstanceOpDataEntry == null) {
-            LOG.debug("getVpnsExportingMyRoute: Could not retrieve vpn instance op data for {}"
-                    + " to check for vpns exporting the routes", vpnName);
+        try {
+            VpnInstanceOpDataEntry opDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
+            if (opDataEntry == null) {
+                LOG.error("getVpnsExportingMyRoute: Null vpn instance op data for vpn {} rd {}"
+                        + " when check for vpns exporting the routes", vpnName, vpnRd);
+                return vpnsToExportRoute;
+            }
+            vpnInstanceOpDataEntry = opDataEntry;
+        } catch (Exception re) {
+            LOG.error("getVpnsExportingMyRoute: DSexception when retrieving vpn instance op data for vpn {} rd {}"
+                    + " to check for vpns exporting the routes", vpnName, vpnRd, re);
             return vpnsToExportRoute;
         }
-
         Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
             if (input.getVpnInstanceName() == null) {
                 LOG.error("getVpnsExportingMyRoute.excludeVpn: Received vpn instance with rd {}  without a name",
@@ -1187,9 +1202,9 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                 }
                                 String prefix = vrfEntry.getDestPrefix();
                                 String gwMac = vrfEntry.getGatewayMacAddress();
-                                vrfEntry.nonnullRoutePaths().forEach(routePath -> {
+                                vrfEntry.nonnullRoutePaths().values().forEach(routePath -> {
                                     String nh = routePath.getNexthopAddress();
-                                    int label = routePath.getLabel().intValue();
+                                    Uint32 label = routePath.getLabel();
                                     if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
                                         vrfEntry.getOrigin()))) {
                                         LOG.info(
@@ -1198,7 +1213,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                             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,
+                                                Uint32.ZERO /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
                                             confTx);
                                     } else {
                                         LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
@@ -1228,7 +1243,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 : vpnInterface.nonnullVpnInstanceNames()) {
+        for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames().values()) {
             String vpnName = vpnInterfaceVpnInstance.getVpnName();
             removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
         }
@@ -1270,7 +1285,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
                                 LOG.info("remove: - intfName {} onto vpnName {} running config-driven",
                                         interfaceName, vpnName);
-                                BigInteger dpId;
+                                Uint64 dpId;
                                 int ifIndex;
                                 String gwMacAddress;
                                 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
@@ -1279,7 +1294,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                 try {
                                     optVpnInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                                             LogicalDatastoreType.OPERATIONAL, interfaceId);
-                                } catch (ReadFailedException e) {
+                                } catch (InterruptedException | ExecutionException e) {
                                     LOG.error("remove: Failed to read data store for interface {} vpn {}",
                                             interfaceName, vpnName);
                                     return;
@@ -1292,7 +1307,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                         + " data store for interface {} on dpn {} for vpn {} Fetching"
                                                         + " from vpn interface op data store. ", interfaceName,
                                                 vpnInterface.getDpnId(), vpnName, e);
-                                        dpId = BigInteger.ZERO;
+                                        dpId = Uint64.ZERO;
                                     }
                                     ifIndex = interfaceState.getIfIndex();
                                     gwMacAddress = interfaceState.getPhysAddress().getValue();
@@ -1320,12 +1335,13 @@ 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);
     }
 
-    protected void processVpnInterfaceDown(BigInteger dpId,
+    protected void processVpnInterfaceDown(Uint64 dpId,
                                            String interfaceName,
                                            int lportTag,
                                            String gwMac,
@@ -1344,7 +1360,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil.getVpnInterfaceOpDataEntryIdentifier(
                                                     interfaceName, vpnName);
         if (!isInterfaceStateDown) {
-            final long vpnId = vpnUtil.getVpnId(vpnName);
+            final Uint32 vpnId = vpnUtil.getVpnId(vpnName);
             vpnUtil.scheduleVpnInterfaceForRemoval(interfaceName, dpId, vpnName,  null);
             final boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
             removeAdjacenciesFromVpn(dpId, lportTag, interfaceName, vpnName,
@@ -1365,8 +1381,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         }
     }
 
-    private void removeAdjacenciesFromVpn(final BigInteger dpnId, final int lportTag, final String interfaceName,
-                                          final String vpnName, final long vpnId, String gwMac,
+    private void removeAdjacenciesFromVpn(final Uint64 dpnId, final int lportTag, final String interfaceName,
+                                          final String vpnName, final Uint32 vpnId, String gwMac,
                                           TypedWriteTransaction<Configuration> writeConfigTxn,
                                           TypedWriteTransaction<Operational> writeOperTxn,
                                           TypedReadWriteTransaction<Configuration> writeInvTxn)
@@ -1375,24 +1391,30 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         try {
             InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil
                     .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
-            InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
-            Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                    LogicalDatastoreType.OPERATIONAL, path);
-            boolean isNonPrimaryAdjIp = Boolean.FALSE;
+            Optional<VpnInterfaceOpDataEntry> vpnInterfaceOpDataEnteryOptional =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                            LogicalDatastoreType.OPERATIONAL, identifier);
+            boolean isNonPrimaryAdjIp = false;
             String primaryRd = vpnUtil.getVpnRd(vpnName);
             LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
                     interfaceName, dpnId, vpnName, primaryRd);
-            if (adjacencies.isPresent() && adjacencies.get().getAdjacency() != null
-                    && !adjacencies.get().getAdjacency().isEmpty()) {
-                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
+            if (!vpnInterfaceOpDataEnteryOptional.isPresent()) {
+                LOG.error("removeAdjacenciesFromVpn: VpnInterfaceOpDataEntry-Oper DS is absent for Interface {} "
+                        + "on vpn {} dpn {}", interfaceName, vpnName, dpnId);
+                return;
+            }
+            AdjacenciesOp adjacencies = vpnInterfaceOpDataEnteryOptional.get().augmentation(AdjacenciesOp.class);
+
+            if (adjacencies != null && !adjacencies.getAdjacency().isEmpty()) {
+                Map<AdjacencyKey, Adjacency> nextHopsMap = adjacencies.getAdjacency();
                 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
-                        interfaceName, dpnId, vpnName, nextHops);
-                for (Adjacency nextHop : nextHops) {
+                        interfaceName, dpnId, vpnName, nextHopsMap);
+                for (Adjacency nextHop : nextHopsMap.values()) {
                     if (nextHop.isPhysNetworkFunc()) {
                         LOG.info("removeAdjacenciesFromVpn: Removing PNF FIB entry rd {} prefix {}",
                                 nextHop.getSubnetId().getValue(), nextHop.getIpAddress());
                         fibManager.removeFibEntry(nextHop.getSubnetId().getValue(), nextHop.getIpAddress(),
-                                null/*writeCfgTxn*/);
+                                null, null/*writeCfgTxn*/);
                     } else {
                         String rd = nextHop.getVrfId();
                         List<String> nhList;
@@ -1404,7 +1426,9 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
                                     : emptyList();
                             removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
+                                    vpnInterfaceOpDataEnteryOptional.get().getGatewayIpAddress(),
                                     interfaceName, writeInvTxn);
+                            isNonPrimaryAdjIp = Boolean.FALSE;
                         }
                         if (!nhList.isEmpty()) {
                             if (Objects.equals(primaryRd, vpnName)) {
@@ -1414,14 +1438,14 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                         interfaceName, dpnId, writeConfigTxn, writeOperTxn));
                             } else {
                                 removeAdjacencyFromBgpvpn(nextHop, nhList, vpnName, primaryRd, dpnId, rd,
-                                        interfaceName, writeConfigTxn, writeOperTxn);
+                                        interfaceName, isNonPrimaryAdjIp, writeConfigTxn, writeOperTxn);
                             }
                         } else {
                             LOG.error("removeAdjacenciesFromVpn: nextHop empty for ip {} rd {} adjacencyType {}"
                                             + " interface {}", nextHop.getIpAddress(), rd,
                                     nextHop.getAdjacencyType().toString(), interfaceName);
                             bgpManager.withdrawPrefixIfPresent(rd, nextHop.getIpAddress());
-                            fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), writeConfigTxn);
+                            fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), null, writeConfigTxn);
                         }
                     }
                     String ip = nextHop.getIpAddress().split("/")[0];
@@ -1458,14 +1482,14 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         + " Removing it.", interfaceName, vpnName, dpnId);
                 writeOperTxn.delete(identifier);
             }
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("removeAdjacenciesFromVpn: Failed to read data store for interface {} dpn {} vpn {}",
                     interfaceName, dpnId, vpnName);
         }
     }
 
     private Consumer<String> removeAdjacencyFromInternalVpn(Adjacency nextHop, String vpnName,
-                                                            String interfaceName, BigInteger dpnId,
+                                                            String interfaceName, Uint64 dpnId,
                                                             TypedWriteTransaction<Configuration> writeConfigTxn,
                                                             TypedWriteTransaction<Operational> writeOperTx) {
         return (nh) -> {
@@ -1474,7 +1498,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
@@ -1484,6 +1511,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 {}",
@@ -1492,15 +1521,19 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     private void removeAdjacencyFromBgpvpn(Adjacency nextHop, List<String> nhList, String vpnName, String primaryRd,
-                                           BigInteger dpnId, String rd, String interfaceName,
+                                           Uint64 dpnId, String rd, String interfaceName, boolean isNonPrimaryAdjIp,
                                            TypedWriteTransaction<Configuration> writeConfigTxn,
                                            TypedWriteTransaction<Operational> writeOperTx) {
         List<VpnInstanceOpDataEntry> vpnsToImportRoute =
                 vpnUtil.getVpnsImportingMyRoute(vpnName);
         nhList.forEach((nh) -> {
             //IRT: remove routes from other vpns importing it
-            vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
-                    nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
+            if (isNonPrimaryAdjIp) {
+                removeLearntPrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
+            } else {
+                vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
+                        nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
+            }
             for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
                 String vpnRd = vpn.getVrfId();
                 if (vpnRd != null) {
@@ -1515,8 +1548,28 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         });
     }
 
-    private void removeGwMacAndArpResponderFlows(Adjacency nextHop, long vpnId, BigInteger dpnId,
-                                                 int lportTag, String gwMac, String interfaceName,
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void removeLearntPrefixFromBGP(String rd, String prefix, String nextHop,
+                                           TypedWriteTransaction<Configuration> writeConfigTxn) {
+        try {
+            if (!fibManager.checkFibEntryExist(dataBroker, rd, prefix, nextHop)) {
+                LOG.info("removeLearntPrefixFromBGP: IP {} with nexthop {} rd {} is already removed.Ignoring this"
+                        + " operation", prefix, nextHop, rd);
+                return;
+            }
+            LOG.info("removeLearntPrefixFromBGP: VPN WITHDRAW: Removing Fib Entry rd {} prefix {} nexthop {}",
+                    rd, prefix, nextHop);
+            fibManager.removeOrUpdateFibEntry(rd, prefix, nextHop, writeConfigTxn);
+            bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
+            LOG.info("removeLearntPrefixFromBGP: VPN WITHDRAW: Removed Fib Entry rd {} prefix {} nexthop {}",
+                    rd, prefix, nextHop);
+        } catch (Exception e) {
+            LOG.error("removeLearntPrefixFromBGP: Delete prefix {} rd {} nextHop {} failed", prefix, rd, nextHop, e);
+        }
+    }
+
+    private void removeGwMacAndArpResponderFlows(Adjacency nextHop, Uint32 vpnId, Uint64 dpnId,
+                                                 int lportTag, String gwMac, String gwIp, String interfaceName,
                                                  TypedReadWriteTransaction<Configuration> writeInvTxn)
             throws ExecutionException, InterruptedException {
         final Uuid subnetId = nextHop.getSubnetId();
@@ -1526,11 +1579,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             // to remove the flows for the same here from the L3_GW_MAC_TABLE.
             vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
         }
-        arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, nextHop.getSubnetGatewayIp(),
+        arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, gwIp,
                 subnetId);
     }
 
-    private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, BigInteger dpnId,
+    private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, Uint64 dpnId,
                                                   String interfaceName) {
         // This is either an extra-route (or) a learned IP via subnet-route
         List<String> nhList = null;
@@ -1556,17 +1609,21 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     gwPort.getMacAddress(), ipAddress, ifName, vpnName);
             return Optional.of(gwPort.getMacAddress());
         }
-        return Optional.absent();
+        return Optional.empty();
     }
 
     @Override
-    protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
+    public void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
         final VpnInterface update) {
         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);
+        final Uint64 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
         //handles switching between <internal VPN - external VPN>
         jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterfaceName, () -> {
@@ -1575,8 +1632,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 LOG.info("update: handled Instance update for VPNInterface {} on dpn {} from oldVpn(s) {} "
                                 + "to newVpn(s) {}",
                         original.getName(), dpnId,
-                        VpnHelper.getVpnInterfaceVpnInstanceNamesString(original.getVpnInstanceNames()),
-                        VpnHelper.getVpnInterfaceVpnInstanceNamesString(update.getVpnInstanceNames()));
+                        VpnHelper.getVpnInterfaceVpnInstanceNamesString(
+                                new ArrayList<VpnInstanceNames>(original.getVpnInstanceNames().values())),
+                        VpnHelper.getVpnInterfaceVpnInstanceNamesString(
+                                new ArrayList<VpnInstanceNames>(update.getVpnInstanceNames().values())));
                 return emptyList();
             }
             updateVpnInstanceAdjChange(original, update, vpnInterfaceName, futures);
@@ -1642,7 +1701,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             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) {
@@ -1659,7 +1718,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) {
@@ -1693,11 +1752,11 @@ 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)
-                ? origAdjs.getAdjacency() : new ArrayList<>();
+        final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency() != null
+                ? new ArrayList<Adjacency>(origAdjs.getAdjacency().values()) : new ArrayList<>();
         final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
-        final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
-                ? updateAdjs.getAdjacency() : new ArrayList<>();
+        final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency() != null
+                ? new ArrayList<Adjacency>(updateAdjs.getAdjacency().values()) : new ArrayList<>();
 
         boolean isOldVpnRemoveCallExecuted = false;
         for (String oldVpnName : oldVpnList) {
@@ -1714,7 +1773,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             try {
                 Thread.sleep(2000);
             } catch (InterruptedException e) {
-                //Ignore
+                LOG.error("updateVpnInstanceChange: InterruptedException caught for interface {}", interfaceName, e);
             }
         }
         for (String newVpnName : newVpnList) {
@@ -1745,22 +1804,28 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
                     updateVpnInstanceAdjChange(original, update, interfaceName, futures);
                 }
+            } else {
+                LOG.info("updateVpnInstanceChange: failed to Add for update on VPNInterface {} from oldVpn(s) {} to "
+                                + "newVpn {} as the new vpn does not exist in oper DS or it is in PENDING_DELETE state",
+                        interfaceName, oldVpnListCopy, newVpnName);
             }
         }
     }
 
+    // TODO Clean up the exception handling
+    @SuppressWarnings("checkstyle:IllegalCatch")
     private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
                                                                     String vpnInterfaceName,
                                                                     List<ListenableFuture<Void>> futures) {
         final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
         final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
-                != null ? origAdjs.getAdjacency() : new ArrayList<>();
+                != null ? new ArrayList<Adjacency>(origAdjs.getAdjacency().values()) : new ArrayList<>();
         final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
         final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
-                != null ? updateAdjs.getAdjacency() : new ArrayList<>();
+                != null ? new ArrayList<Adjacency>(updateAdjs.getAdjacency().values()) : new ArrayList<>();
 
-        final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
-        for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames()) {
+        final Uint64 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
+        for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames().values()) {
             String newVpnName = vpnInterfaceVpnInstance.getVpnName();
             List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
             List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
@@ -1788,8 +1853,13 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     } else {
                                         // add new adjacency
                                         if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
-                                            addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
+                                            try {
+                                                addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
                                                     dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
+                                            } catch (RuntimeException e) {
+                                                LOG.error("Failed to add adjacency {} to vpn interface {} with"
+                                                        + " dpnId {}", adj, vpnInterfaceName, dpnId, e);
+                                            }
                                         }
                                         LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
                                             + " added to vpn interface {} on vpn {} dpnId {}",
@@ -1808,7 +1878,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                             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);
+                                            fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), null, confTx);
                                             if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
                                                 bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
                                             }
@@ -1838,33 +1908,37 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         return futures;
     }
 
-    private void updateLabelMapper(Long label, List<String> nextHopIpList) {
+    private void updateLabelMapper(Uint32 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);
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("updateLabelMapper: Failed to read data store for label {} nexthopList {}", label,
                     nextHopIpList);
         } catch (TransactionCommitFailedException e) {
             LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
                     nextHopIpList);
+        } finally {
+            lock.unlock();
         }
     }
 
-    public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
+    public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, Uint32 label,
         SubnetRoute route, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
 
         RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
@@ -1876,7 +1950,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
         VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).setVrfEntry(vrfEntryList).build();
         if (writeConfigTxn != null) {
-            writeConfigTxn.merge(vrfTableId, vrfTableNew, CREATE_MISSING_PARENTS);
+            writeConfigTxn.mergeParentStructureMerge(vrfTableId, vrfTableNew);
         } else {
             vpnUtil.syncUpdate(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
         }
@@ -1885,7 +1959,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, String primaryRd,
-                                           Adjacency adj, BigInteger dpnId,
+                                           Adjacency adj, Uint64 dpnId,
                                            TypedWriteTransaction<Operational> writeOperTxn,
                                            TypedWriteTransaction<Configuration> writeConfigTxn,
                                            TypedReadWriteTransaction<Configuration> writeInvTxn,
@@ -1906,13 +1980,13 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         LogicalDatastoreType.OPERATIONAL, adjPath);
                 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(vpnInstanceOpData.getL3vni());
                 VrfEntry.EncapType encapType = VpnUtil.getEncapType(isL3VpnOverVxLan);
-                long l3vni = vpnInstanceOpData.getL3vni() == null ? 0L :  vpnInstanceOpData.getL3vni();
+                Uint32 l3vni = vpnInstanceOpData.getL3vni() == null ? Uint32.ZERO : vpnInstanceOpData.getL3vni();
                 VpnPopulator populator = L3vpnRegistry.getRegisteredPopulator(encapType);
                 List<Adjacency> adjacencies = new ArrayList<>();
                 if (optAdjacencies.isPresent() && optAdjacencies.get().getAdjacency() != null) {
-                    adjacencies.addAll(optAdjacencies.get().getAdjacency());
+                    adjacencies.addAll(optAdjacencies.get().getAdjacency().values());
                 }
-                long vpnId = vpnUtil.getVpnId(vpnName);
+                Uint32 vpnId = vpnUtil.getVpnId(vpnName);
                 L3vpnInput input = new L3vpnInput().setNextHop(adj).setVpnName(vpnName)
                         .setInterfaceName(currVpnIntf.getName()).setPrimaryRd(primaryRd).setRd(primaryRd);
                 Adjacency operationalAdjacency = null;
@@ -1934,7 +2008,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             : 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()) {
@@ -1961,7 +2038,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     vpnUtil.getVpnsImportingMyRoute(vpnName);
                             vpnsToImportRoute.forEach(vpn -> {
                                 if (vpn.getVrfId() != null) {
-                                    vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(), vpnId, prefix,
+                                    vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(),
+                                            vpnId, prefix,
                                             vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
                                             .ifPresent(
                                                 rds -> vpnManager.addExtraRoute(
@@ -1972,6 +2050,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                 }
                             });
                         }
+                    } finally {
+                        lock.unlock();
                     }
                 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
                     LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
@@ -1981,23 +2061,24 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             .getVpnInterfaceIdentifier(currVpnIntf.getName());
                     Optional<VpnInterface> vpnIntefaceConfig = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                             LogicalDatastoreType.CONFIGURATION, vpnIfaceConfigidentifier);
-                    Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
+                    Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(Uint64.ZERO, currVpnIntf.getName(), prefix,
                             Prefixes.PrefixCue.PhysNetFunc);
                     if (vpnIntefaceConfig.isPresent()) {
-                        pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
+                        pnfPrefix = VpnUtil.getPrefixToInterface(Uint64.ZERO, currVpnIntf.getName(), prefix,
                                 vpnIntefaceConfig.get().getNetworkId(), vpnIntefaceConfig.get().getNetworkType(),
-                                vpnIntefaceConfig.get().getSegmentationId(), Prefixes.PrefixCue.PhysNetFunc);
+                                vpnIntefaceConfig.get().getSegmentationId().toJava(), Prefixes.PrefixCue.PhysNetFunc);
                     }
 
                     String parentVpnRd = getParentVpnRdForExternalSubnet(adj);
 
-                    writeOperTxn.merge(
+                    writeOperTxn.mergeParentStructureMerge(
                             VpnUtil.getPrefixToInterfaceIdentifier(vpnUtil.getVpnId(adj.getSubnetId().getValue()),
-                                    prefix), pnfPrefix, true);
+                                    prefix), pnfPrefix);
 
                     fibManager.addOrUpdateFibEntry(adj.getSubnetId().getValue(), adj.getMacAddress(),
-                            adj.getIpAddress(), emptyList(), null /* EncapType */, 0 /* label */,
-                            0 /*l3vni*/, null /* gw-mac */, parentVpnRd, RouteOrigin.LOCAL, writeConfigTxn);
+                            adj.getIpAddress(), emptyList(), null /* EncapType */, Uint32.ZERO /* label */,
+                            Uint32.ZERO /*l3vni*/, null /* gw-mac */, parentVpnRd,
+                            RouteOrigin.LOCAL, writeConfigTxn);
 
                     input.setRd(adj.getVrfId());
                 }
@@ -2008,12 +2089,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(adjacencies);
                 VpnInterfaceOpDataEntry newVpnIntf =
                         VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
-                                aug, dpnId, currVpnIntf.getLportTag(),
-                                currVpnIntf.getGatewayMacAddress());
-
-                writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
+                                aug, dpnId, currVpnIntf.getLportTag().toJava(),
+                                currVpnIntf.getGatewayMacAddress(), currVpnIntf.getGatewayIpAddress());
+                writeOperTxn.mergeParentStructureMerge(identifier, newVpnIntf);
             }
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("addNewAdjToVpnInterface: Failed to read data store for interface {} dpn {} vpn {} rd {} ip "
                     + "{}", interfaceName, dpnId, configVpnName, primaryRd, adj.getIpAddress());
         }
@@ -2026,7 +2106,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, Adjacency adj,
-                                            BigInteger dpnId, TypedWriteTransaction<Operational> writeOperTxn,
+                                            Uint64 dpnId, TypedWriteTransaction<Operational> writeOperTxn,
                                             TypedWriteTransaction<Configuration> writeConfigTxn) {
         String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
         String vpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
@@ -2039,11 +2119,11 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                         LogicalDatastoreType.OPERATIONAL, path);
                 if (optAdjacencies.isPresent()) {
-                    List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
+                    Map<AdjacencyKey, Adjacency> keyAdjacencyMap = optAdjacencies.get().getAdjacency();
 
-                    if (adjacencies != null && !adjacencies.isEmpty()) {
-                        LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", adjacencies);
-                        for (Adjacency adjacency : adjacencies) {
+                    if (keyAdjacencyMap != null && !keyAdjacencyMap.isEmpty()) {
+                        LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", keyAdjacencyMap);
+                        for (Adjacency adjacency : keyAdjacencyMap.values()) {
                             if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
                                 String rd = adjacency.getVrfId();
                                 if (adj.getNextHopIpList() != null) {
@@ -2056,7 +2136,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     LOG.info("delAdjFromVpnInterface: deleting PNF adjacency prefix {} subnet {}",
                                             adj.getIpAddress(), adj.getSubnetId());
                                     fibManager.removeFibEntry(adj.getSubnetId().getValue(), adj.getIpAddress(),
-                                            writeConfigTxn);
+                                            null, writeConfigTxn);
                                 }
                                 break;
                             }
@@ -2070,7 +2150,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             + "unavailable dpnId {} adjIP {} rd {}", dpnId, adj.getIpAddress(), adj.getVrfId());
                 }
             }
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("delAdjFromVpnInterface: Failed to read data store for ip {} interface {} dpn {} vpn {}",
                     adj.getIpAddress(), interfaceName, dpnId, vpnName);
         }
@@ -2079,18 +2159,22 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     private void deleteExtraRouteFromCurrentAndImportingVpns(String vpnName, String destination, String nextHop,
                                     String rd, String intfName, TypedWriteTransaction<Configuration> writeConfigTxn,
                                     TypedWriteTransaction<Operational> writeOperTx) {
+        LOG.info("removing extra-route {} for nexthop {} in VPN {} intfName {} rd {}",
+                destination, nextHop, vpnName, intfName, rd);
         vpnManager.delExtraRoute(vpnName, destination, nextHop, rd, vpnName, intfName, writeConfigTxn, writeOperTx);
         List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
         for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
             String vpnRd = vpn.getVrfId();
             if (vpnRd != null) {
+                LOG.info("deleting extra-route {} for nexthop {} in VPN {} intfName {} vpnRd {}",
+                        destination, nextHop, vpnName, intfName, vpnRd);
                 vpnManager.delExtraRoute(vpnName, destination, nextHop, vpnRd, vpnName, intfName, writeConfigTxn,
                         writeOperTx);
             }
         }
     }
 
-    InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
+    InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, Uint64 dpnId) {
         return InstanceIdentifier.builder(NeutronRouterDpns.class)
             .child(RouterDpnList.class, new RouterDpnListKey(routerName))
             .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
@@ -2118,9 +2202,15 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 String macAddress = adj.getMacAddress();
                 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
 
-                long label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
+                Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
                         VpnUtil.getNextHopLabelKey(primaryRd, prefix));
-
+                if (label.longValue() == VpnConstants.INVALID_LABEL) {
+                    LOG.error(
+                            "createFibEntryForRouterInterface: Unable to retrieve label for vpn pool {}, "
+                                    + "vpninterface {}, vpn {}, rd {}",
+                            VpnConstants.VPN_IDPOOL_NAME, interfaceName, vpnName, primaryRd);
+                    return;
+                }
                 RouterInterface routerInt = new RouterInterfaceBuilder().setUuid(vpnName)
                         .setIpAddress(primaryInterfaceIp).setMacAddress(macAddress).build();
                 fibManager.addFibEntryForRouterInterface(primaryRd, prefix,
@@ -2141,15 +2231,14 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
         String rd = vpnUtil.getVpnRd(vpnName);
         if (adjs != null) {
-            List<Adjacency> adjsList = adjs.nonnullAdjacency();
-            for (Adjacency adj : adjsList) {
+            Map<AdjacencyKey, Adjacency> keyAdjacencyMap = adjs.nonnullAdjacency();
+            for (Adjacency adj : keyAdjacencyMap.values()) {
                 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
                     String primaryInterfaceIp = adj.getIpAddress();
                     String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
-                    fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
+                    fibManager.removeFibEntry(rd, prefix, null, writeConfigTxn);
                     LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
                             + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
-                    return;
                 }
             }
         } else {
@@ -2191,7 +2280,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) {
@@ -2209,24 +2301,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,7 +2390,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         if (vpnInstanceOpData == null) {
             return;
         }
-        List<VpnToDpnList> vpnToDpnLists = vpnInstanceOpData.getVpnToDpnList();
+        List<VpnToDpnList> vpnToDpnLists = new ArrayList<VpnToDpnList>(vpnInstanceOpData.getVpnToDpnList().values());
         if (vpnToDpnLists == null || vpnToDpnLists.isEmpty()) {
             return;
         }
@@ -2301,7 +2399,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             if (vpnToDpnList.getVpnInterfaces() == null) {
                 return;
             }
-            vpnToDpnList.getVpnInterfaces().forEach(vpnInterface -> {
+            vpnToDpnList.getVpnInterfaces().values().forEach(vpnInterface -> {
                 try {
                     InstanceIdentifier<VpnInterfaceOpDataEntry> existingVpnInterfaceId =
                             VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getInterfaceName(), vpnName);
@@ -2316,8 +2414,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
                         return;
                     }
-                    List<Adjacency> operationVpnAdjacencies = vpnInterfaceOptional.get()
-                            .augmentation(AdjacenciesOp.class).nonnullAdjacency();
+                    List<Adjacency> operationVpnAdjacencies = new ArrayList<Adjacency>(vpnInterfaceOptional.get()
+                            .augmentation(AdjacenciesOp.class).nonnullAdjacency().values());
                     // 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.
@@ -2344,7 +2442,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                                 ListenableFuture<Void> configTxFuture =
                                                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
                                                         confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
-                                                            primaryRd, adjacency, vpnInterfaceOptional.get().getDpnId(),
+                                                            primaryRd, adjacency,
+                                                            vpnInterfaceOptional.get().getDpnId(),
                                                                 operTx, confTx, confTx, prefixListForRefreshFib));
                                                 Futures.addCallback(configTxFuture,
                                                     new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
@@ -2357,7 +2456,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                                     }
                                 });
                         });
-                } catch (ReadFailedException e) {
+                } catch (InterruptedException | ExecutionException e) {
                     LOG.error("updateVpnInterfacesForUnProcessAdjancencies: Failed to read data store for vpn {} rd {}",
                             vpnName, primaryRd);
                 }
@@ -2416,7 +2515,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
         @Override
         public void onFailure(Throwable throwable) {
-            LOG.debug("write Tx config operation failed {}", throwable);
+            LOG.debug("write Tx config operation failed", throwable);
         }
     }
 }