Migrate ListenableFutures.addErrorLogging() users
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInstanceListener.java
index 8494196faaf3f1e5a4dff5a86aecb328c496ec45..a77c0c9a8647464e4a14e9759c9babac36150fd3 100644 (file)
@@ -7,27 +7,33 @@
  */
 package org.opendaylight.netvirt.vpnmanager;
 
-import com.google.common.base.Optional;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
+
 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.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-import javax.annotation.PostConstruct;
+import java.util.concurrent.locks.ReentrantLock;
+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.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-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.TypedWriteTransaction;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
@@ -39,135 +45,165 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.genius.utils.SystemPropertyReader;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargetsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.VpnTargets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTarget;
 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;
 
 @Singleton
-public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInstance, VpnInstanceListener> {
+public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<VpnInstance> {
     private static final Logger LOG = LoggerFactory.getLogger(VpnInstanceListener.class);
     private static final String LOGGING_PREFIX_ADD = "VPN-ADD:";
+    private static final String LOGGING_PREFIX_UPDATE = "VPN-UPDATE:";
     private static final String LOGGING_PREFIX_DELETE = "VPN-REMOVE:";
     private final DataBroker dataBroker;
+    private final ManagedNewTransactionRunner txRunner;
     private final IdManagerService idManager;
     private final VpnInterfaceManager vpnInterfaceManager;
     private final IFibManager fibManager;
     private final VpnOpDataSyncer vpnOpDataNotifier;
     private final IMdsalApiManager mdsalManager;
     private final JobCoordinator jobCoordinator;
+    private final VpnUtil vpnUtil;
 
     @Inject
     public VpnInstanceListener(final DataBroker dataBroker, final IdManagerService idManager,
             final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
             final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
-            final JobCoordinator jobCoordinator) {
-        super(VpnInstance.class, VpnInstanceListener.class);
+            final JobCoordinator jobCoordinator, VpnUtil vpnUtil) {
+        super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class),
+                Executors.newListeningSingleThreadExecutor("VpnInstanceListener", LOG));
         this.dataBroker = dataBroker;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.idManager = idManager;
         this.vpnInterfaceManager = vpnInterfaceManager;
         this.fibManager = fibManager;
         this.vpnOpDataNotifier = vpnOpDataSyncer;
         this.mdsalManager = mdsalManager;
         this.jobCoordinator = jobCoordinator;
+        this.vpnUtil = vpnUtil;
+        start();
     }
 
-    @PostConstruct
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
-        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
     @Override
-    protected InstanceIdentifier<VpnInstance> getWildCardPath() {
-        return InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class);
+    @PreDestroy
+    public void close() {
+        super.close();
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
-    @Override
-    protected VpnInstanceListener getDataTreeChangeListener() {
-        return VpnInstanceListener.this;
-    }
 
     @Override
-    protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
-        LOG.trace("{} remove: VPN event key: {}, value: {}", LOGGING_PREFIX_DELETE, identifier, del);
+    public void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
+        LOG.trace("{} : VPN event key: {}, value: {}", LOGGING_PREFIX_DELETE, identifier, del);
         final String vpnName = del.getVpnInstanceName();
         Optional<VpnInstanceOpDataEntry> vpnOpValue;
-        String primaryRd = VpnUtil.getPrimaryRd(del);
+        String primaryRd = vpnUtil.getVpnRd(vpnName);
+        if (primaryRd == null) {
+            LOG.error("{}, failed to remove VPN: primaryRd is null for vpn {}", LOGGING_PREFIX_DELETE, vpnName);
+            return;
+        }
 
         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
         try {
             vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd));
-        } catch (ReadFailedException e) {
-            LOG.error("{} remove: Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ",
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("{}, failed to remove VPN: Exception while retrieving VpnInstanceOpDataEntry for VPN {}. ",
                     LOGGING_PREFIX_DELETE,  vpnName, e);
             return;
         }
 
         if (!vpnOpValue.isPresent()) {
-            LOG.error("{} remove: Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", LOGGING_PREFIX_DELETE,
-                    vpnName);
+            LOG.error("{}, failed to remove VPN: Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ",
+                LOGGING_PREFIX_DELETE, vpnName);
             return;
         } else {
-            jobCoordinator.enqueueJob("VPN-" + vpnName, () -> {
-                VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
-                        .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
-                InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
-                WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
-                writeTxn.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
-
-                LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
-                        LOGGING_PREFIX_DELETE, vpnName, primaryRd);
-                return Collections.singletonList(writeTxn.submit());
-            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+            jobCoordinator.enqueueJob("VPN-" + vpnName, () ->
+                Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
+                    VpnInstanceOpDataEntryBuilder builder = null;
+                    InstanceIdentifier<VpnInstanceOpDataEntry> id = null;
+                    if (primaryRd != null) {
+                        builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
+                                .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
+                        id = VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
+                    } else {
+                        builder = new VpnInstanceOpDataEntryBuilder().setVrfId(vpnName)
+                                .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
+                        id = VpnUtil.getVpnInstanceOpDataIdentifier(vpnName);
+                    }
+                    tx.merge(id, builder.build());
+
+                    LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
+                            LOGGING_PREFIX_DELETE, vpnName, primaryRd);
+                })), SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
         }
     }
 
     @Override
-    protected void update(InstanceIdentifier<VpnInstance> identifier,
+    public void update(InstanceIdentifier<VpnInstance> identifier,
         VpnInstance original, VpnInstance update) {
-        LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}. Ignoring", identifier, update);
+        LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}.", identifier, update);
         String vpnName = update.getVpnInstanceName();
+        if (original != null && update != null
+                && original.getRouteDistinguisher() != null
+                && update.getRouteDistinguisher() != null
+                && original.getRouteDistinguisher().size()
+                !=  update.getRouteDistinguisher().size()) {
+            LOG.debug("VPN-UPDATE: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
+                    update.getRouteDistinguisher(),  original.getRouteDistinguisher());
+            vpnUtil.updateVpnInstanceWithRdList(vpnName, update.getRouteDistinguisher());
+        }
         vpnInterfaceManager.updateVpnInterfacesForUnProcessAdjancencies(vpnName);
     }
 
     @Override
-    protected void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
+    public void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
         LOG.trace("{} add: Add VPN event key: {}, value: {}", LOGGING_PREFIX_ADD, identifier, value);
         final String vpnName = value.getVpnInstanceName();
-        jobCoordinator.enqueueJob("VPN-" + vpnName, new AddVpnInstanceWorker(idManager, dataBroker, value),
+        jobCoordinator.enqueueJob("VPN-" + vpnName, new AddVpnInstanceWorker(dataBroker, value),
                 SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
     }
 
-    private class AddVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
+    private class AddVpnInstanceWorker implements Callable<List<? extends ListenableFuture<?>>> {
         private final Logger log = LoggerFactory.getLogger(AddVpnInstanceWorker.class);
-        IdManagerService idManager;
         VpnInstance vpnInstance;
         DataBroker broker;
 
-        AddVpnInstanceWorker(IdManagerService idManager,
-            DataBroker broker,
-            VpnInstance value) {
-            this.idManager = idManager;
+        AddVpnInstanceWorker(DataBroker broker,
+                VpnInstance value) {
             this.broker = broker;
             this.vpnInstance = value;
         }
@@ -176,19 +212,16 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         public List<ListenableFuture<Void>> call() {
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
-            WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
-            WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
-            addVpnInstance(vpnInstance, writeConfigTxn, writeOperTxn);
-            try {
-                writeOperTxn.submit().get();
-            } catch (InterruptedException | ExecutionException e) {
-                log.error("{} call: Error creating vpn {} ", LOGGING_PREFIX_ADD, vpnInstance.getVpnInstanceName());
-                throw new RuntimeException(e.getMessage(), e);
-            }
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
-            futures.add(writeConfigTxn.submit());
-            ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
-            Futures.addCallback(listenableFuture,
+            List<ListenableFuture<Void>> futures = new ArrayList<>(2);
+            futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
+                ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
+                        addVpnInstance(vpnInstance, confTx, operTx));
+                LoggingFutures.addErrorLogging(future, LOG, "{} call: error creating VPN {} rd {}",
+                        LOGGING_PREFIX_ADD, vpnInstance.getVpnInstanceName(),
+                        vpnInstance.getRouteDistinguisher());
+                futures.add(future);
+            }));
+            Futures.addCallback(Futures.allAsList(futures),
                                 new PostAddVpnInstanceWorker(vpnInstance , vpnInstance.getVpnInstanceName()),
                                 MoreExecutors.directExecutor());
             return futures;
@@ -197,13 +230,22 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void addVpnInstance(VpnInstance value, WriteTransaction writeConfigTxn,
-        WriteTransaction writeOperTxn) {
-        VpnAfConfig config = value.getIpv4Family();
+    private void addVpnInstance(VpnInstance value, TypedWriteTransaction<Configuration> writeConfigTxn,
+            TypedWriteTransaction<Operational> writeOperTxn) {
+        if (writeConfigTxn == null) {
+            LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
+                addVpnInstance(value, tx, writeOperTxn)), LOG, "Error adding VPN instance {}", value);
+            return;
+        }
+        if (writeOperTxn == null) {
+            LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx ->
+                addVpnInstance(value, writeConfigTxn, tx)), LOG, "Error adding VPN instance {}", value);
+            return;
+        }
         String vpnInstanceName = value.getVpnInstanceName();
 
-        long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
-        if (vpnId == 0) {
+        Uint32 vpnId = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
+        if (vpnId.longValue() == 0) {
             LOG.error("{} addVpnInstance: Unable to fetch label from Id Manager. Bailing out of adding operational"
                     + " data for Vpn Instance {}", LOGGING_PREFIX_ADD, value.getVpnInstanceName());
             return;
@@ -214,28 +256,13 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
             vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, primaryRd);
 
-        if (writeConfigTxn != null) {
-            writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-                VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
-                vpnInstanceToVpnId, WriteTransaction.CREATE_MISSING_PARENTS);
-        } else {
-            TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
-                vpnInstanceToVpnId, TransactionUtil.DEFAULT_CALLBACK);
-        }
+        writeConfigTxn.mergeParentStructurePut(VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
+            vpnInstanceToVpnId);
 
         VpnIds vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
             primaryRd, VpnUtil.isBgpVpn(vpnInstanceName, primaryRd));
 
-        if (writeConfigTxn != null) {
-            writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-                VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
-                vpnIdToVpnInstance, WriteTransaction.CREATE_MISSING_PARENTS);
-        } else {
-            TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
-                vpnIdToVpnInstance, TransactionUtil.DEFAULT_CALLBACK);
-        }
+        writeConfigTxn.mergeParentStructurePut(VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId), vpnIdToVpnInstance);
 
         try {
             String cachedTransType = fibManager.getConfTransType();
@@ -258,8 +285,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         VpnInstanceOpDataEntryBuilder builder =
                 new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd).setVpnId(vpnId)
                         .setVpnInstanceName(vpnInstanceName)
-                        .setVpnState(VpnInstanceOpDataEntry.VpnState.Created)
-                        .setIpv4Configured(false).setIpv6Configured(false);
+                        .setVpnState(VpnInstanceOpDataEntry.VpnState.Created);
         if (VpnUtil.isBgpVpn(vpnInstanceName, primaryRd)) {
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
                 .instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
@@ -267,16 +293,18 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             if (value.getL3vni() != null) {
                 builder.setL3vni(value.getL3vni());
             }
-            if (value.getType() == VpnInstance.Type.L2) {
+            if (value.isL2vpn()) {
                 builder.setType(VpnInstanceOpDataEntry.Type.L2);
             }
-            VpnTargets vpnTargets = config.getVpnTargets();
+            VpnTargets vpnTargets = value.getVpnTargets();
             if (vpnTargets != null) {
-                List<VpnTarget> vpnTargetList = vpnTargets.getVpnTarget();
-                if (vpnTargetList != null) {
-                    for (VpnTarget vpnTarget : vpnTargetList) {
+                @Nullable Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn
+                        .instances.vpn.instance.vpntargets.VpnTargetKey, VpnTarget> vpnTargetListMap
+                        = vpnTargets.nonnullVpnTarget();
+                if (vpnTargetListMap != null) {
+                    for (VpnTarget vpnTarget : vpnTargetListMap.values()) {
                         VpnTargetBuilder vpnTargetBuilder =
-                            new VpnTargetBuilder().setKey(new VpnTargetKey(vpnTarget.getKey().getVrfRTValue()))
+                            new VpnTargetBuilder().withKey(new VpnTargetKey(vpnTarget.key().getVrfRTValue()))
                                 .setVrfRTType(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
                                     .instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget.VrfRTType
                                     .forValue(vpnTarget.getVrfRTType().getIntValue())).setVrfRTValue(
@@ -288,20 +316,12 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             VpnTargetsBuilder vpnTargetsBuilder = new VpnTargetsBuilder().setVpnTarget(opVpnTargetList);
             builder.setVpnTargets(vpnTargetsBuilder.build());
 
-            List<String> rds = config.getRouteDistinguisher();
+            List<String> rds = value.getRouteDistinguisher();
             builder.setRd(rds);
         } else {
             builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.VPN);
         }
-        if (writeOperTxn != null) {
-            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
-                builder.build(), true);
-        } else {
-            TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
-                builder.build(), TransactionUtil.DEFAULT_CALLBACK);
-        }
+        writeOperTxn.mergeParentStructureMerge(VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd), builder.build());
         LOG.info("{} addVpnInstance: VpnInstanceOpData populated successfully for vpn {} rd {}", LOGGING_PREFIX_ADD,
                 vpnInstanceName, primaryRd);
     }
@@ -325,41 +345,44 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             if rd is null, then its either a router vpn instance (or) a vlan external network vpn instance.
             if rd is non-null, then it is a bgpvpn instance
              */
-            VpnAfConfig config = vpnInstance.getIpv4Family();
-            List<String> rd = config.getRouteDistinguisher();
-            if (rd == null || addBgpVrf(voids)) {
+            List<String> rd = vpnInstance.getRouteDistinguisher();
+            if (rd == null || addBgpVrf()) {
                 notifyTask();
                 vpnInterfaceManager.vpnInstanceIsReady(vpnName);
             }
             log.info("{} onSuccess: Vpn Instance Op Data addition for {} successful.", LOGGING_PREFIX_ADD, vpnName);
-            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker,
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(
                     VpnUtil.getPrimaryRd(vpnInstance));
 
             // bind service on each tunnel interface
             //TODO (KIRAN): Add a new listener to handle creation of new DC-GW binding and deletion of existing DC-GW.
             if (VpnUtil.isL3VpnOverVxLan(vpnInstance.getL3vni())) { //Handled for L3VPN Over VxLAN
                 for (String tunnelInterfaceName: getDcGatewayTunnelInterfaceNameList()) {
-                    VpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName, dataBroker,
-                            true/*isTunnelInterface*/, jobCoordinator);
+                    vpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName,
+                            true/*isTunnelInterface*/);
                 }
 
                 // install flow
                 List<MatchInfo> mkMatches = new ArrayList<>();
-                mkMatches.add(new MatchTunnelId(BigInteger.valueOf(vpnInstance.getL3vni())));
+                mkMatches.add(new MatchTunnelId(Uint64.valueOf(vpnInstance.getL3vni())));
 
                 List<InstructionInfo> instructions =
                         Arrays.asList(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnInstanceOpDataEntry
-                                .getVpnId()), MetaDataUtil.METADATA_MASK_VRFID),
+                                .getVpnId().toJava()), MetaDataUtil.METADATA_MASK_VRFID),
                                 new InstructionGotoTable(NwConstants.L3_GW_MAC_TABLE));
-
-                for (BigInteger dpnId: NWUtil.getOperativeDPNs(dataBroker)) {
-                    String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
-                            vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
-                    FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
-                            NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef, VpnConstants.DEFAULT_FLOW_PRIORITY,
-                            "VxLAN VPN Tunnel Bind Service", 0, 0, NwConstants.COOKIE_VM_FIB_TABLE,
-                            mkMatches, instructions);
-                    mdsalManager.installFlow(dpnId, flowEntity);
+                try {
+                    for (Uint64 dpnId: NWUtil.getOperativeDPNs(dataBroker)) {
+                        String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+                                vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
+                        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
+                                NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef,
+                                VpnConstants.DEFAULT_FLOW_PRIORITY, "VxLAN VPN Tunnel Bind Service",
+                                0, 0, NwConstants.COOKIE_VM_FIB_TABLE, mkMatches, instructions);
+                        mdsalManager.installFlow(dpnId, flowEntity);
+                    }
+                } catch (ExecutionException | InterruptedException e) {
+                    LOG.error("PostAddVpnInstanceWorker: Exception while getting the list of Operative DPNs for Vpn {}",
+                            vpnName, e);
                 }
 
                 ///////////////////////
@@ -368,16 +391,25 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
         // TODO Clean up the exception handling
         @SuppressWarnings("checkstyle:IllegalCatch")
-        private boolean addBgpVrf(List<Void> voids) {
-            VpnAfConfig config = vpnInstance.getIpv4Family();
-            String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
-            List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
+        private boolean addBgpVrf() {
+            String primaryRd = vpnUtil.getPrimaryRd(vpnName);
+            @Nullable Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn
+                    .instances.vpn.instance.vpntargets.VpnTargetKey, VpnTarget> vpnTargetList
+                    = vpnInstance.getVpnTargets().getVpnTarget();
 
             if (vpnTargetList == null) {
                 log.error("{} addBgpVrf: vpn target list is empty for vpn {} RD {}", LOGGING_PREFIX_ADD,
                         this.vpnName, primaryRd);
                 return false;
             }
+            // FIXME: separate out to somehow?
+            final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+            lock.lock();
+            try {
+                fibManager.addVrfTable(primaryRd, null);
+            } finally {
+                lock.unlock();
+            }
             vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, primaryRd);
             return true;
         }
@@ -402,71 +434,73 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         }
     }
 
+    @Nullable
     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
-        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
-            TransactionUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
-        if (vpnInstanceOpData.isPresent()) {
-            return vpnInstanceOpData.get();
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    id).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException("Error reading VPN instance data for " + rd, e);
         }
-        return null;
     }
 
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+            justification = "https://github.com/spotbugs/spotbugs/issues/811")
     private List<String> getDcGatewayTunnelInterfaceNameList() {
         List<String> tunnelInterfaceNameList = new ArrayList<>();
-
-        InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
-                .create(DcGatewayIpList.class);
-        Optional<DcGatewayIpList> dcGatewayIpListOptional = VpnUtil.read(dataBroker,
-                LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
-        if (!dcGatewayIpListOptional.isPresent()) {
-            LOG.info("No DC gateways configured.");
-            return tunnelInterfaceNameList;
-        }
-        List<DcGatewayIp> dcGatewayIps = dcGatewayIpListOptional.get().getDcGatewayIp();
-
-        InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
-                .create(ExternalTunnelList.class);
-
-        Optional<ExternalTunnelList> externalTunnelListOptional = VpnUtil.read(dataBroker,
-                LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
-        if (externalTunnelListOptional.isPresent()) {
-            List<ExternalTunnel> externalTunnels = externalTunnelListOptional.get().getExternalTunnel();
-
-            List<String> externalTunnelIpList = new ArrayList<>();
-            for (ExternalTunnel externalTunnel: externalTunnels) {
-                externalTunnelIpList.add(externalTunnel.getDestinationDevice());
-            }
-
-            List<String> dcGatewayIpList = new ArrayList<>();
-            for (DcGatewayIp dcGatewayIp: dcGatewayIps) {
-                dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
+        try {
+            InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
+                    .create(DcGatewayIpList.class);
+            Optional<DcGatewayIpList> dcGatewayIpListOptional = SingleTransactionDataBroker.syncReadOptional(
+                    dataBroker, LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
+            if (!dcGatewayIpListOptional.isPresent()) {
+                LOG.info("No DC gateways configured.");
+                return tunnelInterfaceNameList;
             }
-
-            // Find all externalTunnelIps present in dcGateWayIpList
-            List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
-            for (String externalTunnelIp: externalTunnelIpList) {
-                for (String dcGateWayIp: dcGatewayIpList) {
-                    if (externalTunnelIp.contentEquals(dcGateWayIp)) {
-                        externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
+            Map<DcGatewayIpKey, DcGatewayIp> keyDcGatewayIpMap = dcGatewayIpListOptional.get().nonnullDcGatewayIp();
+            InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
+                    .create(ExternalTunnelList.class);
+            Optional<ExternalTunnelList> externalTunnelListOptional = SingleTransactionDataBroker.syncReadOptional(
+                    dataBroker, LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
+            if (externalTunnelListOptional.isPresent()) {
+                Map<ExternalTunnelKey, ExternalTunnel> keyExternalTunnelMap
+                        = externalTunnelListOptional.get().nonnullExternalTunnel();
+                List<String> externalTunnelIpList = new ArrayList<>();
+                for (ExternalTunnel externalTunnel: keyExternalTunnelMap.values()) {
+                    externalTunnelIpList.add(externalTunnel.getDestinationDevice());
+                }
+                List<String> dcGatewayIpList = new ArrayList<>();
+                for (DcGatewayIp dcGatewayIp: keyDcGatewayIpMap.values()) {
+                    dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
+                }
+                // Find all externalTunnelIps present in dcGateWayIpList
+                List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
+                for (String externalTunnelIp: externalTunnelIpList) {
+                    for (String dcGateWayIp: dcGatewayIpList) {
+                        if (externalTunnelIp.contentEquals(dcGateWayIp)) {
+                            externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
+                        }
                     }
                 }
-            }
-
-
-            for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
-                for (ExternalTunnel externalTunnel: externalTunnels) {
-                    if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
-                        tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
+                for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
+                    for (ExternalTunnel externalTunnel: keyExternalTunnelMap.values()) {
+                        if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
+                            tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
+                        }
                     }
                 }
-            }
 
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("getDcGatewayTunnelInterfaceNameList: Failed to read data store");
         }
         return tunnelInterfaceNameList;
     }
 
-    private String getFibFlowRef(BigInteger dpnId, short tableId, String vpnName, int priority) {
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+            justification = "https://github.com/spotbugs/spotbugs/issues/811")
+    private String getFibFlowRef(Uint64 dpnId, short tableId, String vpnName, int priority) {
         return VpnConstants.FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
                 + NwConstants.FLOWID_SEPARATOR + vpnName + NwConstants.FLOWID_SEPARATOR + priority;
     }