Use documenting constants for put()
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / FibUtil.java
index 5f4f59e2714fcfb214bb0f2aef640e14f0b85bd3..883813c6a1ce291336b48870b8cd7a68d1613ed9 100644 (file)
@@ -10,14 +10,13 @@ package org.opendaylight.netvirt.fibmanager;
 
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
+import static org.opendaylight.netvirt.fibmanager.VrfEntryListener.isOpenStackVniSemanticsEnforced;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
 
 import java.math.BigInteger;
+import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -25,11 +24,11 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 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.TransactionCommitFailedException;
+import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
@@ -39,16 +38,31 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.re
 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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
+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.group.types.rev131018.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
@@ -72,18 +86,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
 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.VpnInstanceOpDataEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.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.rev150602.NetworkAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -91,50 +99,7 @@ import org.slf4j.LoggerFactory;
 
 public class FibUtil {
     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
-
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                          InstanceIdentifier<T> path) {
-
-        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
-
-        Optional<T> result = Optional.absent();
-        try {
-            result = tx.read(datastoreType, path).get();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-
-        return result;
-    }
-
-    static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.merge(datastoreType, path, data, true);
-        Futures.addCallback(tx.submit(), callback);
-    }
-
-    static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.put(datastoreType, path, data, true);
-        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
-        try {
-            futures.get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
-            throw new RuntimeException(e.getMessage());
-        }
-    }
-
-    static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-                                              InstanceIdentifier<T> path) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.delete(datastoreType, path);
-        Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
-    }
+    private static final String FLOWID_PREFIX = "L3.";
 
     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
@@ -182,19 +147,6 @@ public class FibUtil {
                     .VpnInterfaceKey(vpnInterfaceName)).build();
     }
 
-    public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
-        return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
-            .rev130911.VpnInstanceOpData.class)
-            .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                .VpnInstanceOpDataEntry.class,
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                    .VpnInstanceOpDataEntryKey(rd))
-            .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                .vpn.instance.op.data.entry.VpnToDpnList.class,
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                    .vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build();
-    }
-
     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
         return InstanceIdentifier.builder(VpnInstanceOpData.class)
             .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
@@ -202,7 +154,16 @@ public class FibUtil {
 
     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
-        return read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    static VpnInstanceOpDataEntry getVpnInstance(DataBroker dataBroker, String rd) {
+        InstanceIdentifier<VpnInstanceOpDataEntry> id =
+                InstanceIdentifier.create(VpnInstanceOpData.class)
+                        .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
+                MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
     }
 
     static String getNextHopLabelKey(String rd, String prefix) {
@@ -211,13 +172,13 @@ public class FibUtil {
     }
 
     static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
-        Optional<Prefixes> localNextHopInfoData = read(broker, LogicalDatastoreType.OPERATIONAL,
+        Optional<Prefixes> localNextHopInfoData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
             getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
     }
 
     static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
-        Optional<Adjacency> adjacencyData = read(broker, LogicalDatastoreType.OPERATIONAL,
+        Optional<Adjacency> adjacencyData = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
             getAdjacencyIdentifier(ifName, ipPrefix));
         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
     }
@@ -247,7 +208,7 @@ public class FibUtil {
     public static long getVpnId(DataBroker broker, String vpnName) {
 
         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
-        return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVpnId).or(-1L);
+        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVpnId).or(-1L);
     }
 
     /**
@@ -261,100 +222,10 @@ public class FibUtil {
         return getVpnInstanceOpData(broker, rd).transform(VpnInstanceOpDataEntry::getVpnInstanceName);
     }
 
-    static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
-        InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
-
-        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid).transform(
-            InterVpnLinks::getInterVpnLink).or(new ArrayList<>());
-    }
-
-    /**
-     * Returns the instance identifier for a given vpnLinkName.
-     *
-     * @param vpnLinkName The vpn link name
-     * @return InstanceIdentifier
-     */
-    public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
-        return InstanceIdentifier.builder(InterVpnLinkStates.class)
-            .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
-    }
-
-    /**
-     * Checks if the InterVpnLink is in Active state.
-     *
-     * @param broker The DataBroker
-     * @param vpnLinkName The vpn linkname
-     * @return The link state
-     */
-    public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
-        Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
-        if (!interVpnLinkState.isPresent()) {
-            LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
-            return false;
-        }
-
-        return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
-    }
-
-    /**
-     * Checks if the state of the interVpnLink.
-     *
-     * @param broker The DataBroker
-     * @param vpnLinkName The vpn linkname
-     * @return The link state
-     */
-    public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
-        InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
-        return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
-    }
-
-    /**
-     * Obtains the route-distinguisher for a given vpn-name.
-     *
-     * @param broker The DataBroker
-     * @param vpnName vpn name
-     * @return route-distinguisher
-     */
-    public static String getVpnRd(DataBroker broker, String vpnName) {
-        InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
-        return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVrfId).orNull();
-    }
-
-    public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
-        AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
-
-        try {
-            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
-            RpcResult<AllocateIdOutput> rpcResult = result.get();
-            if (rpcResult.isSuccessful()) {
-                return rpcResult.getResult().getIdValue().intValue();
-            } else {
-                LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
-            }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when getting Unique Id", e);
-        }
-        return 0;
-    }
-
-    static final FutureCallback<Void> DEFAULT_CALLBACK =
-        new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void result) {
-                LOG.debug("Success in Datastore operation");
-            }
-
-            @Override
-            public void onFailure(Throwable error) {
-                LOG.error("Error in Datastore operation", error);
-            }
-
-            ;
-        };
-
     public static String getVpnNameFromId(DataBroker broker, long vpnId) {
         InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
-        return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnIds::getVpnInstanceName).orNull();
+        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnIds::getVpnInstanceName)
+                .orNull();
     }
 
     static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
@@ -362,19 +233,6 @@ public class FibUtil {
             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
     }
 
-    public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                         InstanceIdentifier<T> path, T data) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.put(datastoreType, path, data, true);
-        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
-        try {
-            futures.get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
-            throw new RuntimeException(e.getMessage());
-        }
-    }
-
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
@@ -441,7 +299,7 @@ public class FibUtil {
 
             // Filling the nextHop with dummy nextHopAddress
             VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
-                    FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL)
+                    FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL, null /* parentVpnRd */)
                 .addAugmentation(RouterInterface.class, routerInterface).build();
 
             if (writeConfigTxn != null) {
@@ -461,7 +319,9 @@ public class FibUtil {
             builder.setMac(macAddress);
             return;
         }
-        if (!encapType.equals(VrfEntry.EncapType.Mplsgre)) {
+        //if (!encapType.equals(VrfEntry.EncapType.Mplsgre)) {
+        // TODO - validate this check
+        if (l3vni != 0) {
             builder.setL3vni(l3vni);
         }
         builder.setEncapType(encapType);
@@ -515,7 +375,6 @@ public class FibUtil {
             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
                 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
         Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
-
         if (entry.isPresent()) {
             final List<RoutePaths> routePaths = entry.get().getRoutePaths();
             if (routePaths == null || routePaths.isEmpty()) {
@@ -556,56 +415,37 @@ public class FibUtil {
         }
     }
 
-    public static void updateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
-                                      String gwMacAddress, long label, WriteTransaction writeConfigTxn) {
-
-        LOG.debug("Updating fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
-
-        // Looking for existing prefix in MDSAL database
-        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(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+    /**
+     * Adds or removes nextHop from routePath based on the flag nextHopAdd.
+     */
+    public static void updateRoutePathForFibEntry(DataBroker broker, String rd, String prefix, String nextHop,
+                                      long label, boolean nextHopAdd, WriteTransaction writeConfigTxn) {
 
-        if (entry.isPresent()) {
-            RouteOrigin routeOrigin = RouteOrigin.value(entry.get().getOrigin());
-            // Update the VRF entry with nextHopList
-            VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(entry.get(), label, nextHopList, routeOrigin)
-                    .setGatewayMacAddress(gwMacAddress).build();
+        LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
 
-            if (nextHopList.isEmpty()) {
-                if (writeConfigTxn != null) {
-                    writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
-                } else {
-                    MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
-                }
+        InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
+        if (nextHopAdd) {
+            RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
+            if (writeConfigTxn != null) {
+                writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, routePathId, routePaths,
+                        WriteTransaction.CREATE_MISSING_PARENTS);
             } else {
-                if (writeConfigTxn != null) {
-                    writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
-                } else {
-                    MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
-                }
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
             }
-            LOG.debug("Updated fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
+            LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
         } else {
-            LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
-        }
-    }
-
-    public static void addVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
-        LOG.debug("Adding vrf table for rd {}", rd);
-        InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
-            InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
-        InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
-        VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().setKey(new VrfTablesKey(rd))
-            .setRouteDistinguisher(rd).setVrfEntry(new ArrayList<>());
-        if (writeConfigTxn != null) {
-            writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
-        } else {
-            syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build(),
-                FibUtil.DEFAULT_CALLBACK);
+            Optional<RoutePaths> routePath = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
+            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);
+            } else {
+                MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
+            }
+            LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
         }
-
     }
 
     public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
@@ -617,20 +457,10 @@ public class FibUtil {
         if (writeConfigTxn != null) {
             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
         } else {
-            delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
+            MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
         }
     }
 
-    public static List<String> getNextHopListFromRoutePaths(final VrfEntry vrfEntry) {
-        List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
-        if (routePaths == null || routePaths.isEmpty()) {
-            return Collections.EMPTY_LIST;
-        }
-        return routePaths.stream()
-                .map(routePath -> routePath.getNexthopAddress())
-                .collect(toList());
-    }
-
     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) {
@@ -675,7 +505,7 @@ public class FibUtil {
         .state.Interface getInterfaceStateFromOperDS(DataBroker dataBroker, 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 = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+        Optional<Interface> ifStateOptional = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
         if (ifStateOptional.isPresent()) {
             return ifStateOptional.get();
         }
@@ -687,26 +517,73 @@ public class FibUtil {
         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
     }
 
-    public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
-        return Tunnel.class.equals(adjacencyResult.getInterfaceType());
+    public static String getJobKeyForRdPrefix(String rd, String prefix) {
+        return "FIB-" + rd + "-" + prefix;
     }
 
-    public static Optional<Routes> getLastRoutePathExtraRouteIfPresent(DataBroker dataBroker, Long vpnId,
-            String rd, String prefix) {
-        List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, prefix);
-        String vpnName = getVpnNameFromId(dataBroker, vpnId);
-        if (usedRds == null || usedRds.isEmpty()) {
-            LOG.debug("No used rd found for prefix {} on vpn {}", prefix, vpnName);
-            return Optional.absent();
-        } else if (usedRds.size() > 1) {
-            LOG.debug("The extra route prefix is still present in some DPNs");
-            return Optional.absent();
-        } else {
-            rd = usedRds.get(0);
+    public static String getJobKeyForVpnIdDpnId(Long vpnId, BigInteger dpnId) {
+        return "FIB-" + vpnId.toString() + "-" + dpnId.toString() ;
+    }
+
+    public static void updateUsedRdAndVpnToExtraRoute(WriteTransaction writeOperTxn, DataBroker broker,
+                                                      String tunnelIpRemoved, String primaryRd, String prefix) {
+        Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(broker, primaryRd);
+        if (!optVpnInstance.isPresent()) {
+            return;
+        }
+        VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
+        String vpnName = vpnInstance.getVpnInstanceName();
+        long vpnId = vpnInstance.getVpnId();
+        List<String> usedRds = VpnExtraRouteHelper.getUsedRds(broker, 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(broker, 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(broker, vpnId, getIpPrefix(nextHopRemoved));
+                if (prefixToInterface != null && tunnelIpRemoved
+                        .equals(getEndpointIpAddressForDPN(broker, prefixToInterface.getDpnId()))) {
+                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
+                            getAdjacencyIdentifier(prefixToInterface.getVpnInterfaceName(), prefix));
+                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
+                            VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
+                    writeOperTxn.delete(LogicalDatastoreType.CONFIGURATION,
+                            VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHopRemoved));
+                    break;
+                }
+            }
         }
-        //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
-        return VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
-                getVpnNameFromId(dataBroker, vpnId), rd, prefix);
+    }
+
+    private static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger 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(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
+        if (tunnelInfo.isPresent()) {
+            List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
+            if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
+                nextHopIp = String.valueOf(nexthopIpList.get(0).getIpAddress().getValue());
+            }
+        }
+        return nextHopIp;
+    }
+
+    public static String getIpPrefix(String prefix) {
+        String[] prefixValues = prefix.split(FibConstants.PREFIX_SEPARATOR);
+        if (prefixValues.length == 1) {
+            prefix = prefix + NwConstants.IPV4PREFIX;
+        }
+        return prefix;
+    }
+
+    public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
+        return Tunnel.class.equals(adjacencyResult.getInterfaceType());
     }
 
     public static InstanceIdentifier<VrfEntry> getNextHopIdentifier(String rd, String prefix) {
@@ -716,28 +593,18 @@ public class FibUtil {
 
     public static List<String> getNextHopAddresses(DataBroker broker, String rd, String prefix) {
         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
-        Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        Optional<VrfEntry> vrfEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
         if (vrfEntry.isPresent()) {
-            return getNextHopListFromRoutePaths(vrfEntry.get());
+            return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
         } else {
             return Collections.emptyList();
         }
     }
 
-    public static Optional<String> getGatewayMac(DataBroker dataBroker, String rd, String localNextHopIP) {
-        InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, localNextHopIP);
-        Optional<VrfEntry> vrfEntry = read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
-        if (vrfEntry.isPresent()) {
-            return Optional.fromNullable(vrfEntry.get().getGatewayMacAddress());
-        } else {
-            return Optional.absent();
-        }
-    }
-
     public static Subnetmap getSubnetMap(DataBroker broker, Uuid subnetId) {
         InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier.builder(Subnetmaps.class)
             .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
-        return read(broker, LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
+        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
     }
 
     public static String getGreLbGroupKey(List<String> availableDcGws) {
@@ -805,7 +672,7 @@ public class FibUtil {
     public static Optional<Nexthops> getNexthops(DataBroker dataBroker, String nextHopKey) {
         InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
                 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
-        return read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
+        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
     }
 
     public static Optional<DpnLbNexthops> getDpnLbNexthops(DataBroker dataBroker, BigInteger dpnId,
@@ -813,6 +680,92 @@ public class FibUtil {
         InstanceIdentifier<DpnLbNexthops> id = InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
                 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
                 .build();
-        return read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+    protected static boolean isVxlanNetworkAndInternalRouterVpn(DataBroker dataBroker, Uuid subnetId, String
+            vpnInstanceName, String rd) {
+        if (rd.equals(vpnInstanceName)) {
+            Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
+            if (subnetmap != null) {
+                return subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN;
+            }
+        }
+        return false;
+    }
+
+    protected static java.util.Optional<Long> getVniForVxlanNetwork(DataBroker dataBroker, Uuid subnetId) {
+        Subnetmap subnetmap = getSubnetMap(dataBroker, subnetId);
+        if (subnetmap != null && subnetmap.getNetworkType() == NetworkAttributes.NetworkType.VXLAN) {
+            return java.util.Optional.of(subnetmap.getSegmentationId());
+        }
+        return java.util.Optional.empty();
+    }
+
+    protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
+                                                                               long vpnId, String rd) {
+        return (isOpenStackVniSemanticsEnforced
+                && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, getVpnNameFromId(dataBroker, vpnId), rd));
+    }
+
+    protected static boolean enforceVxlanDatapathSemanticsforInternalRouterVpn(DataBroker dataBroker, Uuid subnetId,
+                                                                               String vpnName, String rd) {
+        return (isOpenStackVniSemanticsEnforced
+                && isVxlanNetworkAndInternalRouterVpn(dataBroker, subnetId, vpnName, rd));
+    }
+
+    static NodeRef buildNodeRef(BigInteger 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) {
+        InstanceIdentifier<Group> groupInstanceId = 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();
+        return groupInstanceId;
+    }
+
+    static Buckets buildBuckets(List<BucketInfo> listBucketInfo) {
+        long index = 0;
+        BucketsBuilder bucketsBuilder = new BucketsBuilder();
+        if (listBucketInfo != null) {
+            List<Bucket> bucketList = new ArrayList<>();
+
+            for (BucketInfo bucketInfo : listBucketInfo) {
+                BucketBuilder bucketBuilder = new BucketBuilder();
+                bucketBuilder.setAction(bucketInfo.buildActions());
+                bucketBuilder.setWeight(bucketInfo.getWeight());
+                bucketBuilder.setBucketId(new BucketId(index++));
+                bucketBuilder.setWeight(bucketInfo.getWeight()).setWatchPort(bucketInfo.getWatchPort())
+                        .setWatchGroup(bucketInfo.getWatchGroup());
+                bucketList.add(bucketBuilder.build());
+            }
+
+            bucketsBuilder.setBucket(bucketList);
+        }
+        return bucketsBuilder.build();
+    }
+
+    static String getFlowRef(BigInteger dpnId, short tableId, long 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) {
+        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) {
+        return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
+                + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
+    }
+
+    static Node buildDpnNode(BigInteger dpnId) {
+        NodeId nodeId = new NodeId("openflow:" + dpnId);
+        Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
+
+        return nodeDpn;
     }
 }