Bug 7034 : Replace all write_actions by apply_actions.
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / VrfEntryListener.java
index 1c41c1bdaa945ee179a360f153e878dfae86db08..7227c6364458ee4377327b38848075a1b489882b 100644 (file)
@@ -9,10 +9,10 @@ package org.opendaylight.netvirt.fibmanager;
 
 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 com.google.common.util.concurrent.ListenableFuture;
+
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -25,15 +25,13 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
+
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 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.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
-import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.ActionType;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
@@ -45,14 +43,20 @@ import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.batching.ActionableResource;
 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
 import org.opendaylight.genius.utils.batching.ResourceHandler;
+import org.opendaylight.genius.utils.batching.SubTransaction;
+import org.opendaylight.genius.utils.batching.SubTransactionImpl;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
+import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
@@ -75,6 +79,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.N
 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.LabelRouteMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
 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.VrfTablesKey;
@@ -106,9 +111,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
 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.InterVpnLinkState.State;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
@@ -116,34 +121,34 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable, ResourceHandler {
+public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener> implements AutoCloseable, ResourceHandler {
     private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
     private static final String FLOWID_PREFIX = "L3.";
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker dataBroker;
     private final IMdsalApiManager mdsalManager;
     private IVpnManager vpnmanager;
-    private NexthopManager nextHopManager;
+    private final NexthopManager nextHopManager;
     private ItmRpcService itmManager;
-    private OdlInterfaceRpcService interfaceManager;
-    private IdManagerService idManager;
+    private final OdlInterfaceRpcService interfaceManager;
+    private final IdManagerService idManager;
     private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
     private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
     private static final int LFIB_INTERVPN_PRIORITY = 1;
     private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
     private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
     public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+    List<SubTransaction> transactionObjects;
     private static final int PERIODICITY = 500;
     private static Integer batchSize;
     private static Integer batchInterval;
     private static final int BATCH_SIZE = 1000;
     private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
-    private ResourceBatchingManager resourceBatchingManager;
+    private final ResourceBatchingManager resourceBatchingManager;
 
     public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
                             final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
                             final IdManagerService idManager) {
-        super(VrfEntry.class);
+        super(VrfEntry.class, VrfEntryListener.class);
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalApiManager;
         this.nextHopManager = nexthopManager;
@@ -159,25 +164,20 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         }
         resourceBatchingManager = ResourceBatchingManager.getInstance();
         resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY",vrfEntryBufferQ, this);
+        transactionObjects = new ArrayList<>();
     }
 
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
-        listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                getWildCardPath(), this, DataChangeScope.SUBTREE);
+        registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
     }
 
-    private InstanceIdentifier<VrfEntry> getWildCardPath() {
-        return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
-    }
+    @Override
+    protected VrfEntryListener getDataTreeChangeListener() { return VrfEntryListener.this; }
 
     @Override
-    public void close() throws Exception {
-        if (listenerRegistration != null) {
-            listenerRegistration.close();
-            listenerRegistration = null;
-        }
-        LOG.info("{} close", getClass().getSimpleName());
+    protected InstanceIdentifier<VrfEntry> getWildCardPath() {
+        return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
     }
 
     @Override
@@ -246,14 +246,16 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
     }
 
     @Override
-    public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
+    public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
+        this.transactionObjects = transactionObjects;
         if (vrfEntry instanceof VrfEntry) {
             createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
         }
     }
 
     @Override
-    public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
+    public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
+        this.transactionObjects = transactionObjects;
         if (vrfEntry instanceof VrfEntry) {
             deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
         }
@@ -261,7 +263,8 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
     @Override
     public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
-                       Object update) {
+                       Object update, List<SubTransaction> transactionObjects) {
+        this.transactionObjects = transactionObjects;
         if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
             createFibEntries(tx, identifier, (VrfEntry)update);
         }
@@ -317,6 +320,10 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
             }
             return;
         }
+        // ping responder for router interfaces
+        if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
+            return;
+        }
 
         if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
             // When it is a leaked route, the LFIB and FIB goes a bit different.
@@ -349,14 +356,17 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
         Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
         if ( optVpnUuid.isPresent() ) {
-            Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, optVpnUuid.get());
-            if ( interVpnLink.isPresent() ) {
+            Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
+            LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
+            if ( optInterVpnLink.isPresent() ) {
+                InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
                 String vpnUuid = optVpnUuid.get();
                 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
-                if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid, interVpnLink.get()) ) {
+                if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid) ) {
                     // This is an static route that points to the other endpoint of an InterVpnLink
                     // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
-                    installRouteInInterVpnLink(interVpnLink.get(), vpnUuid, vrfEntry, vpnId);
+                    installRouteInInterVpnLink(interVpnLink, vpnUuid, vrfEntry, vpnId);
+                    installInterVpnRouteInLFib(rd, vrfEntry);
                 }
             }
         }
@@ -386,20 +396,6 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         }
     }
 
-    /*
-     * Returns true if the specified nexthop is the other endpoint in an
-     * InterVpnLink, regarding one of the VPN's point of view.
-     */
-    private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
-        return
-                interVpnLink != null
-                        && (   (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
-                        && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
-                        || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
-                        && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
-    }
-
-
     // FIXME: Refactoring needed here.
     //        This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
     private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
@@ -416,7 +412,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
             }
         } else {
             Preconditions.checkNotNull(vpnInstance,
-                    "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
+                                       "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
         }
         String vpnUuid = vpnInstance.getVpnInstanceName();
         Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
@@ -428,8 +424,8 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
         // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
         Optional<InterVpnLink> interVpnLink =
-                (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
-                        : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
+            (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
+                                                  : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
         if ( !interVpnLink.isPresent() ) {
             LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
             return;
@@ -437,12 +433,12 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
         // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
         // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
-        boolean proceed = (addOrRemove == NwConstants.DEL_FLOW )
-                || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
-                && interVpnLink.get().isBgpRoutesLeaking() );
+        boolean proceed =
+            (addOrRemove == NwConstants.DEL_FLOW) || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
+                                                       && interVpnLink.get().isBgpRoutesLeaking() );
 
         if ( proceed ) {
-            String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) )
+            String theOtherVpnId = interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
                     ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
                     : vpnUuid;
 
@@ -570,12 +566,10 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                     return;
                 }
 
-                List<BigInteger> targetDpns =
-                        ( vpnIs1stEndpoint ) ? vpnLinkState.get().getFirstEndpointState().getDpId()
-                                : vpnLinkState.get().getSecondEndpointState().getDpId();
-                Long lportTag =
-                        ( vpnIs1stEndpoint ) ? vpnLinkState.get().getSecondEndpointState().getLportTag()
-                                : vpnLinkState.get().getFirstEndpointState().getLportTag();
+                List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
+                                                               : vpnLinkState.get().getSecondEndpointState().getDpId();
+                Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
+                                                 : vpnLinkState.get().getFirstEndpointState().getLportTag();
 
                 for ( BigInteger dpId : targetDpns ) {
                     List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
@@ -606,110 +600,98 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
 
 
-    private void installRouteInInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
+    private void installRouteInInterVpnLink(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
                                             final VrfEntry vrfEntry, long vpnTag) {
         Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
         Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
                 && vrfEntry.getNextHopAddressList().size() == 1);
         String destination = vrfEntry.getDestPrefix();
         String nextHop = vrfEntry.getNextHopAddressList().get(0);
+        String iVpnLinkName = interVpnLink.getInterVpnLinkName();
 
         // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
         // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
         // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
-        Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
-        if ( !interVpnLinkState.isPresent() ) {
-            LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
-            return;
-        }
-        if ( ! interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
+        if ( interVpnLink.getState().or(State.Error) != State.Active ) {
             LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
-                    destination, nextHop, interVpnLink.getName());
+                    destination, nextHop, iVpnLinkName);
             return;
         }
 
+        Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
+        if ( !optOtherEndpointLportTag.isPresent() ) {
+            LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
+                     vpnUuid, iVpnLinkName);
+            return;
+        }
 
-        // Everything Ok
-        boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
-        List<BigInteger> targetDpns =
-                vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
-                        : interVpnLinkState.get().getSecondEndpointState().getDpId();
-
-        Long otherEndpointlportTag =
-                vpnIsFirstEndpoint ? interVpnLinkState.get().getSecondEndpointState().getLportTag()
-                        : interVpnLinkState.get().getFirstEndpointState().getLportTag();
+        List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
+        if ( targetDpns.isEmpty() ) {
+            LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}", vpnUuid, iVpnLinkName);
+            return;
+        }
 
         BigInteger[] metadata = new BigInteger[] {
-                MetaDataUtil.getMetaDataForLPortDispatcher(otherEndpointlportTag.intValue(),
+                MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
                         ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
                 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
         };
-        int instIdx = 0;
         List<Instruction> instructions =
                 Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0),
-                        new InstructionInfo(InstructionType.goto_table,
-                                new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
+                              new InstructionInfo(InstructionType.goto_table,
+                                                  new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
 
         String values[] = destination.split("/");
         String destPrefixIpAddress = values[0];
         int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
 
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.metadata,
-                new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
-                        MetaDataUtil.METADATA_MASK_VRFID }));
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
+                                                                              MetaDataUtil.METADATA_MASK_VRFID }));
         matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
 
         if (prefixLength != 0) {
             matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
-                    new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
+                                      new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
         }
 
         int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
-        String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), destination, nextHop);
+        String flowRef = getInterVpnFibFlowRef(iVpnLinkName, destination, nextHop);
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
-                COOKIE_VM_FIB_TABLE, matches, instructions);
+                                                 COOKIE_VM_FIB_TABLE, matches, instructions);
 
         for ( BigInteger dpId : targetDpns ) {
             mdsalManager.installFlow(dpId, flowEntity);
         }
     }
 
-    private void removeRouteFromInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
+    private void removeRouteFromInterVpnLink(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
                                              final VrfEntry vrfEntry) {
 
         Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
         Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
-                && vrfEntry.getNextHopAddressList().size() == 1);
+                                    && vrfEntry.getNextHopAddressList().size() == 1);
+
+        String iVpnLinkName = interVpnLink.getInterVpnLinkName();
 
-        Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
-        if ( !interVpnLinkState.isPresent() ) {
-            LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
+        InterVpnLinkState interVpnLinkState = interVpnLink.getInterVpnLinkState();
+        if ( interVpnLinkState == null ) {
+            LOG.warn("Could not find State for InterVpnLink {}", iVpnLinkName);
             return;
         }
 
-        // Everything Ok
-        boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
-        List<BigInteger> targetDpns =
-                vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
-                        : interVpnLinkState.get().getSecondEndpointState().getDpId();
-
         String nextHop = vrfEntry.getNextHopAddressList().get(0);
-        String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop);
-        FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-        Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
-                .setFlowName(flowRef).build();
+        String flowRef = getInterVpnFibFlowRef(iVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
+        FlowId flowId = new FlowId(flowRef);
+        Flow flow = new FlowBuilder().setKey(new FlowKey(flowId)).setId(flowId).setTableId(NwConstants.L3_FIB_TABLE)
+                                     .setFlowName(flowRef).build();
 
-        for ( BigInteger dpId : targetDpns ) {
+        for ( BigInteger dpId : interVpnLink.getEndpointDpnsByVpnName(vpnUuid) ) {
             mdsalManager.removeFlow(dpId, flow);
         }
 
     }
 
-    private boolean isVpnFirstEndPoint(InterVpnLink interVpnLink, String vpnName) {
-        return interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
-    }
-
     private  <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
                                                      InstanceIdentifier<T> path) {
 
@@ -725,26 +707,8 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         return result;
     }
 
-    private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
-        final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
-        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
-        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
-                NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
-
-        if (addOrRemove == NwConstants.ADD_FLOW) {
-            mdsalManager.installFlow(flowEntity);
-        } else {
-            mdsalManager.removeFlow(flowEntity);
-        }
-    }
-
     private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
-        List<BigInteger> returnLocalDpnId = new ArrayList<BigInteger>();
+        List<BigInteger> returnLocalDpnId = new ArrayList<>();
         Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
         String localNextHopIP = vrfEntry.getDestPrefix();
 
@@ -803,18 +767,24 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         if (localNextHopInfo != null) {
             final BigInteger dpnId = localNextHopInfo.getDpnId();
             if (!isVpnPresentInDpn(rd, dpnId)) {
+                LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
                 return BigInteger.ZERO;
             }
 
-            final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
-
+            final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
+                    localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix());
+            if (groupId == 0) {
+                LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
+                        vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
+                return BigInteger.ZERO;
+            }
             List<ActionInfo> actionsInfos =
                     Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
             final List<InstructionInfo> instructions =
-                    Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+                    Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
             actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
                     new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
-            final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+            final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
             if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
                 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
                         dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
@@ -868,7 +838,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         if (lri == null) {
             return true;
         }
-        List<String> vpnInstancesList = lri.getVpnInstanceList();
+        List<String> vpnInstancesList = lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList<String>();
         if (vpnInstancesList.contains(vpnInstanceName)) {
             LOG.debug("vpninstance {} name is present", vpnInstanceName);
             vpnInstancesList.remove(vpnInstanceName);
@@ -908,7 +878,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
 
         List<InstructionInfo> mkInstructions = new ArrayList<>();
-        mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
 
         FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
                 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
@@ -1027,7 +997,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                         }
                     });
             //TODO: verify below adjacency call need to be optimized (?)
-            deleteLocalAdjacency(dpnId, vpnId, localNextHopIP);
+            deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
             return dpnId;
         }
         return BigInteger.ZERO;
@@ -1070,7 +1040,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
             }
 
         } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
+            LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
         }
 
         return null;
@@ -1124,7 +1094,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                 return;
             }
             actionInfos.addAll(egressActions);
-            instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
+            instructions.add(new InstructionInfo(InstructionType.apply_actions, actionInfos));
             makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
         }
         if(!wrTxPresent ){
@@ -1232,6 +1202,28 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         public List<ListenableFuture<Void>> call() throws Exception {
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
+
+            //First Cleanup LabelRouteInfo
+            synchronized (vrfEntry.getLabel().toString().intern()) {
+                LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
+                if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
+                                vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
+                    Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
+                    String vpnInstanceName = "";
+                    if (vpnInstanceOpDataEntryOptional.isPresent()) {
+                            vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
+                        }
+                    boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
+                    if (lriRemoved) {
+                            String parentRd = lri.getParentVpnRd();
+                            FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+                                            FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
+                        }
+                } else {
+                    FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+                                    FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
+                }
+            }
             String ifName = prefixInfo.getVpnInterfaceName();
             Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     FibUtil.getVpnInterfaceIdentifier(ifName));
@@ -1240,9 +1232,6 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                 if (vpnId != associatedVpnId) {
                     LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
                             vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
-                    LOG.trace("Releasing prefix label - rd {}, prefix {}", rd, vrfEntry.getDestPrefix());
-                    FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
-                            FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
                     LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
                     return null;
                 } else {
@@ -1272,27 +1261,6 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
                         FibUtil.getVpnInterfaceIdentifier(ifName));
             }
-
-            synchronized (vrfEntry.getLabel().toString().intern()) {
-                LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
-                if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
-                        vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
-                    Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
-                    String vpnInstanceName = "";
-                    if (vpnInstanceOpDataEntryOptional.isPresent()) {
-                        vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
-                    }
-                    boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
-                    if (lriRemoved) {
-                        String parentRd = lri.getParentVpnRd();
-                        FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
-                                FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
-                    }
-                } else {
-                    FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
-                            FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
-                }
-            }
             return null;
         }
     }
@@ -1360,6 +1328,9 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
             }
             return;
         }
+        if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
+            return;
+        }
 
         final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
                 vrfTableKey.getRouteDistinguisher(), vrfEntry);
@@ -1409,19 +1380,24 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
 
         // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
         // of the interVpnLink.
-        Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
-        if ( vpnUuid.isPresent() ) {
-            Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, vpnUuid.get());
-            String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
-
-            if ( interVpnLink.isPresent()
-                    && ( (interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid.get())
-                    && interVpnLink.get().getSecondEndpoint().getIpAddress().getValue().equals(routeNexthop))
-                    || (interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid.get() )
-                    && interVpnLink.get().getFirstEndpoint().getIpAddress().getValue().equals(routeNexthop)) ) ) {
-                // This is route that points to the other endpoint of an InterVpnLink
-                // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
-                removeRouteFromInterVpnLink(interVpnLink.get(), rd, vrfEntry);
+        Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
+        if ( optVpnUuid.isPresent() ) {
+            String vpnUuid = optVpnUuid.get();
+            List<String> routeNexthoplist = vrfEntry.getNextHopAddressList();
+            if(routeNexthoplist.isEmpty()) {
+                LOG.trace("NextHopList is empty for VrfEntry {}", vrfEntry);
+                return;
+            }
+            String routeNexthop = routeNexthoplist.get(0);
+            Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
+            if ( optInterVpnLink.isPresent() ) {
+                InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
+                if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid))
+                {
+                    // This is route that points to the other endpoint of an InterVpnLink
+                    // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
+                    removeRouteFromInterVpnLink(interVpnLink, rd, vrfEntry);
+                }
             }
         }
 
@@ -1492,7 +1468,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                                            VrfEntry vrfEntry, String rd, WriteTransaction tx){
         boolean isRemoteRoute = true;
         if (localNextHopInfo != null) {
-            isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
+            isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
         }
         if (isRemoteRoute) {
             deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
@@ -1564,6 +1540,20 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
+
+        if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
+            SubTransaction subTransaction = new SubTransactionImpl();
+            if (addOrRemove == NwConstants.ADD_FLOW) {
+                subTransaction.setInstanceIdentifier(flowInstanceId);
+                subTransaction.setInstance(flow);
+                subTransaction.setAction(SubTransaction.CREATE);
+            } else {
+                subTransaction.setInstanceIdentifier(flowInstanceId);
+                subTransaction.setAction(SubTransaction.DELETE);
+            }
+            transactionObjects.add(subTransaction);
+        }
+
         if (addOrRemove == NwConstants.ADD_FLOW) {
             tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
         } else {
@@ -1622,10 +1612,11 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                 dpId, label, instructions );
     }
 
-    private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
+    private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
+                                      final String ipPrefixAddress) {
         LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
         try {
-            nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
+            nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
         } catch (NullPointerException e) {
             LOG.trace("", e);
         }
@@ -1661,6 +1652,14 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                             installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
                             continue;
                         }
+                        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+                        if (routerInt != null) {
+                            LOG.trace( "Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
+                                    rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
+                            installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
+                                    new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
+                            continue;
+                        }
                         if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { //Handle local flow creation for imports
                             LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
                             if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
@@ -1794,8 +1793,9 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
                         VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
                         VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
-                        if (vrfEntry == null)
+                        if (vrfEntry == null) {
                             return futures;
+                        }
                         LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
                                         "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
                                 action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
@@ -1841,6 +1841,15 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                                                 vrfEntry.getDestPrefix());
                                         continue;
                                     }
+                                    // ping responder for router interfaces
+                                    RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+                                    if (routerInt != null) {
+                                        LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
+                                                rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
+                                        installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
+                                                new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
+                                        continue;
+                                    }
                                     // Passing null as we don't know the dpn
                                     // to which prefix is attached at this point
                                     deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
@@ -1996,55 +2005,6 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
     }
 
-    public void processNodeAdd(BigInteger dpnId) {
-        LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
-        makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
-        makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
-        makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
-        createTableMissForVpnGwFlow(dpnId);
-    }
-
-    private void createTableMissForVpnGwFlow(BigInteger dpnId) {
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
-        FlowEntity flowEntityMissforGw = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_GW_MAC_TABLE,
-                getTableMissFlowRef(dpnId, NwConstants.L3_GW_MAC_TABLE, NwConstants.TABLE_MISS_FLOW),
-                NwConstants.TABLE_MISS_PRIORITY, "L3 Gw Mac Table Miss", 0, 0, new BigInteger("1080000", 16), matches, instructions);
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Invoking MDSAL to install L3 Gw Mac Table Miss Entry");
-        }
-        mdsalManager.installFlow(flowEntityMissforGw);
-   }
-
-    private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
-        final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
-        // Instruction to goto L3 InterfaceTable
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
-                getTableMissFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
-                NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
-
-        FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE,
-                getTableMissFlowRef(dpnId, NwConstants.L3_FIB_TABLE,
-                        NwConstants.TABLE_MISS_FLOW),
-                NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow",
-                0, 0, COOKIE_VM_FIB_TABLE,
-                matches, instructions);
-
-        if (addOrRemove == NwConstants.ADD_FLOW) {
-            LOG.debug("Invoking MDSAL to install Table Miss Entries");
-            mdsalManager.installFlow(flowEntityLfib);
-            mdsalManager.installFlow(flowEntityFib);
-        } else {
-            mdsalManager.removeFlow(flowEntityLfib);
-            mdsalManager.removeFlow(flowEntityFib);
-
-        }
-    }
-
     private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
         return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
@@ -2081,7 +2041,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
     }
 
     public List<String> printFibEntries() {
-        List<String> result = new ArrayList<String>();
+        List<String> result = new ArrayList<>();
         result.add(String.format("   %-7s  %-20s  %-20s  %-7s  %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
         result.add("-------------------------------------------------------------------");
         InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
@@ -2106,29 +2066,6 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
         return result;
     }
 
-    private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
-        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
-        List<MatchInfo> matches = new ArrayList<MatchInfo>();
-        final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
-        // Instruction to goto L3 InterfaceTable
-
-        List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
-        actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
-                Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
-        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
-        //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
-
-        FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
-                getTableMissFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
-                NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS,
-                matches, instructions);
-        if (addOrRemove == NwConstants.ADD_FLOW) {
-            LOG.debug("Invoking MDSAL to install L3 interface Table Miss Entries");
-            mdsalManager.installFlow(flowEntityL3Intf);
-        } else {
-            mdsalManager.removeFlow(flowEntityL3Intf);
-        }
-    }
 
     private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
         InstanceIdentifier<VrfEntry> vrfEntryId =
@@ -2136,7 +2073,7 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                         child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
         Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
         if (vrfEntry.isPresent())  {
-            return (vrfEntry.get());
+            return vrfEntry.get();
         }
         return null;
     }
@@ -2147,4 +2084,76 @@ public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> imple
                         child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
         return vrfEntryId;
     }
+
+    protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
+            long vpnId, int addOrRemove) {
+        RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
+        if (routerInt != null && vpnToDpnList != null) {
+            String routerId = routerInt.getUuid();
+            String macAddress = routerInt.getMacAddress();
+            String ipValue = routerInt.getIpAddress();
+            LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
+                    routerId, ipValue, macAddress);
+            for (VpnToDpnList vpnDpn : vpnToDpnList) {
+                if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+                    installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
+                            new MacAddress(macAddress), addOrRemove);
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
+                                      String routerInternalIp, MacAddress routerMac, int addOrRemove) {
+        String[] subSplit = routerInternalIp.split("/");
+
+        String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
+        LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
+                dpnId, routerInternalIp, vpnId, subSplit[0]);
+
+        List<MatchInfo> matches = new ArrayList<>();
+
+        matches.add(new MatchInfo(MatchFieldType.ip_proto, new long[] { IPProtocols.ICMP.intValue() }));
+        matches.add(new MatchInfo(MatchFieldType.metadata,
+                new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+        matches.add(new MatchInfo(MatchFieldType.icmp_v4, new long[] { (short) 8, (short) 0 }));
+        matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
+        matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { subSplit[0], "32" }));
+
+        List<ActionInfo> actionsInfos = new ArrayList<>();
+
+        // Set Eth Src and Eth Dst
+        actionsInfos.add(new ActionInfo(ActionType.move_src_dst_eth, new String[] {}));
+        actionsInfos.add(new ActionInfo(ActionType.set_field_eth_src, new String[] { routerMac.getValue() }));
+
+        // Move Ip Src to Ip Dst
+        actionsInfos.add(new ActionInfo(ActionType.move_src_dst_ip, new String[] {}));
+        actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[] { subSplit[0], "32" }));
+
+        // Set the ICMP type to 0 (echo reply)
+        actionsInfos.add(new ActionInfo(ActionType.set_icmp_type, new String[] { "0" }));
+
+        actionsInfos.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{ BigInteger.ZERO }));
+
+        actionsInfos.add(new ActionInfo(ActionType.nx_resubmit,
+                new String[] { Short.toString(NwConstants.L3_FIB_TABLE) }));
+
+        List<InstructionInfo> instructions = new ArrayList<>();
+
+        instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+
+        int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
+        String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vrfEntry.getLabel(), priority);
+
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
+                0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
+
+        if (addOrRemove == NwConstants.ADD_FLOW) {
+            mdsalManager.installFlow(flowEntity);
+        } else {
+            mdsalManager.removeFlow(flowEntity);
+        }
+    }
 }