Unsupported operation exception handling
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnFootprintService.java
index 453a4b83b719fea8ca87d5ff56fb96a6470ad3b2..4ed201d85e405f5d7ec26cf4d3aa217e76e48784 100644 (file)
@@ -13,14 +13,16 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
-import java.math.BigInteger;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
@@ -28,6 +30,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnFootprintService;
 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
@@ -57,6 +60,8 @@ 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.vpn.to.dpn.list.VpnInterfacesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,34 +76,37 @@ public class VpnFootprintService implements IVpnFootprintService {
     private final VpnOpDataSyncer vpnOpDataSyncer;
     private final NotificationPublishService notificationPublishService;
     private final IInterfaceManager interfaceManager;
+    private final VpnUtil vpnUtil;
 
     @Inject
     public VpnFootprintService(final DataBroker dataBroker, final IFibManager fibManager,
             final NotificationPublishService notificationPublishService, final VpnOpDataSyncer vpnOpDataSyncer,
-            final IInterfaceManager interfaceManager) {
+            final IInterfaceManager interfaceManager, VpnUtil vpnUtil) {
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.fibManager = fibManager;
         this.vpnOpDataSyncer = vpnOpDataSyncer;
         this.notificationPublishService = notificationPublishService;
         this.interfaceManager = interfaceManager;
+        this.vpnUtil = vpnUtil;
     }
 
     @Override
-    public void updateVpnToDpnMapping(BigInteger dpId, String vpnName, String primaryRd, String interfaceName,
-            ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, boolean add) {
-        long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
-        if (!dpId.equals(BigInteger.ZERO)) {
+    public void updateVpnToDpnMapping(Uint64 dpId, String vpnName, String primaryRd, @Nullable String interfaceName,
+                                      @Nullable ImmutablePair<IpAddresses.IpAddressSource,
+                                              String> ipAddressSourceValuePair, boolean add) {
+        Uint32 vpnId = vpnUtil.getVpnId(vpnName);
+        if (!dpId.equals(Uint64.ZERO)) {
             if (add) {
                 // Considering the possibility of VpnInstanceOpData not being ready yet cause
                 // the VPN is
                 // still in its creation process
-                if (vpnId == VpnConstants.INVALID_ID) {
+                if (VpnConstants.INVALID_ID.equals(vpnId)) {
                     LOG.error("updateVpnToDpnMapping: Operational data  for vpn not ready. Waiting to update vpn"
                             + " footprint for vpn {} on dpn {} interface {}", vpnName, dpId, interfaceName);
                     vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpnName,
                             VpnConstants.PER_VPN_INSTANCE_OPDATA_MAX_WAIT_TIME_IN_MILLISECONDS);
-                    vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
+                    vpnId = vpnUtil.getVpnId(vpnName);
                 }
                 if (interfaceName != null) {
                     createOrUpdateVpnToDpnListForInterfaceName(vpnId, primaryRd, dpId, interfaceName, vpnName);
@@ -117,28 +125,29 @@ public class VpnFootprintService implements IVpnFootprintService {
         }
     }
 
-    private void createOrUpdateVpnToDpnListForInterfaceName(long vpnId, String primaryRd, BigInteger dpnId,
+    private void createOrUpdateVpnToDpnListForInterfaceName(Uint32 vpnId, String primaryRd, Uint64 dpnId,
             String intfName, String vpnName) {
         AtomicBoolean newDpnOnVpn = new AtomicBoolean(false);
-
-        synchronized (vpnName.intern()) {
-            InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
-            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
-            VpnInterfaces vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
-
-            ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        /* Starts synchronized block. This ensures only one reader/writer get access to vpn-dpn-list
+         * The future.get ensures that the write to the datastore is complete before leaving the synchronized block.
+         */
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+        lock.lock();
+        try {
+            ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+                InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
+                VpnInterfaces vpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
+                Optional<VpnToDpnList> dpnInVpn = tx.read(LogicalDatastoreType.OPERATIONAL, id).checkedGet();
                 if (dpnInVpn.isPresent()) {
                     VpnToDpnList vpnToDpnList = dpnInVpn.get();
-                    List<VpnInterfaces> vpnInterfaces = vpnToDpnList.getVpnInterfaces();
-                    if (vpnInterfaces == null) {
-                        vpnInterfaces = new ArrayList<>();
-                    }
+                    List<VpnInterfaces> vpnInterfaces = new ArrayList<>(vpnToDpnList.nonnullVpnInterfaces());
                     vpnInterfaces.add(vpnInterface);
                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
 
                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(),
-                            WriteTransaction.CREATE_MISSING_PARENTS);
+                        WriteTransaction.CREATE_MISSING_PARENTS);
                     /*
                      * If earlier state was inactive, it is considered new DPN coming back to the
                      * same VPN
@@ -155,20 +164,19 @@ public class VpnFootprintService implements IVpnFootprintService {
                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setVpnInterfaces(vpnInterfaces);
 
                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(),
-                            WriteTransaction.CREATE_MISSING_PARENTS);
+                        WriteTransaction.CREATE_MISSING_PARENTS);
                     newDpnOnVpn.set(true);
                     LOG.debug("createOrUpdateVpnToDpnList: Creating vpn footprint for vpn {} vpnId {} interface {}"
                             + " on dpn {}", vpnName, vpnId, intfName, dpnId);
                 }
             });
-
-            try {
-                future.get();
-            } catch (InterruptedException | ExecutionException e) {
-                LOG.error("createOrUpdateVpnToDpnList: Error adding to dpnToVpnList for vpn {} vpnId {} interface {}"
-                        + " dpn {}", vpnName, vpnId, intfName, dpnId, e);
-                throw new RuntimeException(e.getMessage(), e);
-            }
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("createOrUpdateVpnToDpnList: Error adding to dpnToVpnList for vpn {} vpnId {} interface {}"
+                    + " dpn {}", vpnName, vpnId, intfName, dpnId, e);
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            lock.unlock();
         }
         LOG.info("createOrUpdateVpnToDpnList: Created/Updated vpn footprint for vpn {} vpnId {} interfacName{}"
                 + " on dpn {}", vpnName, vpnId, intfName, dpnId);
@@ -176,8 +184,8 @@ public class VpnFootprintService implements IVpnFootprintService {
          * Informing the FIB only after writeTxn is submitted successfully.
          */
         if (newDpnOnVpn.get()) {
-            if (VpnUtil.isVlan(dataBroker ,intfName)) {
-                if (!VpnUtil.shouldPopulateFibForVlan(dataBroker, vpnName, null, dpnId, interfaceManager)) {
+            if (vpnUtil.isVlan(intfName)) {
+                if (!vpnUtil.shouldPopulateFibForVlan(vpnName, null, dpnId)) {
                     return;
                 }
             }
@@ -188,25 +196,26 @@ public class VpnFootprintService implements IVpnFootprintService {
         }
     }
 
-    private void createOrUpdateVpnToDpnListForIPAddress(long vpnId, String primaryRd, BigInteger dpnId,
+    private void createOrUpdateVpnToDpnListForIPAddress(Uint32 vpnId, String primaryRd, Uint64 dpnId,
             ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, String vpnName) {
         AtomicBoolean newDpnOnVpn = new AtomicBoolean(false);
-
-        synchronized (vpnName.intern()) {
-            InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
-            Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
-            IpAddressesBuilder ipAddressesBldr = new IpAddressesBuilder()
-                    .setIpAddressSource(ipAddressSourceValuePair.getKey());
-            ipAddressesBldr.setKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()));
-            ipAddressesBldr.setIpAddress(ipAddressSourceValuePair.getValue());
-
-            ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        /* Starts synchronized block. This ensures only one reader/writer get access to vpn-dpn-list
+         * The future.get ensures that the write to the datastore is complete before leaving the synchronized block.
+         */
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+        lock.lock();
+        try {
+            ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+                InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
+                IpAddressesBuilder ipAddressesBldr = new IpAddressesBuilder()
+                        .setIpAddressSource(ipAddressSourceValuePair.getKey());
+                ipAddressesBldr.withKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()));
+                ipAddressesBldr.setIpAddress(ipAddressSourceValuePair.getValue());
+                Optional<VpnToDpnList> dpnInVpn = tx.read(LogicalDatastoreType.OPERATIONAL, id).checkedGet();
                 if (dpnInVpn.isPresent()) {
                     VpnToDpnList vpnToDpnList = dpnInVpn.get();
-                    List<IpAddresses> ipAddresses = vpnToDpnList.getIpAddresses();
-                    if (ipAddresses == null) {
-                        ipAddresses = new ArrayList<>();
-                    }
+                    List<IpAddresses> ipAddresses = new ArrayList<>(vpnToDpnList.nonnullIpAddresses());
                     ipAddresses.add(ipAddressesBldr.build());
                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder(vpnToDpnList);
                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setIpAddresses(ipAddresses);
@@ -224,18 +233,18 @@ public class VpnFootprintService implements IVpnFootprintService {
                     ipAddresses.add(ipAddressesBldr.build());
                     VpnToDpnListBuilder vpnToDpnListBuilder = new VpnToDpnListBuilder().setDpnId(dpnId);
                     vpnToDpnListBuilder.setDpnState(VpnToDpnList.DpnState.Active).setIpAddresses(ipAddresses);
-
                     tx.put(LogicalDatastoreType.OPERATIONAL, id, vpnToDpnListBuilder.build(), true);
                     newDpnOnVpn.set(true);
                 }
+
             });
-            try {
-                future.get();
-            } catch (InterruptedException | ExecutionException e) {
-                LOG.error("Error adding to dpnToVpnList for vpn {} ipAddresses {} dpn {}", vpnName,
-                        ipAddressSourceValuePair.getValue(), dpnId, e);
-                throw new RuntimeException(e.getMessage(), e);
-            }
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("createOrUpdateVpnToDpnListForIPAddress: Error adding to dpnToVpnList for vpn {}"
+                    + " ipAddresses {} dpn {}", vpnName, ipAddressSourceValuePair.getValue(), dpnId, e);
+            throw new RuntimeException(e.getMessage(), e); //TODO: Avoid this
+        } finally {
+            lock.unlock();
         }
         /*
          * Informing the Fib only after writeTxn is submitted successfuly.
@@ -247,28 +256,35 @@ public class VpnFootprintService implements IVpnFootprintService {
         }
     }
 
-    private void removeOrUpdateVpnToDpnListForInterfaceName(long vpnId, String rd, BigInteger dpnId, String intfName,
+    private void removeOrUpdateVpnToDpnListForInterfaceName(Uint32 vpnId, String rd, Uint64 dpnId, String intfName,
             String vpnName) {
         AtomicBoolean lastDpnOnVpn = new AtomicBoolean(false);
-        synchronized (vpnName.intern()) {
-            InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
-            VpnToDpnList dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).orNull();
-            if (dpnInVpn == null) {
-                LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={} rd={} id={}]"
-                        + " and dpnId={}", vpnName, rd, id, dpnId);
-                return;
-            }
-            List<VpnInterfaces> vpnInterfaces = dpnInVpn.getVpnInterfaces();
-            if (vpnInterfaces == null) {
-                LOG.error("Could not find vpnInterfaces for DpnInVpn map for VPN=[name={} rd={} id={}] and dpnId={}",
-                        vpnName, rd, id, dpnId);
-                return;
-            }
-
-            VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
-            if (vpnInterfaces.remove(currVpnInterface)) {
-                try {
-                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        /* Starts synchronized block. This ensures only one reader/writer get access to vpn-dpn-list
+         * The future.get ensures that the write to the datastore is complete before leaving the synchronized block.
+         */
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+        lock.lock();
+        try {
+            try {
+                ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+                    InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
+                    Optional<VpnToDpnList> dpnInVpnOpt = tx.read(LogicalDatastoreType.OPERATIONAL, id)
+                            .checkedGet();
+                    if (!dpnInVpnOpt.isPresent()) {
+                        LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={}"
+                                + " rd={} id={}] and dpnId={}", vpnName, rd, id, dpnId);
+                        return;
+                    }
+                    VpnToDpnList dpnInVpn = dpnInVpnOpt.get();
+                    List<VpnInterfaces> vpnInterfaces = new ArrayList<>(dpnInVpn.nonnullVpnInterfaces());
+                    if (vpnInterfaces == null) {
+                        LOG.error("Could not find vpnInterfaces for DpnInVpn map for VPN=[name={} rd={} id={}] and "
+                                + "dpnId={}", vpnName, rd, id, dpnId);
+                        return;
+                    }
+                    VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
+                    if (vpnInterfaces.remove(currVpnInterface)) {
                         if (vpnInterfaces.isEmpty()) {
                             List<IpAddresses> ipAddresses = dpnInVpn.getIpAddresses();
                             VpnToDpnListBuilder dpnInVpnBuilder =
@@ -277,8 +293,9 @@ public class VpnFootprintService implements IVpnFootprintService {
                                 dpnInVpnBuilder.setDpnState(VpnToDpnList.DpnState.Inactive);
                                 lastDpnOnVpn.set(true);
                             } else {
-                                LOG.error("removeOrUpdateVpnToDpnList: vpn interfaces are empty but ip addresses are "
-                                        + "present for the vpn {} in dpn {} interface {}", vpnName, dpnId, intfName);
+                                LOG.error("removeOrUpdateVpnToDpnList: vpn interfaces are empty but ip addresses"
+                                        + " are present for the vpn {} in dpn {} interface {}", vpnName, dpnId,
+                                        intfName);
                             }
                             LOG.debug("removeOrUpdateVpnToDpnList: Removing vpn footprint for vpn {} vpnId {} "
                                     + "interface {}, on dpn {}", vpnName, vpnName, intfName, dpnId);
@@ -291,74 +308,89 @@ public class VpnFootprintService implements IVpnFootprintService {
                             LOG.debug("removeOrUpdateVpnToDpnList: Updating vpn footprint for vpn {} vpnId {} "
                                     + "interface {}, on dpn {}", vpnName, vpnName, intfName, dpnId);
                         }
-                    }).get();
-                } catch (InterruptedException | ExecutionException e) {
-                    LOG.error("removeOrUpdateVpnToDpnList: Error removing from dpnToVpnList for vpn {} vpnId {}"
-                            + " interface {} dpn {}", vpnName, vpnId, intfName, dpnId, e);
-                    throw new RuntimeException(e.getMessage(), e);
-                }
+                    }
+                });
+                future.get();
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.error("removeOrUpdateVpnToDpnList: Error removing from dpnToVpnList for vpn {} vpnId {}"
+                        + " interface {} dpn {}", vpnName, vpnId, intfName, dpnId, e);
+                throw new RuntimeException(e.getMessage(), e);
             }
-        } // Ends synchronized block
-        LOG.info("removeOrUpdateVpnToDpnList: Updated/Removed vpn footprint for vpn {} vpnId {} interface {},"
-                + " on dpn {}", vpnName, vpnName, intfName, dpnId);
-
-        if (lastDpnOnVpn.get()) {
-            fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd,
-                    new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
-            LOG.info("removeOrUpdateVpnToDpnList: Sent cleanup event for dpn {} in VPN {} vpnId {} interface {}", dpnId,
-                    vpnName, vpnId, intfName);
+            // Ends synchronized block
+            LOG.info("removeOrUpdateVpnToDpnList: Updated/Removed vpn footprint for vpn {} vpnId {} interface {},"
+                    + " on dpn {}", vpnName, vpnName, intfName, dpnId);
+
+            if (lastDpnOnVpn.get()) {
+                fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd,
+                        new DpnEnterExitVpnWorker(dpnId, vpnName, rd, false /* exited */));
+                LOG.info("removeOrUpdateVpnToDpnList: Sent cleanup event for dpn {} in VPN {} vpnId {} interface {}",
+                        dpnId, vpnName, vpnId, intfName);
+            }
+        } finally {
+            lock.unlock();
         }
     }
 
-    private void removeOrUpdateVpnToDpnListForIpAddress(long vpnId, String rd, BigInteger dpnId,
+    private void removeOrUpdateVpnToDpnListForIpAddress(Uint32 vpnId, String rd, Uint64 dpnId,
             ImmutablePair<IpAddresses.IpAddressSource, String> ipAddressSourceValuePair, String vpnName) {
         AtomicBoolean lastDpnOnVpn = new AtomicBoolean(false);
-        synchronized (vpnName.intern()) {
-            InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
-            VpnToDpnList dpnInVpn = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).orNull();
-            if (dpnInVpn == null) {
-                LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={} rd={} id={}]"
-                        + " and dpnId={}", vpnName, rd, id, dpnId);
-                return;
-            }
-            List<IpAddresses> ipAddresses = dpnInVpn.getIpAddresses();
-            if (ipAddresses == null) {
-                LOG.info("Could not find ipAddresses for DpnInVpn map for VPN=[name={} rd={} id={}] and dpnId={}",
-                        vpnName, rd, id, dpnId);
-                return;
-            }
-
-            IpAddresses currIpAddress = new IpAddressesBuilder()
-                    .setKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()))
-                    .setIpAddressSource(ipAddressSourceValuePair.getKey()).build();
-            if (ipAddresses.remove(currIpAddress)) {
-                try {
-                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                        if (ipAddresses.isEmpty()) {
-                            List<VpnInterfaces> vpnInterfaces = dpnInVpn.getVpnInterfaces();
-                            VpnToDpnListBuilder dpnInVpnBuilder =
-                                    new VpnToDpnListBuilder(dpnInVpn).setIpAddresses(null);
-                            if (vpnInterfaces == null || vpnInterfaces.isEmpty()) {
-                                dpnInVpnBuilder.setDpnState(VpnToDpnList.DpnState.Inactive);
-                                lastDpnOnVpn.set(true);
-                            } else {
-                                LOG.warn("ip addresses are empty but vpn interfaces are present for the vpn {} in "
-                                        + "dpn {}", vpnName, dpnId);
-                            }
-                            tx.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
+        /* Starts synchronized block. This ensures only one reader/writer get access to vpn-dpn-list
+         * The future.get ensures that the write to the datastore is complete before leaving the synchronized block.
+         */
+        // FIXME: separate this out somehow?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+        lock.lock();
+        try {
+            ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
+                InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
+
+                Optional<VpnToDpnList> dpnInVpnOpt = tx.read(LogicalDatastoreType.OPERATIONAL, id)
+                        .checkedGet();
+                if (!dpnInVpnOpt.isPresent()) {
+                    LOG.error("removeOrUpdateVpnToDpnList: Could not find DpnToVpn map for VPN=[name={} "
+                            + "rd={} id={}] and dpnId={}", vpnName, rd, id, dpnId);
+                    return;
+                }
+                VpnToDpnList dpnInVpn = dpnInVpnOpt.get();
+                List<IpAddresses> ipAddresses = new ArrayList<>(dpnInVpn.nonnullIpAddresses());
+                if (ipAddresses == null) {
+                    LOG.info("Could not find ipAddresses for DpnInVpn map for VPN=[name={} rd={} id={}] "
+                            + "and dpnId={}", vpnName, rd, id, dpnId);
+                    return;
+                }
 
+                IpAddresses currIpAddress = new IpAddressesBuilder()
+                        .withKey(new IpAddressesKey(ipAddressSourceValuePair.getValue()))
+                        .setIpAddressSource(ipAddressSourceValuePair.getKey()).build();
+                if (ipAddresses.remove(currIpAddress)) {
+                    if (ipAddresses.isEmpty()) {
+                        List<VpnInterfaces> vpnInterfaces = dpnInVpn.getVpnInterfaces();
+                        VpnToDpnListBuilder dpnInVpnBuilder =
+                                new VpnToDpnListBuilder(dpnInVpn).setIpAddresses(null);
+                        if (vpnInterfaces == null || vpnInterfaces.isEmpty()) {
+                            dpnInVpnBuilder.setDpnState(VpnToDpnList.DpnState.Inactive);
+                            lastDpnOnVpn.set(true);
                         } else {
-                            tx.delete(LogicalDatastoreType.OPERATIONAL, id.child(IpAddresses.class,
-                                    new IpAddressesKey(ipAddressSourceValuePair.getValue())));
+                            LOG.warn("ip addresses are empty but vpn interfaces are present for the vpn {} in "
+                                    + "dpn {}", vpnName, dpnId);
                         }
-                    }).get();
-                } catch (InterruptedException | ExecutionException e) {
-                    LOG.error("Error removing from dpnToVpnList for vpn {} Ipaddress {} dpn {}", vpnName,
-                            ipAddressSourceValuePair.getValue(), dpnId, e);
-                    throw new RuntimeException(e.getMessage(), e);
+                        tx.put(LogicalDatastoreType.OPERATIONAL, id, dpnInVpnBuilder.build(), true);
+
+                    } else {
+                        tx.delete(LogicalDatastoreType.OPERATIONAL, id.child(IpAddresses.class,
+                            new IpAddressesKey(ipAddressSourceValuePair.getValue())));
+                    }
                 }
-            }
-        } // Ends synchronized block
+
+            });
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error removing from dpnToVpnList for vpn {} Ipaddress {} dpn {}", vpnName,
+                ipAddressSourceValuePair.getValue(), dpnId, e);
+            throw new RuntimeException(e.getMessage(), e); //TODO: Avoid this
+        } finally {
+            lock.unlock();
+        }
 
         if (lastDpnOnVpn.get()) {
             LOG.debug("Sending cleanup event for dpn {} in VPN {}", dpnId, vpnName);
@@ -367,7 +399,9 @@ public class VpnFootprintService implements IVpnFootprintService {
         }
     }
 
-    private void publishAddNotification(final BigInteger dpnId, final String vpnName, final String rd) {
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+            justification = "https://github.com/spotbugs/spotbugs/issues/811")
+    private void publishAddNotification(final Uint64 dpnId, final String vpnName, final String rd) {
         LOG.debug("publishAddNotification: Sending notification for add dpn {} in vpn {} rd {} event ", dpnId, vpnName,
                 rd);
         AddEventData data = new AddEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
@@ -388,7 +422,9 @@ public class VpnFootprintService implements IVpnFootprintService {
         }, MoreExecutors.directExecutor());
     }
 
-    private void publishRemoveNotification(final BigInteger dpnId, final String vpnName, final String rd) {
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+               justification = "https://github.com/spotbugs/spotbugs/issues/811")
+    private void publishRemoveNotification(final Uint64 dpnId, final String vpnName, final String rd) {
         LOG.debug("publishRemoveNotification: Sending notification for remove dpn {} in vpn {} rd {} event ", dpnId,
                 vpnName, rd);
         RemoveEventData data = new RemoveEventDataBuilder().setVpnName(vpnName).setRd(rd).setDpnId(dpnId).build();
@@ -409,8 +445,8 @@ public class VpnFootprintService implements IVpnFootprintService {
         }, MoreExecutors.directExecutor());
     }
 
-    private void publishInterfaceAddedToVpnNotification(String interfaceName, BigInteger dpnId, String vpnName,
-            Long vpnId) {
+    private void publishInterfaceAddedToVpnNotification(String interfaceName, Uint64 dpnId, String vpnName,
+            Uint32 vpnId) {
         LOG.debug("publishInterfaceAddedToVpnNotification: Sending notification for addition of interface {} on dpn {}"
                 + " for vpn {}", interfaceName, dpnId, vpnName);
         AddInterfaceEventData data = new AddInterfaceEventDataBuilder().setInterfaceName(interfaceName).setVpnId(vpnId)
@@ -433,8 +469,8 @@ public class VpnFootprintService implements IVpnFootprintService {
         }, MoreExecutors.directExecutor());
     }
 
-    private void publishInterfaceRemovedFromVpnNotification(String interfaceName, BigInteger dpnId, String vpnName,
-            Long vpnId) {
+    private void publishInterfaceRemovedFromVpnNotification(String interfaceName, Uint64 dpnId, String vpnName,
+            Uint32 vpnId) {
         LOG.debug("publishInterfaceAddedToVpnNotification: Sending notification for removal of interface {}"
                 + " from dpn {} for vpn {}", interfaceName, dpnId, vpnName);
         RemoveInterfaceEventData data = new RemoveInterfaceEventDataBuilder().setInterfaceName(interfaceName)
@@ -465,12 +501,12 @@ public class VpnFootprintService implements IVpnFootprintService {
      */
     private class DpnEnterExitVpnWorker implements FutureCallback<List<Void>> {
         private final Logger log = LoggerFactory.getLogger(DpnEnterExitVpnWorker.class);
-        BigInteger dpnId;
+        Uint64 dpnId;
         String vpnName;
         String rd;
         boolean entered;
 
-        DpnEnterExitVpnWorker(BigInteger dpnId, String vpnName, String rd, boolean entered) {
+        DpnEnterExitVpnWorker(Uint64 dpnId, String vpnName, String rd, boolean entered) {
             this.entered = entered;
             this.dpnId = dpnId;
             this.vpnName = vpnName;