Replacing nonNull API's in netvirt.
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / FibUtil.java
index 42067f4ae969a50b248f7b8caead321e4fd38c06..bdc7c3196a38ba73db6fa4563565c4d5cedbb723 100644 (file)
@@ -11,35 +11,43 @@ package org.opendaylight.netvirt.fibmanager;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.net.InetAddresses;
-import java.math.BigInteger;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.locks.ReentrantLock;
 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.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.genius.datastoreutils.ExpectedDataObjectNotFoundException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
-import org.opendaylight.genius.infra.Datastore;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.Datastore.Operational;
+import org.opendaylight.genius.infra.TypedReadTransaction;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
 import org.opendaylight.genius.infra.TypedWriteTransaction;
+import org.opendaylight.genius.itm.api.IITMProvider;
 import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.NWUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.Tunnel;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 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.opendaylight.flow.inventory.rev130819.FlowCapableNode;
@@ -51,6 +59,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.Dpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
@@ -82,17 +91,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpidL3vpnLbNexthops;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnDcGws;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnLbNexthops;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
-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.dpid.l3vpn.lb.nexthops.DpnLbNexthops;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGateway;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGatewayBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGatewayKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.Nexthops;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsKey;
@@ -107,10 +115,13 @@ 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.VpnToDpnListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
+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.rev150602.NetworkAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -120,48 +131,24 @@ public class FibUtil {
     private static final String FLOWID_PREFIX = "L3.";
 
     private final DataBroker dataBroker;
-    private final IElanService elanManager;
     private final IdManagerService idManager;
+    private final IITMProvider iitmProvider;
 
     @Inject
-    public FibUtil(DataBroker dataBroker, IElanService elanManager, IdManagerService idManager) {
+    public FibUtil(DataBroker dataBroker, IdManagerService idManager, IITMProvider iitmProvider) {
         this.dataBroker = dataBroker;
-        this.elanManager = elanManager;
         this.idManager = idManager;
-    }
-
-    static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
-        return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
-            .l3vpn.rev140815.VpnInterfaces.class)
-            .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
-                .VpnInterface.class,
-                new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
-                    .VpnInterfaceKey(vpnInterfaceName))
-            .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
-            .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
-                    .AdjacencyKey(ipAddress)).build();
+        this.iitmProvider = iitmProvider;
     }
 
     static InstanceIdentifier<Adjacency> getAdjacencyIdentifierOp(String vpnInterfaceName,
                                       String vpnName, String ipAddress) {
         LOG.debug("getAdjacencyIdentifierOp vpninterface {} vpn {} ip {}", vpnInterfaceName, vpnName, ipAddress);
         return getAdjListPathOp(vpnInterfaceName, vpnName).builder()
-                          .child(org.opendaylight.yang.gen.v1.urn.opendaylight
-                          .netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
-                          new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
-                              .AdjacencyKey(ipAddress)).build();
-    }
-
-    static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
-        return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
-            .rev140815.VpnInterfaces.class)
-            .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
-                .VpnInterface.class,
-                new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
-                    .VpnInterfaceKey(vpnInterfaceName))
-            .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
-            .build();
+                          .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204
+                                          .adjacency.list.Adjacency.class,
+                          new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204
+                                  .adjacency.list.AdjacencyKey(ipAddress)).build();
     }
 
     static InstanceIdentifier<AdjacenciesOp> getAdjListPathOp(String vpnInterfaceName, String vpnName) {
@@ -170,7 +157,7 @@ public class FibUtil {
             .AdjacenciesOp.class).build();
     }
 
-    static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
+    static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Uint32 vpnId, String ipPrefix) {
         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
             .rev130911.PrefixToInterface.class)
             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
@@ -198,15 +185,31 @@ public class FibUtil {
 
     Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getVpnInstance: Exception while reading the VpnInstanceOpData DS for the rd {} ", rd, e);
+        }
+        return Optional.empty();
     }
 
+    static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(TypedReadTransaction<Operational> operTx, String rd)
+        throws ExecutionException, InterruptedException {
+        return operTx.read(getVpnInstanceOpDataIdentifier(rd)).get();
+    }
+
+    @Nullable
     VpnInstanceOpDataEntry getVpnInstance(String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id =
                 InstanceIdentifier.create(VpnInstanceOpData.class)
                         .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
-        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
-                MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = Optional.empty();
+        try {
+            vpnInstanceOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, id);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getVpnInstance: Exception while reading the VpnInstanceOpData DS for the rd {} ", rd, e);
+        }
         return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
     }
 
@@ -214,15 +217,37 @@ public class FibUtil {
         return rd + FibConstants.SEPARATOR + prefix;
     }
 
-    Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
-        Optional<Prefixes> localNextHopInfoData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-            getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
+    @Nullable
+    Prefixes getPrefixToInterface(Uint32 vpnId, String ipPrefix) {
+        Optional<Prefixes> localNextHopInfoData = Optional.empty();
+        try {
+            localNextHopInfoData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL,
+                getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getPrefixToInterface: Exception while reading the prefixToInterface DS for the "
+                    + "prefix {} vpnId {}", ipPrefix, vpnId, e);
+        }
         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
     }
 
+    @Nullable
+    static Prefixes getPrefixToInterface(TypedReadTransaction<Operational> operTx, Uint32 vpnId, String ipPrefix)
+            throws ExecutionException, InterruptedException {
+        return operTx.read(getPrefixToInterfaceIdentifier(vpnId, ipPrefix)).get().orElse(null);
+    }
+
+    @Nullable
     String getMacAddressFromPrefix(String ifName, String vpnName, String ipPrefix) {
-        Optional<Adjacency> adjacencyData = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                       getAdjacencyIdentifierOp(ifName, vpnName, ipPrefix));
+        Optional<Adjacency> adjacencyData;
+        try {
+            adjacencyData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifierOp(ifName, vpnName, ipPrefix));
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getMacAddressFromPrefix: Exception while reading adj-op DS for the interface {} prefix {} "
+                    + "vpn {}", ifName, ipPrefix, vpnName, e);
+            return null;
+        }
         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
     }
 
@@ -247,11 +272,15 @@ public class FibUtil {
                     .VpnInstanceKey(vpnName)).build();
     }
 
-    public long getVpnId(String vpnName) {
-
+    public Uint32 getVpnId(String vpnName) {
         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
-                VpnInstance::getVpnId).orElse(-1L);
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id)
+                    .map(VpnInstance::getVpnId).orElse(Uint32.ZERO);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getVpnNameFromId: Exception while reading vpnInstanceToVpnId DS for the vpn {}", vpnName, e);
+        }
+        return Uint32.ZERO;
     }
 
     /**
@@ -261,17 +290,23 @@ public class FibUtil {
      * @return The vpn instance
      */
     public Optional<String> getVpnNameFromRd(String rd) {
-        return Optional.fromJavaUtil(
-                getVpnInstanceOpData(rd).toJavaUtil().map(VpnInstanceOpDataEntry::getVpnInstanceName));
+        return Optional.ofNullable(getVpnInstanceOpData(rd).map(VpnInstanceOpDataEntry::getVpnInstanceName)
+                .orElse(null));
     }
 
-    public String getVpnNameFromId(long vpnId) {
+    @Nullable
+    public String getVpnNameFromId(Uint32 vpnId) {
         InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(
-                VpnIds::getVpnInstanceName).orElse(null);
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id)
+                    .map(VpnIds::getVpnInstanceName).orElse(null);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getVpnNameFromId: Exception while reading vpnIdToVpnInstance DS for the vpnId {}", vpnId, e);
+        }
+        return null;
     }
 
-    static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
+    static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(Uint32 vpnId) {
         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
     }
@@ -279,8 +314,8 @@ public class FibUtil {
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void addOrUpdateFibEntry(String rd, String macAddress, String prefix, List<String> nextHopList,
-            VrfEntry.EncapType encapType, long label, long l3vni, String gwMacAddress, String parentVpnRd,
-            RouteOrigin origin, WriteTransaction writeConfigTxn) {
+            VrfEntry.EncapType encapType, Uint32 label, Uint32 l3vni, String gwMacAddress, String parentVpnRd,
+            RouteOrigin origin, TypedWriteTransaction<Configuration> writeConfigTxn) {
         if (rd == null || rd.isEmpty()) {
             LOG.error("Prefix {} not associated with vpn", prefix);
             return;
@@ -307,23 +342,23 @@ public class FibUtil {
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix, List<String> nextHopList,
-            long label, Long l3vni, VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
-            String gatewayMacAddress, String parentVpnRd, WriteTransaction writeConfigTxn) {
+            Uint32 label, Uint32 l3vni, VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
+            String gatewayMacAddress, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
         VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
         if (parentVpnRd != null) {
             vrfEntryBuilder.setParentVpnRd(parentVpnRd);
         }
         buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
         if (writeConfigTxn != null) {
-            writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
+            writeConfigTxn.mergeParentStructureMerge(vrfEntryId, vrfEntryBuilder.build());
         } else {
             MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
         }
     }
 
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void addFibEntryForRouterInterface(String rd, String prefix, RouterInterface routerInterface, long label,
-            WriteTransaction writeConfigTxn) {
+    public void addFibEntryForRouterInterface(String rd, String prefix, RouterInterface routerInterface, Uint32 label,
+            TypedWriteTransaction<Configuration> writeConfigTxn) {
         if (rd == null || rd.isEmpty()) {
             LOG.error("Prefix {} not associated with vpn", prefix);
             return;
@@ -341,7 +376,7 @@ public class FibUtil {
                 .addAugmentation(RouterInterface.class, routerInterface).build();
 
             if (writeConfigTxn != null) {
-                writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
+                writeConfigTxn.mergeParentStructureMerge(vrfEntryId, vrfEntry);
             } else {
                 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
             }
@@ -351,46 +386,55 @@ public class FibUtil {
         }
     }
 
-    private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
-                                         long l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
+    private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, Uint32 label,
+                                         Uint32 l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
         if (encapType == null) {
             builder.setMac(macAddress);
             return;
         }
 
         // TODO - validate this check
-        if (l3vni != 0) {
+        if (l3vni.longValue() != 0) {
             builder.setL3vni(l3vni);
         }
         builder.setEncapType(encapType);
         builder.setGatewayMacAddress(gatewayMac);
         builder.setMac(macAddress);
-        Long lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
+        Uint32 lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
         List<RoutePaths> routePaths = nextHopList.stream()
                         .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
                         .map(nextHop -> FibHelper.buildRoutePath(nextHop, lbl)).collect(toList());
         builder.setRoutePaths(routePaths);
     }
 
-    public void removeFibEntry(String rd, String prefix, WriteTransaction writeConfigTxn) {
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public void removeFibEntry(String rd, String prefix, String eventSource,
+                               TypedWriteTransaction<Configuration> writeConfigTxn) {
 
         if (rd == null || rd.isEmpty()) {
             LOG.error("Prefix {} not associated with vpn", prefix);
             return;
         }
-        LOG.debug("removeFibEntry: Removing fib entry with destination prefix {} from vrf table for rd {}",
-                prefix, rd);
-
-        InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
-            InstanceIdentifier.builder(FibEntries.class)
-                .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
-        InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
-        if (writeConfigTxn != null) {
-            writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
-        } else {
-            MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        try {
+            LOG.debug("removeFibEntry: Removing fib entry with destination prefix {} from vrf table for rd {}",
+                    prefix, rd);
+
+            InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
+                    InstanceIdentifier.builder(FibEntries.class)
+                            .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class,
+                            new VrfEntryKey(prefix));
+            InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
+            if (writeConfigTxn != null) {
+                writeConfigTxn.delete(vrfEntryId);
+            } else {
+                MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+            }
+            LOG.error("removeFibEntry: Removed Fib Entry rd {} prefix {} source {} ",
+                    rd, prefix, eventSource);
+        } catch (RuntimeException e) {
+            LOG.error("removeFibEntry: Unable to remove Fib Entry for rd {} prefix {} source {} ",
+                    rd, prefix, eventSource);
         }
-        LOG.info("removeFibEntry: Removed Fib Entry rd {} prefix {}",rd, prefix);
     }
 
     /**
@@ -402,8 +446,7 @@ public class FibUtil {
      *                        If null or empty, then the whole VrfEntry is removed
      */
     public void removeOrUpdateFibEntry(String rd, String prefix, String nextHopToRemove,
-            WriteTransaction writeConfigTxn) {
-
+            TypedWriteTransaction<Configuration> writeConfigTxn) {
         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {} nextHop {}", prefix, rd,
                 nextHopToRemove);
 
@@ -411,17 +454,24 @@ public class FibUtil {
         InstanceIdentifier<VrfEntry> vrfEntryId =
             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
                 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
-        Optional<VrfEntry> entry = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        Optional<VrfEntry> entry = Optional.empty();
+        try {
+            entry = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("removeOrUpdateFibEntry: Exception while reading vrfEntry for the prefix {} rd {} nexthop {}",
+                    prefix, rd, nextHopToRemove, e);
+        }
         if (entry.isPresent()) {
-            final List<RoutePaths> routePaths = entry.get().getRoutePaths();
+            final List<RoutePaths> routePaths = new ArrayList<RoutePaths>(entry.get().nonnullRoutePaths().values());
             if (routePaths == null || routePaths.isEmpty()) {
                 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
                 return;
             }
             java.util.Optional<RoutePaths> optRoutePath =
                     routePaths.stream()
-                              .filter(routePath -> routePath.getNexthopAddress().equals(
-                                    nextHopToRemove)).findFirst();
+                        .filter(
+                            routePath -> Objects.equals(routePath.getNexthopAddress(), nextHopToRemove)).findFirst();
             if (!optRoutePath.isPresent()) {
                 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
                 return;
@@ -430,7 +480,7 @@ public class FibUtil {
             if (routePaths.size() == 1) {
                 // Remove the whole entry
                 if (writeConfigTxn != null) {
-                    writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+                    writeConfigTxn.delete(vrfEntryId);
                 } else {
                     MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
                 }
@@ -452,38 +502,49 @@ public class FibUtil {
     /**
      * Adds or removes nextHop from routePath based on the flag nextHopAdd.
      */
-    public void updateRoutePathForFibEntry(String rd, String prefix, String nextHop, long label,
-            boolean nextHopAdd, WriteTransaction writeConfigTxn) {
+    public void updateRoutePathForFibEntry(String rd, String prefix, String nextHop, Uint32 label,
+            boolean nextHopAdd, TypedWriteTransaction<Configuration> writeConfigTxn) {
 
         LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
 
         InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
-        String routePathKey = rd + prefix + nextHop;
-        synchronized (routePathKey.intern()) {
+
+        // FIXME: use routePathId instead?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(rd + prefix + nextHop);
+        lock.lock();
+        try {
             if (nextHopAdd) {
                 RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
                 if (writeConfigTxn != null) {
-                    writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, routePathId, routePaths,
-                            WriteTransaction.CREATE_MISSING_PARENTS);
+                    writeConfigTxn.mergeParentStructurePut(routePathId, routePaths);
                 } else {
                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
                 }
                 LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
             } else {
-                Optional<RoutePaths> routePath = MDSALUtil.read(dataBroker,
-                        LogicalDatastoreType.CONFIGURATION, routePathId);
+                Optional<RoutePaths> routePath;
+                try {
+                    routePath = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                            LogicalDatastoreType.CONFIGURATION, routePathId);
+                } catch (ExecutionException | InterruptedException e) {
+                    LOG.error("updateRoutePathForFibEntry: Exception while reading the RoutePath with rd {}, "
+                                    + "prefix {} and nh {}", rd, prefix, nextHop, e);
+                    return;
+                }
                 if (!routePath.isPresent()) {
                     LOG.warn("Couldn't find RoutePath with rd {}, prefix {} and nh {} for deleting",
                             rd, prefix, nextHop);
                     return;
                 }
                 if (writeConfigTxn != null) {
-                    writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathId);
+                    writeConfigTxn.delete(routePathId);
                 } else {
                     MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routePathId);
                 }
                 LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
             }
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -502,7 +563,7 @@ public class FibUtil {
         }
     }
 
-    public void removeVrfTable(String rd, TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
+    public void removeVrfTable(String rd, TypedWriteTransaction<Configuration> writeConfigTxn) {
         LOG.debug("Removing vrf table for rd {}", rd);
         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
@@ -511,41 +572,60 @@ public class FibUtil {
         if (writeConfigTxn != null) {
             writeConfigTxn.delete(vrfTableId);
         } else {
-            Optional<VrfTables> ifStateOptional = MDSALUtil.read(dataBroker,
-                    LogicalDatastoreType.CONFIGURATION, vrfTableId);
+            Optional<VrfTables> ifStateOptional;
+            try {
+                ifStateOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, vrfTableId);
+            } catch (ExecutionException | InterruptedException e) {
+                LOG.error("removeVrfTable: Exception while reading vrfTable for the rd {}", rd, e);
+                return;
+            }
             if (ifStateOptional.isPresent()) {
                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
             }
         }
     }
 
-    public static java.util.Optional<Long> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
-        List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
-        if (routePaths == null || routePaths.isEmpty() || vrfEntry.getRoutePaths().get(0).getLabel() == null) {
+    public static java.util.Optional<Uint32> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
+        List<RoutePaths> routePaths = new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values());
+        if (routePaths == null || routePaths.isEmpty()
+                || new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values()).get(0).getLabel() == null) {
             return java.util.Optional.empty();
         }
-        return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
+        return java.util.Optional.of(new ArrayList<RoutePaths>(vrfEntry
+                .nonnullRoutePaths().values()).get(0).getLabel());
+
     }
 
     public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
-        List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
+        List<RoutePaths> routePaths = new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values());
         if (routePaths == null || routePaths.isEmpty()) {
             return java.util.Optional.empty();
         }
-        return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());
+        return java.util.Optional.of(new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values())
+                .get(0).getNexthopAddress());
     }
 
-    public static java.util.Optional<Long> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
-        List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
+    public static java.util.Optional<Uint32> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
+        List<RoutePaths> routePaths = new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values());
         if (routePaths == null || routePaths.isEmpty()) {
             return java.util.Optional.empty();
         }
         return routePaths.stream()
-                .filter(routePath -> routePath.getNexthopAddress().equals(nextHopIp))
+                .filter(routePath -> Objects.equals(routePath.getNexthopAddress(), nextHopIp))
                 .findFirst()
                 .map(RoutePaths::getLabel);
     }
 
+    @Nullable
+    public StateTunnelList getTunnelState(String interfaceName) throws ReadFailedException {
+        Optional<StateTunnelList> tunnelStateOptional = iitmProvider.getTunnelState(interfaceName);
+        if (tunnelStateOptional.isPresent()) {
+            return tunnelStateOptional.get();
+        }
+        return null;
+    }
+
     public static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
                 InstanceIdentifier.builder(InterfacesState.class)
@@ -558,60 +638,69 @@ public class FibUtil {
         return id;
     }
 
-    public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
-        .state.Interface getInterfaceStateFromOperDS(String interfaceName) {
+    public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
+        .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
-        Optional<Interface> ifStateOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+        Optional<Interface> ifStateOptional;
+        try {
+            ifStateOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, ifStateId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getInterfaceStateFromOperDS: Exception while reading interface-state for the interface {}",
+                    interfaceName, e);
+            return null;
+        }
         if (ifStateOptional.isPresent()) {
             return ifStateOptional.get();
         }
-
         return null;
     }
 
-    public static String getCreateLocalNextHopJobKey(Long vpnId, BigInteger dpnId, String prefix) {
+    public static String getCreateLocalNextHopJobKey(Uint32 vpnId, Uint64 dpnId, String prefix) {
         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
     }
 
+    public static String getCreateRemoteNextHopJobKey(Uint32 vpnId, Uint64 dpnId, String prefix) {
+        return getCreateLocalNextHopJobKey(vpnId, dpnId, prefix);
+    }
+
     public static String getJobKeyForRdPrefix(String rd, String prefix) {
         return "FIB-" + rd + "-" + prefix;
     }
 
-    public static String getJobKeyForVpnIdDpnId(Long vpnId, BigInteger dpnId) {
+    public static String getJobKeyForVpnIdDpnId(Uint32 vpnId, Uint64 dpnId) {
         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() ;
     }
 
-    public void updateUsedRdAndVpnToExtraRoute(WriteTransaction writeConfigTxn, WriteTransaction writeOperTxn,
-                                               String tunnelIpRemoved, String primaryRd, String prefix) {
-        Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(primaryRd);
+    public void updateUsedRdAndVpnToExtraRoute(TypedReadWriteTransaction<Configuration> confTx,
+            TypedReadWriteTransaction<Operational> operTx, String tunnelIpRemoved, String primaryRd, String prefix)
+            throws ExecutionException, InterruptedException {
+        Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(operTx, primaryRd);
         if (!optVpnInstance.isPresent()) {
             return;
         }
         VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
         String vpnName = vpnInstance.getVpnInstanceName();
-        long vpnId = vpnInstance.getVpnId();
-        List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, prefix);
+        Uint32 vpnId = vpnInstance.getVpnId();
+        List<String> usedRds = VpnExtraRouteHelper.getUsedRds(confTx, vpnId, prefix);
         // To identify the rd to be removed, iterate through the allocated rds for the prefix and check
         // which rd is allocated for the particular OVS.
         for (String usedRd : usedRds) {
-            Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper
-                    .getVpnExtraroutes(dataBroker, vpnName, usedRd, prefix);
+            Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getVpnExtraroutes(operTx, vpnName, usedRd, prefix);
             if (vpnExtraRoutes.isPresent()) {
                 // Since all the nexthops under one OVS will be present under one rd, only 1 nexthop is read
                 // to identify the OVS
                 String nextHopRemoved = vpnExtraRoutes.get().getNexthopIpList().get(0);
-                Prefixes prefixToInterface = getPrefixToInterface(vpnId, getIpPrefix(nextHopRemoved));
+                Prefixes prefixToInterface = getPrefixToInterface(operTx, vpnId, getIpPrefix(nextHopRemoved));
                 if (prefixToInterface != null && tunnelIpRemoved
                         .equals(getEndpointIpAddressForDPN(prefixToInterface.getDpnId()))) {
                     LOG.info("updating data-stores for prefix {} with primaryRd {} for interface {} on vpn {} ",
                             prefix, primaryRd, prefixToInterface.getVpnInterfaceName(), vpnName);
-                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                            FibUtil.getAdjacencyIdentifierOp(prefixToInterface.getVpnInterfaceName(),
+                    operTx.delete(FibUtil.getAdjacencyIdentifierOp(prefixToInterface.getVpnInterfaceName(),
                                     vpnName, prefix));
-                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                            VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
-                    writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION,
+                    operTx.delete(VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
+                    MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
                             VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHopRemoved));
                     break;
                 }
@@ -619,12 +708,19 @@ public class FibUtil {
         }
     }
 
-    private String getEndpointIpAddressForDPN(BigInteger dpnId) {
+    private String getEndpointIpAddressForDPN(Uint64 dpnId) {
         //TODO: Move it to a common place for vpn and fib
         String nextHopIp = null;
         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
             InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
-        Optional<DPNTEPsInfo> tunnelInfo = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
+        Optional<DPNTEPsInfo> tunnelInfo;
+        try {
+            tunnelInfo = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getEndpointIpAddressForDPN: Exception while reading DPN {} TEP info", dpnId, e);
+            return null;
+        }
         if (tunnelInfo.isPresent()) {
             List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
             if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
@@ -653,7 +749,15 @@ public class FibUtil {
 
     public List<String> getNextHopAddresses(String rd, String prefix) {
         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
-        Optional<VrfEntry> vrfEntry = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        Optional<VrfEntry> vrfEntry;
+        try {
+            vrfEntry = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getNextHopAddresses: Exception while reading vrfEntry DS for the prefix {} rd {}",
+                    prefix, rd, e);
+            return Collections.emptyList();
+        }
         if (vrfEntry.isPresent()) {
             return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
         } else {
@@ -666,74 +770,98 @@ public class FibUtil {
         return "gre-" + availableDcGws.stream().sorted().collect(joining(":"));
     }
 
-    public static void updateLbGroupInfo(BigInteger dpnId, String destinationIp, String groupIdKey,
-            String groupId, WriteTransaction tx) {
-        InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
-        DpnLbNexthops dpnToLbNextHop = buildDpnLbNextHops(dpnId, destinationIp, groupIdKey);
-        tx.merge(LogicalDatastoreType.OPERATIONAL, id, dpnToLbNextHop);
+    public static void updateLbGroupInfo(Uint64 dpnId, String groupIdKey,
+            String groupId, TypedWriteTransaction<Operational> tx) {
         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(groupIdKey);
         Nexthops nextHopsToGroupId = buildNextHops(dpnId, groupIdKey, groupId);
-        tx.merge(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
+        tx.merge(nextHopsId, nextHopsToGroupId);
+    }
+
+    public static void removeL3vpnDcGateWay(String destinationIp, TypedReadWriteTransaction<Operational> tx)
+            throws InterruptedException, ExecutionException {
+        InstanceIdentifier<DcGateway> dcGateWayId = getDcGwInstance(destinationIp);
+        Optional<DcGateway> dcGateWayOpt = tx.read(dcGateWayId).get();
+        if (!dcGateWayOpt.isPresent()) {
+            return;
+        }
+        tx.delete(dcGateWayId);
+    }
+
+    public static void addL3vpnDcGateWay(String destinationIp, TypedReadWriteTransaction<Operational> tx)
+            throws InterruptedException, ExecutionException {
+        InstanceIdentifier<DcGateway> dcGateWayId = getDcGwInstance(destinationIp);
+        Optional<DcGateway> dcGateWayOpt = tx.read(dcGateWayId).get();
+        if (!dcGateWayOpt.isPresent()) {
+            tx.put(dcGateWayId,
+                    new DcGatewayBuilder()
+                    .withKey(new DcGatewayKey(destinationIp))
+                    .setIpAddress(destinationIp).build()
+            );
+        }
     }
 
-    public static void removeDpnIdToNextHopInfo(String destinationIp, BigInteger dpnId, WriteTransaction tx) {
-        InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
-        tx.delete(LogicalDatastoreType.OPERATIONAL, id);
+    private static InstanceIdentifier<DcGateway> getDcGwInstance(String destinationIp) {
+        return InstanceIdentifier.builder(L3vpnDcGws.class)
+                .child(DcGateway.class, new DcGatewayKey(destinationIp))
+                .build();
     }
 
-    public static void removeOrUpdateNextHopInfo(BigInteger dpnId, String nextHopKey, String groupId,
-            Nexthops nexthops, WriteTransaction tx) {
+    public static void removeOrUpdateNextHopInfo(Uint64 dpnId, String nextHopKey, String groupId,
+            Nexthops nexthops, TypedWriteTransaction<Operational> tx) {
         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(nextHopKey);
-        List<String> targetDeviceIds = nexthops.getTargetDeviceId();
+        List<String> targetDeviceIds =
+            nexthops.getTargetDeviceId() != null ? new ArrayList<>(nexthops.getTargetDeviceId()) : new ArrayList<>();
         targetDeviceIds.remove(dpnId.toString());
         if (targetDeviceIds.isEmpty()) {
-            tx.delete(LogicalDatastoreType.OPERATIONAL, nextHopsId);
+            tx.delete(nextHopsId);
         } else {
             Nexthops nextHopsToGroupId = new NexthopsBuilder().withKey(new NexthopsKey(nextHopKey))
                 .setNexthopKey(nextHopKey)
                 .setGroupId(groupId)
                 .setTargetDeviceId(targetDeviceIds).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
+            tx.put(nextHopsId, nextHopsToGroupId);
         }
     }
 
-    private static InstanceIdentifier<DpnLbNexthops> getDpnLbNexthopsIdentifier(BigInteger dpnId,
-            String destinationIp) {
-        return InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
-                .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
-                .build();
-    }
-
     private static InstanceIdentifier<Nexthops> getNextHopsIdentifier(String groupIdKey) {
         return InstanceIdentifier.builder(L3vpnLbNexthops.class)
                 .child(Nexthops.class, new NexthopsKey(groupIdKey)).build();
     }
 
-    private static Nexthops buildNextHops(BigInteger dpnId, String groupIdKey, String groupId) {
+    private static Nexthops buildNextHops(Uint64 dpnId, String groupIdKey, String groupId) {
         return new NexthopsBuilder().withKey(new NexthopsKey(groupIdKey))
                 .setNexthopKey(groupIdKey)
                 .setGroupId(groupId)
                 .setTargetDeviceId(Collections.singletonList(dpnId.toString())).build();
     }
 
-    private static DpnLbNexthops buildDpnLbNextHops(BigInteger dpnId, String destinationIp,
-            String groupIdKey) {
-        return new DpnLbNexthopsBuilder().withKey(new DpnLbNexthopsKey(destinationIp, dpnId))
-                .setDstDeviceId(destinationIp).setSrcDpId(dpnId)
-                .setNexthopKey(Collections.singletonList(groupIdKey)).build();
-    }
-
     public Optional<Nexthops> getNexthops(String nextHopKey) {
         InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
                 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    nextHopsId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getNexthops: Exception while reading L3-vpn-nexthop DS for the nexthop {}", nextHopKey, e);
+        }
+        return Optional.empty();
     }
 
-    public Optional<DpnLbNexthops> getDpnLbNexthops(BigInteger dpnId, String destinationIp) {
-        InstanceIdentifier<DpnLbNexthops> id = InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
-                .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
+    public List<String> getL3VpnDcGateWays() {
+        InstanceIdentifier<L3vpnDcGws> id = InstanceIdentifier.builder(L3vpnDcGws.class)
                 .build();
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        Optional<L3vpnDcGws> dcGwsOpt;
+        try {
+            dcGwsOpt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, id);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getNexthops: Exception while reading L3vpnDcGws DS", e);
+            return Collections.emptyList();
+        }
+        if (!dcGwsOpt.isPresent()) {
+            return Collections.emptyList();
+        }
+        return dcGwsOpt.get().nonnullDcGateway().values().stream().map(DcGateway::getIpAddress).collect(toList());
     }
 
     static boolean isVxlanNetwork(NetworkType networkType) {
@@ -743,12 +871,16 @@ public class FibUtil {
         return false;
     }
 
-    static NodeRef buildNodeRef(BigInteger dpId) {
+    static boolean isBgpVpn(String vpnName, String rd) {
+        return vpnName != null && !vpnName.equals(rd);
+    }
+
+    static NodeRef buildNodeRef(Uint64 dpId) {
         return new NodeRef(InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
     }
 
-    static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, BigInteger dpId) {
+    static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, Uint64 dpId) {
         return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpId)))
                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
     }
@@ -774,22 +906,22 @@ public class FibUtil {
         return bucketsBuilder.build();
     }
 
-    static String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
+    static String getFlowRef(Uint64 dpnId, short tableId, Uint32 label, int priority) {
         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
                 + NwConstants.FLOWID_SEPARATOR + priority;
     }
 
-    static String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
+    static String getFlowRef(Uint64 dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
                 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
     }
 
-    static String getL3VpnGatewayFlowRef(short l3GwMacTable, BigInteger dpId, long vpnId, String gwMacAddress) {
+    static String getL3VpnGatewayFlowRef(short l3GwMacTable, Uint64 dpId, Uint32 vpnId, String gwMacAddress) {
         return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
                 + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
     }
 
-    static Node buildDpnNode(BigInteger dpnId) {
+    static Node buildDpnNode(Uint64 dpnId) {
         return new NodeBuilder().setId(new NodeId("openflow:" + dpnId))
                 .withKey(new NodeKey(new NodeId("openflow:" + dpnId))).build();
     }
@@ -842,7 +974,7 @@ public class FibUtil {
         }
     }
 
-    public boolean isInterfacePresentInDpn(String vpnName, BigInteger dpnId) {
+    public boolean isInterfacePresentInDpn(String vpnName, Uint64 dpnId) {
         InstanceIdentifier<VpnToDpnList> vpnToDpnListId = InstanceIdentifier.builder(VpnInstanceOpData.class)
                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vpnName))
                 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
@@ -853,9 +985,33 @@ public class FibUtil {
                     && !vpnToDpnList.getVpnInterfaces().isEmpty()) {
                 return true;
             }
-        } catch (ReadFailedException e) {
+        } catch (ExpectedDataObjectNotFoundException e) {
             LOG.warn("Failed to read interfaces with error {}", e.getMessage());
         }
         return false;
     }
+
+    public static boolean checkFibEntryExist(DataBroker broker, String rd, String prefix, String nextHopIp) {
+        InstanceIdentifier<VrfEntry> vrfEntryId =
+                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
+                        .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
+        Optional<VrfEntry> entry;
+        try {
+            entry = SingleTransactionDataBroker.syncReadOptional(broker,
+                    LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("checkFibEntryExist: Exception while reading vrfEntry DS for the prefix {} rd {} nexthop {}",
+                    prefix, rd, nextHopIp, e);
+            return false;
+        }
+        if (entry.isPresent()) {
+            Map<RoutePathsKey, RoutePaths> pathsMap = entry.get().nonnullRoutePaths();
+            for (RoutePaths path: pathsMap.values()) {
+                if (path.getNexthopAddress().equals(nextHopIp)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }