FibManager module sync up 56/41956/5
authorSuraj Ranjan <suraj.ranjan@ericsson.com>
Mon, 18 Jul 2016 09:36:58 +0000 (15:06 +0530)
committerSuraj Ranjan <suraj.ranjan@ericsson.com>
Tue, 19 Jul 2016 14:25:24 +0000 (19:55 +0530)
Change-Id: I6e5be84e484de2277ea43e2c065ebd9ca31fab92
Signed-off-by: Suraj Ranjan <suraj.ranjan@ericsson.com>
18 files changed:
vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java
vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang
vpnservice/fibmanager/fibmanager-api/src/main/yang/odl-fib.yang
vpnservice/fibmanager/fibmanager-impl/pom.xml
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibConstants.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManager.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerProvider.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibUtil.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/L3VPNTransportTypes.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/NexthopManager.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/fibmanager/impl/rev150325/FibmanagerImplModule.java
vpnservice/fibmanager/fibmanager-impl/src/test/java/org/opendaylight/netvirt/fibmanager/test/FibManagerTest.java
vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/ShowTransportTypeCommand.java
vpnservice/fibmanager/fibmanager-shell/src/main/java/org/opendaylight/netvirt/fibmanager/shell/confTransportL3VPNCommand.java
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang [new file with mode: 0644]
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java

index 1b9faa49051979c8896573f7ae2e2b34af1bf57c..4bca84fbca9830dde73618f4beccfc63d95149f9 100644 (file)
@@ -13,13 +13,20 @@ import java.util.List;
 
 public interface IFibManager {
     void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd);
+    void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nextHopIp);
+    void populateFibOnDpn(BigInteger localDpnId, BigInteger destDpnId, long vpnId, String rd, String nextHopIp);
     void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd);
     List<String> printFibEntries();
+
+    // TODO Feels like this method is not used anywhere
     void addStaticRoute(String prefix, String nextHop, String rd, int label);
-    void deleteStaticRoute(String prefix, String rd);
+    void deleteStaticRoute(String prefix, String nextHop, String rd);
     void setConfTransType(String service, String transportType);
     String getConfTransType();
     boolean isVPNConfigured();
     void writeConfTransTypeConfigDS();
     String getReqTransType();
+    String getTransportTypeStr(String tunType);
+    void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId,
+                           long vpnId, String rd, String destPrefix, String nextHopIp);
 }
index e6448e3d3707b336eac38c033c0be6380b062f78..8ebe0b2ed9dc9bbf079ca83fca90bb87f65b39ad 100644 (file)
@@ -54,4 +54,35 @@ module fib-rpc {
             }\r
         }\r
     }\r
-}
+\r
+    rpc populate-fib-on-dpn {\r
+        description "Populates FIB table in specified DPN";\r
+        input {\r
+            leaf dpid {\r
+                type uint64;\r
+            }\r
+            leaf vpn-id {\r
+                type uint32;\r
+            }\r
+            leaf rd {\r
+                type string;\r
+            }\r
+        }\r
+    }\r
+\r
+    rpc cleanup-dpn-for-vpn {\r
+        description "Removes the VPN Fib entries in a given DPN";\r
+        input {\r
+            leaf dpid {\r
+                type uint64;\r
+            }\r
+            leaf vpn-id {\r
+                type uint32;\r
+            }\r
+            leaf rd {\r
+                type string;\r
+            }\r
+\r
+        }\r
+    }\r
+}\r
index 7e5213a77b6ce59b7992de7695fce7adaa885952..10d70f84cccdaed241d29a213b12c93b3ce0d652 100644 (file)
@@ -27,8 +27,13 @@ module odl-fib {
                 type uint32;
                 mandatory true;
             }
-            leaf nextHopAddress {
+            leaf-list nextHopAddressList {
                 type string;
+                min-elements "1";
+            }
+            leaf origin {
+                type string;
+                mandatory true;
             }
         }
     }
index af77917cb7ebe5917dbd3883cbde3a79b5f9c161..3cc15c55cf14b8d39b730883371a0b29435c990f 100644 (file)
@@ -26,6 +26,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>fibmanager-api</artifactId>
       <version>${vpnservices.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netvirt</groupId>
+      <artifactId>bgpmanager-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.genius</groupId>
       <artifactId>mdsalutil-api</artifactId>
index 65b21c3bd9c9a469940f17f806ff0f0112ca2037..5d837d98b9342a5ff2593209aabe5e792f56cbb0 100644 (file)
@@ -17,4 +17,5 @@ public class FibConstants {
     static final String FLOWID_PREFIX = "L3.";
     static final String VPN_IDPOOL_NAME = "vpnservices";
     static final String SEPARATOR = ".";
+    public static final short L3VPN_SERVICE_IDENTIFIER = 2; // TODO : This should be in just on place
 }
index 096924c76d2705f030a68b147f28f9e060d77d23..61db4a4be96c61f634d2726c36e6b2d588ba04ce 100644 (file)
@@ -13,18 +13,24 @@ import com.google.common.base.Preconditions;
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
+import com.google.common.util.concurrent.ListenableFuture;
 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.genius.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
@@ -39,7 +45,22 @@ import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.SubnetRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
@@ -50,6 +71,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.pre
 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.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
+        .links.InterVpnLink;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
@@ -78,334 +105,724 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
-  private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
-  private static final String FLOWID_PREFIX = "L3.";
-  private ListenerRegistration<DataChangeListener> listenerRegistration;
-  private final DataBroker broker;
-  private IMdsalApiManager mdsalManager;
-  private IVpnManager vpnmanager;
-  private NexthopManager nextHopManager;
-  private ItmRpcService itmManager;
-  private OdlInterfaceRpcService interfaceManager;
-  private IdManagerService idManager;
-  private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
-  private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
-  private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
-  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);
-
-
-  public FibManager(final DataBroker db) {
-    super(VrfEntry.class);
-    broker = db;
-    registerListener(db);
-  }
-
-  @Override
-  public void close() throws Exception {
-    if (listenerRegistration != null) {
-      try {
-        listenerRegistration.close();
-      } catch (final Exception e) {
-        LOG.error("Error when cleaning up DataChangeListener.", e);
-      }
-      listenerRegistration = null;
-    }
-    LOG.info("Fib Manager Closed");
-  }
-
-  public void setNextHopManager(NexthopManager nextHopManager) {
-    this.nextHopManager = nextHopManager;
-  }
+    private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
+    private static final String FLOWID_PREFIX = "L3.";
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+    private final DataBroker broker;
+    private IMdsalApiManager mdsalManager;
+    private IVpnManager vpnmanager;
+    private NexthopManager nextHopManager;
+    private ItmRpcService itmManager;
+
+    private OdlInterfaceRpcService interfaceManager;
+    private IdManagerService idManager;
+    private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
+    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);
+
+
+    public FibManager(final DataBroker db) {
+        super(VrfEntry.class);
+        broker = db;
+        registerListener(db);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (final Exception e) {
+                LOG.error("Error when cleaning up DataChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+        LOG.info("Fib Manager Closed");
+    }
 
+    public void setNextHopManager(NexthopManager nextHopManager) {
+        this.nextHopManager = nextHopManager;
+    }
     public NexthopManager getNextHopManager() {
         return this.nextHopManager;
     }
 
-  public void setMdsalManager(IMdsalApiManager mdsalManager) {
-    this.mdsalManager = mdsalManager;
-  }
-
-  public void setVpnmanager(IVpnManager vpnmanager) {
-    this.vpnmanager = vpnmanager;
-  }
-
-  public void setITMRpcService(ItmRpcService itmManager) {
-      this.itmManager = itmManager;
-  }
-  
-  public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
-      this.interfaceManager = ifManager;
-  }
-
-  public void setIdManager(IdManagerService idManager) {
-      this.idManager = idManager;
-  }
-
-  private void registerListener(final DataBroker db) {
-    try {
-      listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                                                           getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
-    } catch (final Exception e) {
-      LOG.error("FibManager DataChange listener registration fail!", e);
-      throw new IllegalStateException("FibManager registration Listener failed.", e);
-    }
-  }
-
-
-  private InstanceIdentifier<VrfEntry> getWildCardPath() {
-    return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
-  }
-
-
-  @Override
-  protected void add(final InstanceIdentifier<VrfEntry> identifier,
-                     final VrfEntry vrfEntry) {
-    LOG.trace("Add key: " + identifier + ", value=" + vrfEntry );
-    createFibEntries(identifier, vrfEntry);
-  }
-
-  @Override
-  protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
-    LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry);
-    deleteFibEntries(identifier, vrfEntry);
-  }
-
-  @Override
-  protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
-    LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update );
-    if (original.getAugmentation(SubnetRoute.class) != null && update.getAugmentation(SubnetRoute.class) == null)
-        return;
-    createFibEntries(identifier, update);
-  }
-
-  private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
-                                final VrfEntry vrfEntry) {
-    final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
-    Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
-    Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
-
-    VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
-    Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
-    Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
-
-    Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
-    Long vpnId = vpnInstance.getVpnId();
-    String rd = vrfTableKey.getRouteDistinguisher();
-    SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-    if (subnetRoute != null) {
-        LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
-                rd, vrfEntry.getDestPrefix(), subnetRoute.getElantag());
-        long elanTag = subnetRoute.getElantag();
+    public void setMdsalManager(IMdsalApiManager mdsalManager) {
+        this.mdsalManager = mdsalManager;
+    }
+
+    public void setVpnmanager(IVpnManager vpnmanager) {
+        this.vpnmanager = vpnmanager;
+    }
+
+    public void setITMRpcService(ItmRpcService itmManager) {
+        this.itmManager = itmManager;
+    }
+
+    public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
+        this.interfaceManager = ifManager;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    private void registerListener(final DataBroker db) {
+        try {
+            listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                    getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
+        } catch (final Exception e) {
+            LOG.error("FibManager DataChange listener registration fail!", e);
+            throw new IllegalStateException("FibManager registration Listener failed.", e);
+        }
+    }
+
+
+    private InstanceIdentifier<VrfEntry> getWildCardPath() {
+        return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
+    }
+
+
+    @Override
+    protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
+        Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
+        String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
+        LOG.info("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
+                rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
+        createFibEntries(identifier, vrfEntry);
+        LOG.info("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
+                rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
+        leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
+        Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
+        String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
+        LOG.info("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
+                rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
+        deleteFibEntries(identifier, vrfEntry);
+        LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
+                rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
+        leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
+        Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
+        if (original.getAugmentation(SubnetRoute.class) != null && update.getAugmentation(SubnetRoute.class) == null)
+            return;
+        String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
+        LOG.info("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
+                rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
+        createFibEntries(identifier, update);
+        LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
+                rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
+    }
+
+    private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
+        final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
+
+        final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
+        Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
+        Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
+
+        final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+        final Long vpnId = vpnInstance.getVpnId();
+        final String rd = vrfTableKey.getRouteDistinguisher();
+        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+        if (subnetRoute != null) {
+            final long elanTag = subnetRoute.getElantag();
+            LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
+                    rd, vrfEntry.getDestPrefix(), elanTag);
+            if (vpnToDpnList != null) {
+                DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() throws Exception {
+                                WriteTransaction tx = broker.newWriteOnlyTransaction();
+                                for (final VpnToDpnList curDpn : vpnToDpnList) {
+                                    installSubnetRouteInFib(curDpn.getDpnId(),elanTag, rd, vpnId.longValue(), vrfEntry, tx);
+                                }
+                                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                                futures.add(tx.submit());
+                                return futures;
+                            }
+                        });
+            }
+            return;
+        }
+
+        if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
+            // When it is a leaked route, the LFIB and FIB goes a bit different.
+            installInterVpnRouteInLFib(rd, vrfEntry);
+            return;
+        }
+
+        final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
+
         if (vpnToDpnList != null) {
-            for (VpnToDpnList curDpn : vpnToDpnList) {
-                installSubnetRouteInFib(curDpn.getDpnId(),elanTag, rd, vpnId.longValue(), vrfEntry);
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction tx = broker.newWriteOnlyTransaction();
+                            for (VpnToDpnList vpnDpn : vpnToDpnList) {
+                                if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
+                                    createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
+                                }
+                            }
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(tx.submit());
+                            return futures;
+                        }
+                    });
+        }
+
+        Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(broker, rd);
+        if ( vpnUuid.isPresent() ) {
+            Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(broker, vpnUuid.get());
+            if ( interVpnLink.isPresent() ) {
+                String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
+                if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid.get(), interVpnLink.get()) ) {
+                    // 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(), rd, vrfEntry, vpnId);
+                }
             }
         }
-        return;
     }
-    BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
-            rd, vrfEntry);
-    if (vpnToDpnList != null) {
-        for (VpnToDpnList curDpn : vpnToDpnList) {
-            if (!curDpn.getDpnId().equals(localDpnId)) {
-                createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
-                        vrfTableKey, vrfEntry);
+
+    /*
+     * 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,
+                                   int addOrRemove) {
+        Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
+        final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
+
+        String rd = vrfTableKey.getRouteDistinguisher();
+        VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
+        Preconditions.checkNotNull(vpnInstance,
+                "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
+        Preconditions.checkNotNull(vpnInstance.getVpnId(),
+                "Vpn Instance with vrf " + vpnInstance.getVrfId() + " has null vpnId!");
+
+        String vpnUuid = vpnInstance.getVpnInstanceName();
+        Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
+                "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
+
+        // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
+        // there an interVpnLink for the involved vpn in order to make learn the new route to
+        // the other part of the inter-vpn-link.
+
+        // 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(broker, rd)
+                        : FibUtil.getInterVpnLinkByRd(broker, rd);
+        if ( !interVpnLink.isPresent() ) {
+            LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
+            return;
+        }
+
+        // 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() );
+
+        if ( proceed ) {
+            String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) )
+                    ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
+                    : vpnUuid;
+
+            String dstVpnRd = FibUtil.getVpnRd(broker, theOtherVpnId);
+            String endpointIp = vrfEntry.getNextHopAddressList().get(0);
+
+            InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
+                    InstanceIdentifier.builder(FibEntries.class)
+                            .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
+                            .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
+                            .build();
+            if ( addOrRemove == NwConstants.ADD_FLOW ) {
+                LOG.info("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
+                        vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
+                String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
+                long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
+                VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
+                        .setLabel(label)
+                        .setOrigin(RouteOrigin.INTERVPN.getValue())
+                        .build();
+                MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
+            } else {
+                LOG.info("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
+                MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
             }
         }
     }
-  }
 
-  private void installSubnetRouteInFib(BigInteger dpnId, long elanTag, String rd,
-                                       long vpnId, VrfEntry vrfEntry){
-      List<InstructionInfo> instructions = new ArrayList<>();
+    private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
+                                         final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
+        Boolean wrTxPresent = true;
+        if (tx == null) {
+            wrTxPresent = false;
+            tx = broker.newWriteOnlyTransaction();
+        }
+        final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        BigInteger subnetRouteMeta =  ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId)));
+        instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+        makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
 
-      instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
-      instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
-      makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW);
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        // reinitialize instructions list for LFIB Table
+        final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
 
-      List<ActionInfo> actionsInfos = new ArrayList<>();
-      // reinitialize instructions list for LFIB Table
-      instructions = new ArrayList<>();
+        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
+        LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
+        LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
 
-      actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
-      instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
-      instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
-      instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
+        makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
+        if(!wrTxPresent ){
+            tx.submit();
+        }
+    }
 
-      makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
-              vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
-      // TODO makeTunnelTableEntry();
-  }
+    private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
+        // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
+        // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
+        // packet is commuted from Vpn2 to Vpn1.
+        Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(broker, rd);
+        if ( !vpnNameOpc.isPresent() ) {
+            LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
+            return;
+        }
 
-  private  <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                  InstanceIdentifier<T> path) {
+        String vpnName = vpnNameOpc.get();
+        List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(broker);
+        boolean interVpnLinkFound = false;
+        for ( InterVpnLink interVpnLink : interVpnLinks ) {
+            boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
+            boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
+                    && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
+            if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
+                interVpnLinkFound = true;
+
+                Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(broker, interVpnLink.getName());
+                if ( !vpnLinkState.isPresent()
+                        || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
+                    LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
+                            interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
+                            interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
+                    return;
+                }
+
+                List<BigInteger> targetDpns =
+                        ( vpnIs1stEndpoint ) ? vpnLinkState.get().getFirstEndpointState().getDpId()
+                                : vpnLinkState.get().getSecondEndpointState().getDpId();
+                int 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[]{}));
+
+                    BigInteger[] metadata = new BigInteger[] {
+                            MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, FibConstants.L3VPN_SERVICE_IDENTIFIER),
+                            MetaDataUtil.getMetaDataMaskForLPortDispatcher()
+                    };
+                    List<InstructionInfo> instructions =
+                            Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
+                                    new InstructionInfo(InstructionType.write_metadata, metadata),
+                                    new InstructionInfo(InstructionType.goto_table,
+                                            new long[] { NwConstants.L3_INTERFACE_TABLE }));
+
+                    makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
+                            NwConstants.ADD_FLOW, null);
+                }
+
+                break;
+            }
+        }
+
+        if ( !interVpnLinkFound ) {
+            LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
+                    vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
+        }
+    }
 
-      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;
-  }
+    private void installRouteInInterVpnLink(final InterVpnLink 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);
 
-  private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
-      final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
-      List<ActionInfo> actionsInfos = new ArrayList<>();
-      List<InstructionInfo> instructions = new ArrayList<>();
-      actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
-      instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
-      List<MatchInfo> matches = new ArrayList<>();
-      String flowRef = getFlowRef(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);
+        // 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(broker, interVpnLink.getName());
+        if ( !interVpnLinkState.isPresent() ) {
+            LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
+            return;
+        }
+        if ( ! interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
+            LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
+                    vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList().get(0), interVpnLink.getName());
+            return;
+        }
 
-      if (addOrRemove == NwConstants.ADD_FLOW) {
-          mdsalManager.installFlow(flowEntity);
-      } else {
-          mdsalManager.removeFlow(flowEntity);
-      }
-  }
 
-  private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
-      Collection<BigInteger> dpns = new HashSet<>();
-      for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
-          dpns.add(dpn.getDpnId());
-      }
+        // Everything Ok
+        boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
+        List<BigInteger> targetDpns =
+                vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
+                        : interVpnLinkState.get().getSecondEndpointState().getDpId();
 
-      return dpns;
-  }
+        Integer otherEndpointlportTag =
+                vpnIsFirstEndpoint ? interVpnLinkState.get().getSecondEndpointState().getLportTag()
+                        : interVpnLinkState.get().getFirstEndpointState().getLportTag();
 
-  public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
-    BigInteger localDpnId = BigInteger.ZERO;
-    Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
-    String localNextHopIP = vrfEntry.getDestPrefix();
+        BigInteger[] metadata = new BigInteger[] {
+                MetaDataUtil.getMetaDataForLPortDispatcher(otherEndpointlportTag,
+                        FibConstants.L3VPN_SERVICE_IDENTIFIER),
+                MetaDataUtil.getMetaDataMaskForLPortDispatcher()
+        };
+        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));
 
-    if(localNextHopInfo == null) {
-        //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
-        Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
-        if (extra_route != null) {
-            localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
-            localNextHopIP = extra_route.getNexthopIp() + "/32";
+        String values[] = vrfEntry.getDestPrefix().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[] { BigInteger.valueOf(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) }));
+        }
+
+        int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+        String nextHop = vrfEntry.getNextHopAddressList().get(0);
+        String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop);
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
+                COOKIE_VM_FIB_TABLE, matches, instructions);
+
+        for ( BigInteger dpId : targetDpns ) {
+            mdsalManager.installFlow(dpId, flowEntity);
         }
     }
 
-    if(localNextHopInfo != null) {
-        localDpnId = localNextHopInfo.getDpnId();
-        long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
+    private void removeRouteFromInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
+                                             final VrfEntry vrfEntry) {
 
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        List<InstructionInfo> instructions = new ArrayList<>();
+        Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
+        Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
+                && vrfEntry.getNextHopAddressList().size() == 1);
 
-        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
-        instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
-        makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
+        Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(broker, interVpnLink.getName());
+        if ( !interVpnLinkState.isPresent() ) {
+            LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
+            return;
+        }
 
-        actionsInfos= new ArrayList<>();
-        instructions= new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
-        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
-        instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
-        makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
+        // Everything Ok
+        boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
+        List<BigInteger> targetDpns =
+                vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
+                        : interVpnLinkState.get().getSecondEndpointState().getDpId();
 
-        LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
-                localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
-        makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
+        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();
 
-    }
-    return localDpnId;
-  }
+        for ( BigInteger dpId : targetDpns ) {
+            mdsalManager.removeFlow(dpId, flow);
+        }
 
-  private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
-      List<ActionInfo> actionsInfos = new ArrayList<>();
-      actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+    }
 
+    private boolean isVpnFirstEndPoint(InterVpnLink interVpnLink, String vpnName) {
+        return interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
+    }
 
-      createTerminatingServiceActions(dpId, (int)label, actionsInfos);
+    private  <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+                                                     InstanceIdentifier<T> path) {
 
-      LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
-              dpId, label, groupId);
-  }
+        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
 
-  public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
-      List<MatchInfo> mkMatches = new ArrayList<>();
+        Optional<T> result = Optional.absent();
+        try {
+            result = tx.read(datastoreType, path).get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
 
-      LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
+        return result;
+    }
 
-      // Matching metadata
-      // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
-      mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
+    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);
 
-      List<InstructionInfo> mkInstructions = new ArrayList<>();
-      mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
+        if (addOrRemove == NwConstants.ADD_FLOW) {
+            mdsalManager.installFlow(flowEntity);
+        } else {
+            mdsalManager.removeFlow(flowEntity);
+        }
+    }
 
-      FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
-                      getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
-                      0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
+    private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
+        Collection<BigInteger> dpns = new HashSet<>();
+        for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
+            dpns.add(dpn.getDpnId());
+        }
 
-      mdsalManager.installFlow(terminatingServiceTableFlowEntity);
- }
+        return dpns;
   }
 
-  private void removeTunnelTableEntry(BigInteger dpId, long label) {
-    FlowEntity flowEntity;
-    LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
-    List<MatchInfo> mkMatches = new ArrayList<>();
-    // Matching metadata
-    mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
-    flowEntity = MDSALUtil.buildFlowEntity(dpId,
-                                           NwConstants.INTERNAL_TUNNEL_TABLE,
-                                           getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
-                                           5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
-                                           COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
-    mdsalManager.removeFlow(flowEntity);
-    LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully",dpId, label);
-  }
+    private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
+        List<BigInteger> returnLocalDpnId = new ArrayList<BigInteger>();
+        Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
+        String localNextHopIP = vrfEntry.getDestPrefix();
+
+        if (localNextHopInfo == null) {
+            //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
+            Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
+            if (extraRoute != null) {
+                //FIXME:Suraj
+//                for (String nextHopIp : extraRoute.getNexthopIpList()) {
+//                    LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
+//                    if (nextHopIp != null) {
+//                        localNextHopInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
+//                        localNextHopIP = nextHopIp + "/32";
+//                        BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd,
+//                        vrfEntry);
+//                        returnLocalDpnId.add(dpnId);
+//                    }
+//                }
+            }
+        } else {
+            BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry);
+            returnLocalDpnId.add(dpnId);
+        }
 
-  public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
-    BigInteger localDpnId = BigInteger.ZERO;
-    boolean isExtraRoute = false;
-    VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
-    String localNextHopIP = vrfEntry.getDestPrefix();
+        return returnLocalDpnId;
+    }
 
-    if(localNextHopInfo == null) {
-        //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
-        Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
-        if (extra_route != null) {
-            localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
-            localNextHopIP = extra_route.getNexthopIp() + "/32";
-            isExtraRoute = true;
+    private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
+                                                final VrfEntry vrfEntry){
+        if (localNextHopInfo != null) {
+            final BigInteger dpnId = localNextHopInfo.getDpnId();
+            final long groupId = nextHopManager.createLocalNextHop(vpnId, dpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
+
+            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));
+
+            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));
+
+            LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
+                    dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
+
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction tx = broker.newWriteOnlyTransaction();
+
+                            makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
+                            makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
+                            makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(tx.submit());
+                            return futures;
+                        }
+                    });
+            return dpnId;
         }
+        return BigInteger.ZERO;
     }
 
+    private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
+                                      WriteTransaction tx) {
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+        actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
+
+
+        createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
+
+        LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
+                dpId, label, groupId);
+    }
+
+    public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
+                                                 WriteTransaction tx) {
+        List<MatchInfo> mkMatches = new ArrayList<>();
+
+        LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
+
+        // Matching metadata
+        // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
 
-    if(localNextHopInfo != null) {
-      localDpnId = localNextHopInfo.getDpnId();
-      Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
-        makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
-                           NwConstants.DEL_FLOW);
-        makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
-                           vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
-        removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
-        deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
+        List<InstructionInfo> mkInstructions = new ArrayList<>();
+        mkInstructions.add(new InstructionInfo(InstructionType.write_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),
+                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
+
+        FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
+
+        FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
+
+        Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
+        tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
     }
-    return localDpnId;
-  }
 
-  private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
-    return InstanceIdentifier.builder(PrefixToInterface.class)
-        .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
-  }
+    private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
+        FlowEntity flowEntity;
+        LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
+        List<MatchInfo> mkMatches = new ArrayList<>();
+        // Matching metadata
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
+        flowEntity = MDSALUtil.buildFlowEntity(dpId,
+                NwConstants.INTERNAL_TUNNEL_TABLE,
+                getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
+                5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
+                COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
+        Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
+        FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
+
+        tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
+    }
 
-  private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
-    Optional<Prefixes> localNextHopInfoData =
-        FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
-    return  localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
-  }
+    /**
+     * Delete local FIB entry
+     * @param vpnId
+     * @param rd
+     * @param vrfEntry
+     * @return
+     */
+    public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
+        List<BigInteger> returnLocalDpnId = new ArrayList<>();
+        BigInteger localDpnId = BigInteger.ZERO;
+        VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
+        String localNextHopIP = vrfEntry.getDestPrefix();
+
+        if (localNextHopInfo == null) {
+            //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
+            Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
+            if (extra_route != null) {
+                //FIXME:Suraj
+//                for (String nextHopIp : extra_route.getNexthopIpList()) {
+//                    LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
+//                    if (nextHopIp != null) {
+//                        localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
+//                        localNextHopIP = nextHopIp + "/32";
+//                        BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, localDpnId,
+//                                vpnId, rd, vrfEntry, true /*isExtraRoute*/);
+//                        returnLocalDpnId.add(dpnId);
+//                    }
+//                }
+            }
+        } else {
+            BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, localDpnId,
+                    vpnId, rd, vrfEntry, false /*isExtraRoute*/);
+            returnLocalDpnId.add(dpnId);
+        }
+
+        return returnLocalDpnId;
+    }
+
+    private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
+                                                final BigInteger localDpnId, final Long vpnId, final String rd,
+                                                final VrfEntry vrfEntry, final boolean isExtraRoute) {
+        if (localNextHopInfo != null) {
+            final BigInteger dpnId = localNextHopInfo.getDpnId();;
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction tx = broker.newWriteOnlyTransaction();
+
+                            Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
+                            makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
+                                    NwConstants.DEL_FLOW, tx);
+                            makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
+                                    DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
+                            removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(tx.submit());
+                            return futures;
+                        }
+                    });
+            //TODO: verify below adjacency call need to be optimized (?)
+            deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
+        }
+        return localDpnId;
+    }
+
+
+    private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
+        return InstanceIdentifier.builder(PrefixToInterface.class)
+                .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
+    }
+
+    private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
+        Optional<Prefixes> localNextHopInfoData =
+                FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
+        return  localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
+    }
 
     private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
         return InstanceIdentifier.builder(VpnToExtraroute.class)
@@ -420,117 +837,106 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
 
     }
 
-  private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
+    private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
         try {
             Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
-                         new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
-          RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
-          if(!rpcResult.isSuccessful()) {
-              LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
-          } else {
-              return rpcResult.getResult().getTunnelType();
-          }
-         
-      } catch (InterruptedException | ExecutionException e) {
-          LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
-      }
-  
-  return null;
-
-  }
-  private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
-                                    final long vpnId, final VrfTablesKey vrfTableKey,
-                                    final VrfEntry vrfEntry) {
-    String rd = vrfTableKey.getRouteDistinguisher();
-    LOG.debug("createremotefibentry: adding route {} for rd {}", vrfEntry.getDestPrefix(), rd);
-    /********************************************/
-    String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
-    if(tunnelInterface == null) {
-      LOG.error("Could not get interface for nexthop: {} in vpn {}",
-                                   vrfEntry.getNextHopAddress(), rd);
-      LOG.warn("Failed to add Route: {} in vpn: {}",
-                             vrfEntry.getDestPrefix(), rd);
-      return;
-    }
-      List<ActionInfo> actionInfos = new ArrayList<>();
-       Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
-    if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
-        LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
-        actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
-        actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
-    } else {
-        int label = vrfEntry.getLabel().intValue();
-        BigInteger tunnelId;
-        // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
-        if(tunnel_type.equals(TunnelTypeVxlan.class)) {
-               tunnelId = BigInteger.valueOf(label);
-        } else {
-               tunnelId = BigInteger.valueOf(label);
+                    new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
+            RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
+            if(!rpcResult.isSuccessful()) {
+                LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
+            } else {
+                return rpcResult.getResult().getTunnelType();
+            }
+
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
         }
-        LOG.debug("adding set tunnel id action for label {}", label);
-        actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
-                tunnelId}));
+
+        return null;
+
     }
-    actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
-    List<InstructionInfo> instructions= new ArrayList<>();
-    instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
-/*
-    List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
-    if(actionInfos == null) {
-      LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
-                                   vrfEntry.getNextHopAddress(), rd);
-      LOG.warn("Failed to add Route: {} in vpn: {}",
-                             vrfEntry.getDestPrefix(), rd);
-      return;
-    }
-    BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
-    if(dpnId == null) {
-        //This route may be extra route... try to query with nexthop Ip
-        LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
-        dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
-    }
-    if(dpnId == null) {
-        LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
-        actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
-        actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
-    } else {
-        int label = vrfEntry.getLabel().intValue();
-        LOG.debug("adding set tunnel id action for label {}", label);
-        actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
-                MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
-                MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
-    }
-**/
-      makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
-      LOG.debug("Successfully added fib entry for prefix {} in vpn {} ", vrfEntry.getDestPrefix(), vpnId);
-  }
-
-  private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
-      InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
-      Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-      if (dpnInVpn.isPresent()) {
-          List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                  .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
-          org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
-                  currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
-
-          if (vpnInterfaces.remove(currVpnInterface)) {
-              if (vpnInterfaces.isEmpty()) {
-                  LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
-                  FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
-                  cleanUpDpnForVpn(dpnId, vpnId, rd);
-              } else {
-                  LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
-                  FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
-                          org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                                  .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
-                          new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
-              }
-          }
-      }
-  }
-
-  private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
+    private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
+                                      final VrfEntry vrfEntry, WriteTransaction tx) {
+        Boolean wrTxPresent = true;
+        if (tx == null) {
+            wrTxPresent = false;
+            tx = broker.newWriteOnlyTransaction();
+        }
+        String rd = vrfTableKey.getRouteDistinguisher();
+        LOG.debug("createremotefibentry: adding route {} for rd {} with transaction ", vrfEntry.getDestPrefix(), rd);
+        /********************************************/
+        List<String> tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
+
+        if (tunnelInterfaceList.isEmpty()) {
+            LOG.error("Could not get interface for nexthop: {} in vpn {}",
+                    vrfEntry.getNextHopAddressList(), rd);
+            LOG.warn("Failed to add Route: {} in vpn: {}",
+                    vrfEntry.getDestPrefix(), rd);
+            return;
+        }
+
+        for (String tunnelInterface : tunnelInterfaceList) {
+            List<InstructionInfo> instructions = new ArrayList<>();
+            List<ActionInfo> actionInfos = new ArrayList<>();
+            Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
+            if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
+                LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
+                actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[]{null}));
+                actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[]{Long.toString(vrfEntry.getLabel())}));
+            } else {
+                int label = vrfEntry.getLabel().intValue();
+                BigInteger tunnelId;
+                // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
+                if (tunnel_type.equals(TunnelTypeVxlan.class)) {
+                    tunnelId = BigInteger.valueOf(label);
+                } else {
+                    tunnelId = BigInteger.valueOf(label);
+                }
+
+                LOG.debug("adding set tunnel id action for label {}", label);
+                actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{tunnelId}));
+            }
+            List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(tunnelInterface);
+            if(egressActions.isEmpty()){
+                LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), tunnelInterface);
+                return;
+            }
+            actionInfos.addAll(egressActions);
+            instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
+            makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
+        }
+        if(!wrTxPresent ){
+            tx.submit();
+        }
+        LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
+    }
+
+    private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
+        InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (dpnInVpn.isPresent()) {
+            List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
+                    .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
+            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
+                    currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
+
+            if (vpnInterfaces.remove(currVpnInterface)) {
+                if (vpnInterfaces.isEmpty()) {
+                    LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
+                    FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
+                    cleanUpDpnForVpn(dpnId, vpnId, rd);
+                } else {
+                    LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
+                    FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
+                                    .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
+                            new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
+                }
+            }
+        }
+    }
+
+    private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
     /* Get interface info from prefix to interface mapping;
         Use the interface info to get the corresponding vpn interface op DS entry,
         remove the adjacency corresponding to this fib entry.
@@ -539,370 +945,557 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
          - prefix to interface entry
          - vpn interface op DS
      */
-      LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
-      Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
-      Extraroute extraRoute = null;
-      if (prefixInfo == null) {
-          extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
-          if(extraRoute != null) {
-              prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
-              //clean up the vpn to extra route entry in DS
-              //FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd,
-                //      vrfEntry.getDestPrefix()));
-          }
-      }
-      if (prefixInfo == null) {
-          LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}" , vrfEntry.getDestPrefix());
-          return; //Don't have any info for this prefix (shouldn't happen); need to return
-      }
-      String ifName = prefixInfo.getVpnInterfaceName();
-      synchronized (ifName.intern()) {
-          Optional<VpnInterface> optvpnInterface = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnInterfaceIdentifier(ifName));
-          if (optvpnInterface.isPresent()) {
-              long associatedVpnId = FibUtil.getVpnId(broker, optvpnInterface.get().getVpnInstanceName());
-              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;
-              } else {
-                  LOG.debug("Processing cleanup of prefix {} associated with vpn {}", vrfEntry.getDestPrefix(), associatedVpnId);
-              }
-          }
-          if (extraRoute != null) {
-              FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
-          }
-          Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
-          int numAdj = 0;
-          if (optAdjacencies.isPresent()) {
-              numAdj = optAdjacencies.get().getAdjacency().size();
-          }
-
-          //remove adjacency corr to prefix
-          if (numAdj > 1) {
-              LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
-              FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-                      FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
-          }
-
-          if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
-              //clean up the vpn interface from DpnToVpn list
-              LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
-              FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
-                      FibUtil.getVpnInterfaceIdentifier(ifName));
-          }
-
-          FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
-                  FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
-      }
-  }
-
-  private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
-                                final VrfEntry vrfEntry) {
-    final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
-    Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
-    Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
-
-    String rd  = vrfTableKey.getRouteDistinguisher();
-    VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
-    if (vpnInstance == null) {
-        LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
-        return;
-    }
-    Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
-    SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-    if (subnetRoute != null) {
+        LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
+        Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
+        Extraroute extraRoute = null;
+        if (prefixInfo == null) {
+            extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
+            if(extraRoute != null) {
+                //FIXME:Suraj
+//                for (String nextHopIp : extraRoute.getNexthopIpList()) {
+  //                  LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
+//
+  //                  if (nextHopIp != null) {
+    //                    prefixInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
+      //                  checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
+        //            }
+          //      }
+            }
+        } else {
+            checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
+        }
+    }
+
+    private void checkCleanUpOpDataForFib(Prefixes prefixInfo, Long vpnId, String rd,
+                                          final VrfEntry vrfEntry, Extraroute extraRoute) {
+
+        if (prefixInfo == null) {
+            LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
+            return; //Don't have any info for this prefix (shouldn't happen); need to return
+        }
+
+        String ifName = prefixInfo.getVpnInterfaceName();
+        synchronized (ifName.intern()) {
+            Optional<VpnInterface> optvpnInterface = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                    FibUtil.getVpnInterfaceIdentifier(ifName));
+            if (optvpnInterface.isPresent()) {
+                long associatedVpnId = FibUtil.getVpnId(broker, optvpnInterface.get().getVpnInstanceName());
+                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;
+                } else {
+                    LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
+                            vrfEntry.getDestPrefix(), associatedVpnId);
+                }
+            }
+            if (extraRoute != null) {
+                FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                        FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
+            }
+            Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
+                    FibUtil.getAdjListPath(ifName));
+            int numAdj = 0;
+            if (optAdjacencies.isPresent()) {
+                numAdj = optAdjacencies.get().getAdjacency().size();
+            }
+            //remove adjacency corr to prefix
+            if (numAdj > 1) {
+                LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
+                FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                        FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
+            }
+            if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
+                //clean up the vpn interface from DpnToVpn list
+                LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
+                FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
+                        FibUtil.getVpnInterfaceIdentifier(ifName));
+            }
+            FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+                    FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
+        }
+    }
+
+
+    private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
+        final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
+
+        final String rd  = vrfTableKey.getRouteDistinguisher();
+        final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
+        if (vpnInstance == null) {
+            LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
+            return;
+        }
+        final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+        SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+        if (subnetRoute != null) {
+            if (vpnToDpnList != null) {
+                DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() throws Exception {
+                                WriteTransaction tx = broker.newWriteOnlyTransaction();
+
+                                for (final VpnToDpnList curDpn : vpnToDpnList) {
+
+                                    makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
+                                            vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
+                                    makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
+                                            DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
+                                }
+                                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                                futures.add(tx.submit());
+                                return futures;
+                            }
+                        });
+            }
+            FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
+                    FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
+            LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
+                    vrfEntry.getDestPrefix());
+            return;
+        }
+
+        final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
+                vrfTableKey.getRouteDistinguisher(), vrfEntry);
         if (vpnToDpnList != null) {
-            for (VpnToDpnList curDpn : vpnToDpnList) {
-                makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry, vrfTableKey
-                        .getRouteDistinguisher(), null, NwConstants.DEL_FLOW);
-                makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
-                        vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
+            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+            dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
+                    new Callable<List<ListenableFuture<Void>>>() {
+                        @Override
+                        public List<ListenableFuture<Void>> call() throws Exception {
+                            WriteTransaction tx = broker.newWriteOnlyTransaction();
+
+                            if (localDpnIdList.size() <= 0) {
+                                for (VpnToDpnList curDpn : vpnToDpnList) {
+                                    deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
+                                }
+                            } else {
+                                for (BigInteger localDpnId : localDpnIdList) {
+                                    for (VpnToDpnList curDpn : vpnToDpnList) {
+                                        if (!curDpn.getDpnId().equals(localDpnId)) {
+                                            deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
+                                        }
+                                    }
+                                }
+                            }
+                            List<ListenableFuture<Void>> futures = new ArrayList<>();
+                            futures.add(tx.submit());
+                            return futures;
+                        }
+                    });
+        }
+
+        //The flow/group entry has been deleted from config DS; need to clean up associated operational
+        //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
+        cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
+
+        // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
+        // of the interVpnLink.
+        Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(broker, rd);
+        if ( vpnUuid.isPresent() ) {
+            Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(broker, 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);
             }
         }
-        FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
-              FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
-        LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
-                vrfEntry.getDestPrefix());
-        return;
-    }
-    BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
-            vrfTableKey.getRouteDistinguisher(), vrfEntry);
-    if (vpnToDpnList != null) {
-        for (VpnToDpnList curDpn : vpnToDpnList) {
-            if (!curDpn.getDpnId().equals(localDpnId)) {
-                deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
+
+    }
+
+    public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
+                                  final long vpnId, final VrfTablesKey vrfTableKey,
+                                  final VrfEntry vrfEntry, WriteTransaction tx) {
+
+        Boolean wrTxPresent = true;
+        if (tx == null) {
+            wrTxPresent = false;
+            tx = broker.newWriteOnlyTransaction();
+        }
+
+        LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
+        String rd = vrfTableKey.getRouteDistinguisher();
+
+        if(localDpnId != null) {
+            // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
+            deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
+            return;
+        }
+
+        // below two reads are kept as is, until best way is found to identify dpnID
+        VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
+        Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
+
+        if (localNextHopInfo == null && extraRoute != null) {
+            // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
+            //FIXME:Suraj
+//            for (String nextHopIp : extraRoute.getNexthopIpList()) {
+  //              localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
+    //            checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
+      //      }
+        } else {
+            checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
+        }
+        if(!wrTxPresent ){
+            tx.submit();
+        }
+    }
+
+    private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
+                                           VrfEntry vrfEntry, String rd, WriteTransaction tx){
+        boolean isRemoteRoute = true;
+        if (localNextHopInfo != null) {
+            isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
+        }
+        if (isRemoteRoute) {
+            deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
+            return true;
+        } else {
+            LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
+            return false;
+        }
+    }
+
+    private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
+        makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
+        LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
+    }
+
+    private long get
+            (byte[] rawIpAddress) {
+        return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
+                + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
+    }
+
+    private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
+                                    List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
+        Boolean wrTxPresent = true;
+        if (tx == null) {
+            wrTxPresent = false;
+            tx = broker.newWriteOnlyTransaction();
+        }
+
+        LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
+        String values[] = vrfEntry.getDestPrefix().split("/");
+        String ipAddress = values[0];
+        int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
+        if (addOrRemove == NwConstants.ADD_FLOW) {
+            LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
+        } else {
+            LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
+        }
+        InetAddress destPrefix;
+        try {
+            destPrefix = InetAddress.getByName(ipAddress);
+        } catch (UnknownHostException e) {
+            LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
+            return;
+        }
+
+        List<MatchInfo> matches = new ArrayList<>();
+
+        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
+                BigInteger.valueOf(vpnId), 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[] {
+                    destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
+        }
+        int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
+        String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
+                COOKIE_VM_FIB_TABLE, matches, instructions);
+
+        Flow flow = flowEntity.getFlowBuilder().build();
+        String flowId = flowEntity.getFlowId();
+        FlowKey flowKey = new FlowKey( new FlowId(flowId));
+        Node nodeDpn = buildDpnNode(dpId);
+
+        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 (addOrRemove == NwConstants.ADD_FLOW) {
+            tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
+        } else {
+            tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        }
+
+        if(!wrTxPresent ){
+            tx.submit();
+        }
+    }
+
+    //TODO: How to handle the below code, its a copy paste from MDSALManager.java
+    private Node buildDpnNode(BigInteger dpnId) {
+        NodeId nodeId = new NodeId("openflow:" + dpnId);
+        Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
+
+        return nodeDpn;
+    }
+
+    private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
+                                    int addOrRemove, WriteTransaction tx) {
+        Boolean wrTxPresent = true;
+        if (tx == null) {
+            wrTxPresent = false;
+            tx = broker.newWriteOnlyTransaction();
+        }
+
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { NwConstants.ETHTYPE_MPLS_UC }));
+        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
+
+        // Install the flow entry in L3_LFIB_TABLE
+        String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
+
+        FlowEntity flowEntity;
+        flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, instructions);
+        Flow flow = flowEntity.getFlowBuilder().build();
+        String flowId = flowEntity.getFlowId();
+        FlowKey flowKey = new FlowKey( new FlowId(flowId));
+        Node nodeDpn = buildDpnNode(dpId);
+        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 (addOrRemove == NwConstants.ADD_FLOW) {
+            tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
+        } else {
+            tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        }
+        if(!wrTxPresent ){
+            tx.submit();
+        }
+        LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
+    }
+
+    private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
+        LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
+        try {
+            nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
+        } catch (NullPointerException e) {
+            LOG.trace("", e);
+        }
+    }
+
+    public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd) {
+        LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
+        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+        String lockOnDpnVpn = new String(dpnId.toString() + vpnId);
+        synchronized (lockOnDpnVpn.intern()) {
+            final Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+            if (vrfTable.isPresent()) {
+                DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                dataStoreCoordinator.enqueueJob("FIB" + vpnId + dpnId.toString(),
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            @Override
+                            public List<ListenableFuture<Void>> call() throws Exception {
+                                WriteTransaction tx = broker.newWriteOnlyTransaction();
+                                for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+
+                                    SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+                                    if (subnetRoute != null) {
+                                        long elanTag = subnetRoute.getElantag();
+                                        installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
+                                        continue;
+                                    }
+                                    // Passing null as we don't know the dpn
+                                    // to which prefix is attached at this point
+                                    createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
+                                }
+                                //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
+                                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                                futures.add(tx.submit());
+                                return futures;
+                            }
+                        });
+            }
+        }
+    }
+
+    public void populateFibOnDpn(BigInteger dpnId, BigInteger localDpnId, long vpnId, String rd, String nexthopIp) {
+        LOG.trace(" dpn {} for vpn {}, rd {}, nexthopIp {} : populateFibOnDpn", dpnId, vpnId, rd, nexthopIp);
+        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+        String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
+        synchronized (lockOnDpnVpn.intern()) {
+            Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+            if (vrfTable.isPresent()) {
+                for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                    // Passing null as we don't know the dpn
+                    // to which prefix is attached at this point
+                    if (nexthopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
+                        LOG.trace(" creating remote FIB entry");
+                        createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, null);
+                    }
+                }
             }
         }
     }
-    //The flow/group entry has been deleted from config DS; need to clean up associated operational
-    //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
-    cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
-  }
-
-  public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
-                                final long vpnId, final VrfTablesKey vrfTableKey,
-                                final VrfEntry vrfEntry) {
-    LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
-    String rd = vrfTableKey.getRouteDistinguisher();
-    boolean isRemoteRoute = true;
-    if (localDpnId == null) {
-      // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
-      VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
-      if(localNextHopInfo == null) {
-        //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
-        Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
-        if (extra_route != null) {
-          localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
-        }
-      }
-      if (localNextHopInfo != null) {
-        isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
-      }
-    }
-    if (isRemoteRoute) {
-      makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
-      LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
-    } else{
-      LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
-    }
-  }
-
-  private long getIpAddress(byte[] rawIpAddress) {
-    return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
-            + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
-  }
-
-  private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
-                                  List<InstructionInfo> instructions, int addOrRemove) {    LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
-    String values[] = vrfEntry.getDestPrefix().split("/");
-    String ipAddress = values[0];
-    int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
-    if (addOrRemove == NwConstants.ADD_FLOW) {
-        LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
-    } else {
-        LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
-    }
-    InetAddress destPrefix = null;
-    try {
-      destPrefix = InetAddress.getByName(ipAddress);
-    } catch (UnknownHostException e) {
-      LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
-      return;
-    }
-
-    List<MatchInfo> matches = new ArrayList<>();
-
-    matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-        BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
-
-    matches.add(new MatchInfo(MatchFieldType.eth_type,
-                              new long[] { 0x0800L }));
-
-    if(prefixLength != 0) {
-        matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
-                destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
-    }
-
-    String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
-
-    FlowEntity flowEntity;
-
-    int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
-    flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
-                                           priority, flowRef, 0, 0,
-                                           COOKIE_VM_FIB_TABLE, matches, instructions);
-
-    if (addOrRemove == NwConstants.ADD_FLOW) {
-      /* We need to call sync API to install flow so that 2 DS operations on the same object do not
-      * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
-      * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
-      * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
-      * wait indefinitely. */
-      mdsalManager.syncInstallFlow(flowEntity, 1);
-    } else {
-      mdsalManager.syncRemoveFlow(flowEntity, 1);
-    }
-  }
-
-  private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
-                                  String nextHop, int addOrRemove) {
-    List<MatchInfo> matches = new ArrayList<>();
-    matches.add(new MatchInfo(MatchFieldType.eth_type,
-                              new long[] { 0x8847L }));
-    matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
-
-    // Install the flow entry in L3_LFIB_TABLE
-    String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
-
-    FlowEntity flowEntity;
-    flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
-                                           DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
-                                           COOKIE_VM_LFIB_TABLE, matches, instructions);
-
-    if (addOrRemove == NwConstants.ADD_FLOW) {
-      /* We need to call sync API to install flow so that 2 DS operations on the same object do not
-      * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
-      * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
-      * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
-      * wait indefinitely. */
-
-      mdsalManager.syncInstallFlow(flowEntity, 1);
-    } else {
-      mdsalManager.syncRemoveFlow(flowEntity, 1);
-    }
-      LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
-  }
-
-  private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
-    LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
-    try {
-      nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
-    } catch (NullPointerException e) {
-      LOG.trace("", e);
-    }
-  }
-
-  public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
-    LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
-    InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-    String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
-    synchronized (lockOnDpnVpn.intern()) {
-      Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-      if (vrfTable.isPresent()) {
-        for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-          SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-          if (subnetRoute != null){
-              long elanTag= subnetRoute.getElantag();
-              installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry);
-              continue;
-          }
-          // Passing null as we don't know the dpn
-          // to which prefix is attached at this point
-          createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
-        }
-      }
-    }
-  }
-
-  public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
-    LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
-    InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-    String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
-    synchronized (lockOnDpnVpn.intern()) {
-      Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-      if (vrfTable.isPresent()) {
-        for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-          // Passing null as we don't know the dpn
-          // to which prefix is attached at this point
-          if (nexthopIp == vrfEntry.getNextHopAddress()) {
-            createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
-          }
-        }
-      }
-    }
-  }
-
-  public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
-    LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
-    InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-    String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
-    synchronized (lockOnDpnVpn.intern()) {
-      Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-      if (vrfTable.isPresent()) {
-        for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-                        /* Handle subnet routes here */
-            SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
-            if (subnetRoute != null){
-                LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
-                        dpnId, rd);
-                makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
-                makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
-                        vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
-                LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
-                        vrfEntry.getDestPrefix());
-                continue;
+
+    public void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String  rd, String destPrefix ,
+                                  String nextHopIp) {
+        VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
+        VrfEntry vrfEntry = getVrfEntry(broker, rd, destPrefix);
+        if (vrfEntry == null) {
+            LOG.trace("VrfEntry for prefix {} is null. Exitting.", nextHopIp);
+            return;
+        }
+        LOG.trace("handleRemoteRoute --- action {}, localDpnId {}, remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
+                action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
+        if (action == true) {
+            createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, null);
+        } else {
+            deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, null);
+        }
+
+    }
+
+    public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd) {
+        LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
+        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+        String lockOnDpnVpn = new String(dpnId.toString() + vpnId);
+        synchronized (lockOnDpnVpn.intern()) {
+
+            final Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+            if (vrfTable.isPresent()) {
+                DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                dataStoreCoordinator.enqueueJob("FIB" + vpnId + dpnId.toString(),
+                        new Callable<List<ListenableFuture<Void>>>() {
+                            WriteTransaction tx = broker.newWriteOnlyTransaction();
+                            @Override
+                            public List<ListenableFuture<Void>> call() throws Exception {
+                                for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                            /* Handle subnet routes here */
+                                    SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+                                    if (subnetRoute != null) {
+                                        LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
+                                                dpnId, rd);
+                                        makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
+                                        makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
+                                        LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
+                                                vrfEntry.getDestPrefix());
+                                        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);
+                                }
+                                List<ListenableFuture<Void>> futures = new ArrayList<>();
+                                futures.add(tx.submit());
+                                return futures;
+                            }
+
+                        });
+            }
+
+        }
+    }
+
+    public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
+        LOG.trace(" cleanup remote routes on dpn {} for vpn {}, rd {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, vpnId, rd, nexthopIp);
+        InstanceIdentifier<VrfTables> id = buildVrfId(rd);
+        String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
+        synchronized (lockOnDpnVpn.intern()) {
+            Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+            if (vrfTable.isPresent()) {
+                for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
+                    LOG.trace(":vrfEntry :: {}", vrfEntry);
+                    // Passing null as we don't know the dpn
+                    // to which prefix is attached at this point
+                    if (nexthopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
+                        LOG.trace(" deleting remote FIB entry {}", vrfEntry);
+                        deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, null);
+                    }
+                }
+            } else {
+                LOG.trace("No vrfTable is present");
+            }
+        }
+    }
+
+    public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
+        InstanceIdentifierBuilder<VrfTables> idBuilder =
+                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
+        InstanceIdentifier<VrfTables> id = idBuilder.build();
+        return id;
+    }
+
+    private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
+        return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
+                .append(priority).toString();
+    }
+
+    private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
+        return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(rd).append(NwConstants.FLOWID_SEPARATOR)
+                .append(priority).append(NwConstants.FLOWID_SEPARATOR)
+                .append(destPrefix.getHostAddress()).toString();
+    }
+
+    private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
+        return new StringBuilder(64).append(FLOWID_PREFIX)
+                .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
+                .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
+                .append(nextHop).toString();
+    }
+
+    protected List<String> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId, final VrfEntry vrfEntry,
+                                            String rd) {
+        List<String> adjacencyList = new ArrayList<>();
+        LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}", remoteDpnId, vpnId, vrfEntry);
+        try {
+            Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
+            List<String> prefixIpList;
+            if (extra_route == null) {
+                prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
+            } else {
+                prefixIpList = new ArrayList<>();
+                //FIXME:Suraj
+//                for (String extraRouteIp : extra_route.getNexthopIpList()) {
+  //                  prefixIpList.add(extraRouteIp + "/32");
+    //            }
+            }
+
+            for (String prefixIp : prefixIpList) {
+                for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
+                    LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
+                    String adjacency = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId, prefixIp, nextHopIp);
+                    if (adjacency != null && !adjacency.isEmpty() && !adjacencyList.contains(adjacency)) {
+                        adjacencyList.add(adjacency);
+                    }
+                }
             }
-          // 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);
-        }
-      }
-    }
-  }
-
-  public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
-    LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
-    InstanceIdentifier<VrfTables> id = buildVrfId(rd);
-    String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
-    synchronized (lockOnDpnVpn.intern()) {
-      Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-      if (vrfTable.isPresent()) {
-        for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
-          // Passing null as we don't know the dpn
-          // to which prefix is attached at this point
-          if (nexthopIp == vrfEntry.getNextHopAddress()) {
-            deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
-          }
-        }
-      }
-    }
-  }
-
-  public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
-    InstanceIdentifierBuilder<VrfTables> idBuilder =
-        InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
-    InstanceIdentifier<VrfTables> id = idBuilder.build();
-    return id;
-  }
-
-  private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
-    return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-        .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-        .append(label).append(NwConstants.FLOWID_SEPARATOR)
-        .append(nextHop).toString();
-  }
-
-  private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
-    return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-        .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-        .append(rd).append(NwConstants.FLOWID_SEPARATOR)
-        .append(destPrefix.getHostAddress()).toString();
-  }
-
-  protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
-                                              final long vpnId, final VrfEntry vrfEntry, String rd) {
-    String adjacency = null;
-    boolean staticRoute = false;
-    LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
-    try {
-        Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
-        if(extra_route != null) {
-            staticRoute = true;
-        }
-
-        adjacency =
-          nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
-                  (staticRoute) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
-                                                vrfEntry.getNextHopAddress());
-    } catch (NullPointerException e) {
-      LOG.trace("", e);
-    }
-    return adjacency;
-  }
-
-  protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
-    InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
-        VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
-    Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-    if(vpnInstanceOpData.isPresent()) {
-      return vpnInstanceOpData.get();
-    }
-    return null;
-  }
+        } catch (NullPointerException e) {
+            LOG.trace("", e);
+        }
+        return adjacencyList;
+    }
+
+    protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
+                VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
+    }
 
     public void processNodeAdd(BigInteger dpnId) {
         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
@@ -914,15 +1507,18 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
     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<>();
+        List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
-        List<MatchInfo> matches = new ArrayList<>();
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
         FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
-                getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
+                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, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
-                NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
+        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) {
@@ -936,85 +1532,94 @@ public class FibManager extends AbstractDataChangeListener<VrfEntry> implements
         }
     }
 
-    private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
+    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)
                 .append(FLOWID_PREFIX).toString();
     }
 
-  /*
-   * Install flow entry in protocol table to forward mpls
-   * coming through gre tunnel to LFIB table.
-   */
-  private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
-    final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
-    // Instruction to goto L3 InterfaceTable
-    List<InstructionInfo> instructions = new ArrayList<>();
-    instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
-    List<MatchInfo> matches = new ArrayList<>();
-    matches.add(new MatchInfo(MatchFieldType.eth_type,
-                              new long[] { 0x8847L }));
-    FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
-                                                          getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
-                                                                  NwConstants.L3_LFIB_TABLE),
-                                                          DEFAULT_FIB_FLOW_PRIORITY,
-                                                          "Protocol Table For LFIB",
-                                                          0, 0,
-                                                          COOKIE_PROTOCOL_TABLE,
-                                                          matches, instructions);
-
-    if (addOrRemove == NwConstants.ADD_FLOW) {
-      LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
-      mdsalManager.installFlow(flowEntityToLfib);
-    } else {
-      mdsalManager.removeFlow(flowEntityToLfib);
-    }
-  }
-
-  public List<String> printFibEntries() {
-    List<String> result = new ArrayList<>();
-    result.add(String.format("   %-7s  %-20s  %-20s  %-7s", "RD", "Prefix", "Nexthop", "Label"));
-    result.add("-------------------------------------------------------------------");
-    InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
-    Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
-    if (fibEntries.isPresent()) {
-      List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
-      for (VrfTables vrfTable : vrfTables) {
-        for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
-          result.add(String.format("   %-7s  %-20s  %-20s  %-7s", vrfTable.getRouteDistinguisher(),
-                  vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
-        }
-      }
-    }
-    return result;
-  }
-
-  private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
-    List<InstructionInfo> instructions = new ArrayList<>();
-    List<MatchInfo> matches = new ArrayList<>();
-    final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
-    // Instruction to clear metadata except SI and LportTag bits
-    instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
-                    CLEAR_METADATA, METADATA_MASK_CLEAR }));
-    // Instruction to clear action
-    instructions.add(new InstructionInfo(InstructionType.clear_actions));
-    // Instruction to goto L3 InterfaceTable
-
-    List <ActionInfo> actionsInfos = new ArrayList<>();
-    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,
-            getFlowRef(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.info("Invoking MDSAL to install L3 interface Table Miss Entries");
-      mdsalManager.installFlow(flowEntityL3Intf);
-    } else {
-      mdsalManager.removeFlow(flowEntityL3Intf);
-    }
-  }
+    /*
+     * Install flow entry in protocol table to forward mpls
+     * coming through gre tunnel to LFIB table.
+     */
+    private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
+        final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
+        // Instruction to goto L3 InterfaceTable
+        List<InstructionInfo> instructions = new ArrayList<>();
+        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
+        matches.add(new MatchInfo(MatchFieldType.eth_type,
+                new long[] { NwConstants.ETHTYPE_MPLS_UC }));
+        FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
+                getTableMissFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
+                        NwConstants.L3_LFIB_TABLE),
+                DEFAULT_FIB_FLOW_PRIORITY,
+                "Protocol Table For LFIB",
+                0, 0,
+                COOKIE_PROTOCOL_TABLE,
+                matches, instructions);
+
+        if (addOrRemove == NwConstants.ADD_FLOW) {
+            LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
+            mdsalManager.installFlow(flowEntityToLfib);
+        } else {
+            mdsalManager.removeFlow(flowEntityToLfib);
+        }
+    }
 
+    public List<String> printFibEntries() {
+        List<String> result = new ArrayList<String>();
+        result.add(String.format("   %-7s  %-20s  %-20s  %-7s  %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
+        result.add("-------------------------------------------------------------------");
+        InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
+        Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (fibEntries.isPresent()) {
+            List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
+            for (VrfTables vrfTable : vrfTables) {
+                for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
+                    for (String nextHop : vrfEntry.getNextHopAddressList()) {
+                        result.add(String.format("   %-7s  %-20s  %-20s  %-7s  %-7s", vrfTable.getRouteDistinguisher(),
+                                vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
+                    }
+                }
+            }
+        }
+        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.info("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 =
+                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
+                        child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
+        Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
+        if (vrfEntry.isPresent())  {
+            return (vrfEntry.get());
+        }
+        return null;
+    }
 }
+
+
index ec0e2835c10a88ebce6d3af91fab4940bce12af9..327da2f48d5792335d47ccd59e39f8927176e364 100644 (file)
@@ -108,15 +108,15 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au
     return fibManager.printFibEntries();
   }
 
-  //Temp
   @Override
   public void addStaticRoute(String prefix, String nextHop, String rd, int label) {
     this.vpnmanager.addExtraRoute(prefix, nextHop, rd, null, label);
   }
 
+  //FIXME: Once changes are upstreamed from vpnmanager
   @Override
-  public void deleteStaticRoute(String prefix, String rd) {
-    this.vpnmanager.delExtraRoute(prefix, rd, null);
+  public void deleteStaticRoute(String prefix, String nextHop, String rd) {
+  //  this.vpnmanager.delExtraRoute(prefix, nextHop, rd, null);
   }
 
   public void setRpcProviderRegistry(RpcProviderRegistry rpcProviderRegistry) {
@@ -153,5 +153,23 @@ public class FibManagerProvider implements BindingAwareProvider, IFibManager, Au
   public boolean isVPNConfigured() {
     return this.vpnmanager.isVPNConfigured();
   }
+  @Override
+  public String getTransportTypeStr(String tunType) {
+    return this.nexthopManager.getTransportTypeStr(tunType);
+  }
+
+  @Override
+  public void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String  rd, String destPrefix , String nextHopIp) {
+    fibManager.handleRemoteRoute(action, localDpnId, remoteDpnId, vpnId,rd, destPrefix, nextHopIp);
+  }
+  @Override
+  public void populateFibOnDpn(BigInteger localDpnId, BigInteger remoteDpnId, long vpnId, String rd, String nextHopIp) {
+    fibManager.populateFibOnDpn(localDpnId, remoteDpnId, vpnId, rd, nextHopIp);
+  }
+
+  @Override
+  public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nextHopIp) {
+    fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, nextHopIp);
+  }
 
-}
+}
\ No newline at end of file
index 1e2e44785ada0c30f135997d56de962655eb8e7a..f2542ec2d92152f727f2f9cabc74aa1fd8adf5d1 100644 (file)
@@ -28,6 +28,11 @@ 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.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.PopulateFibOnDpnInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CleanupDpnForVpnInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
@@ -40,9 +45,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -74,18 +76,20 @@ public class FibRpcServiceImpl implements FibRpcService {
      * to install FIB routes on specified dpn with given instructions
      *
      */
+    @Override
     public Future<RpcResult<Void>> createFibEntry(CreateFibEntryInput input) {
 
         BigInteger dpnId = input.getSourceDpid();
         String vpnName = input.getVpnName();
         long vpnId = getVpnId(broker, vpnName);
+        String vpnRd = getVpnRd(broker, vpnName);
         String ipAddress = input.getIpAddress();
         LOG.info("Create custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
         List<Instruction> instructions = input.getInstruction();
-
+        LOG.info("ADD: Adding Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
         makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions);
         updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
-
+        LOG.info("ADD: Added Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
         return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
     }
 
@@ -93,24 +97,40 @@ public class FibRpcServiceImpl implements FibRpcService {
      * to remove FIB/LFIB/TST routes from specified dpn
      *
      */
+    @Override
     public Future<RpcResult<Void>> removeFibEntry(RemoveFibEntryInput input) {
 
         BigInteger dpnId = input.getSourceDpid();
         String vpnName = input.getVpnName();
         long vpnId = getVpnId(broker, vpnName);
+        String vpnRd = getVpnRd(broker, vpnName);
         long serviceId = input.getServiceId();
         String ipAddress = input.getIpAddress();
 
         LOG.info("Delete custom FIB entry - {} on dpn {} for VPN {} ", ipAddress, dpnId, vpnName);
-
+        LOG.info("REMOVE: Removing Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
         removeLocalFibEntry(dpnId, vpnId, ipAddress);
         //removeLFibTableEntry(dpnId, serviceId);
         //removeTunnelTableEntry(dpnId, serviceId);
         removeFromVpnDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+        LOG.info("REMOVE: Removed Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
 
         return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
     }
 
+
+    @Override
+    public Future<RpcResult<Void>> populateFibOnDpn(PopulateFibOnDpnInput input) {
+        fibManager.populateFibOnNewDpn(input.getDpid(), input.getVpnId(), input.getRd());
+        return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+    }
+
+    @Override
+    public Future<RpcResult<Void>> cleanupDpnForVpn(CleanupDpnForVpnInput input) {
+        fibManager.cleanUpDpnForVpn(input.getDpid(), input.getVpnId(), input.getRd());
+        return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
+    }
+
     private void removeLocalFibEntry(BigInteger dpnId, long vpnId, String ipPrefix) {
         String values[] = ipPrefix.split("/");
         String ipAddress = values[0];
@@ -118,18 +138,18 @@ public class FibRpcServiceImpl implements FibRpcService {
         LOG.debug("Removing route from DPN. ip {} masklen {}", ipAddress, prefixLength);
         InetAddress destPrefix = null;
         try {
-          destPrefix = InetAddress.getByName(ipAddress);
+            destPrefix = InetAddress.getByName(ipAddress);
         } catch (UnknownHostException e) {
-          LOG.error("UnknowHostException in removeRoute. Failed  to remove Route for ipPrefix {}", ipAddress);
-          return;
+            LOG.error("UnknowHostException in removeRoute. Failed  to remove Route for ipPrefix {}", ipAddress);
+            return;
         }
-        List<MatchInfo> matches = new ArrayList<>();
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
 
         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-            BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
 
         matches.add(new MatchInfo(MatchFieldType.eth_type,
-                                  new long[] { 0x0800L }));
+                new long[] { 0x0800L }));
 
         if(prefixLength != 0) {
             matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
@@ -141,8 +161,8 @@ public class FibRpcServiceImpl implements FibRpcService {
 
         int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
-                                               priority, flowRef, 0, 0,
-                                               COOKIE_VM_FIB_TABLE, matches, null);
+                priority, flowRef, 0, 0,
+                COOKIE_VM_FIB_TABLE, matches, null);
 
         mdsalManager.removeFlow(dpnId, flowEntity);
 
@@ -150,9 +170,9 @@ public class FibRpcServiceImpl implements FibRpcService {
     }
 
     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
-        List<MatchInfo> matches = new ArrayList<>();
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
         matches.add(new MatchInfo(MatchFieldType.eth_type,
-                                  new long[] { 0x8847L }));
+                new long[] { 0x8847L }));
         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
 
         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
@@ -160,8 +180,8 @@ public class FibRpcServiceImpl implements FibRpcService {
         LOG.debug("removing LFib entry with flow ref {}", flowRef);
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
-                                               DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
-                                               COOKIE_VM_LFIB_TABLE, matches, null);
+                DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
+                COOKIE_VM_LFIB_TABLE, matches, null);
 
         mdsalManager.removeFlow(dpnId, flowEntity);
 
@@ -170,27 +190,27 @@ public class FibRpcServiceImpl implements FibRpcService {
 
     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
         LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
-        List<MatchInfo> mkMatches = new ArrayList<>();
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
         // Matching metadata
         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-                                               getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
-                                               5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
-                                               COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+                5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
+                COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
         mdsalManager.removeFlow(dpnId, flowEntity);
         LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
     }
 
     private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
-        List<MatchInfo> mkMatches = new ArrayList<>();
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
 
         LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
 
         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
 
         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-                        getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
-                        0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
+                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
 
         mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
     }
@@ -207,22 +227,22 @@ public class FibRpcServiceImpl implements FibRpcService {
         LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
         InetAddress destPrefix = null;
         try {
-          destPrefix = InetAddress.getByName(ipAddress);
+            destPrefix = InetAddress.getByName(ipAddress);
         } catch (UnknownHostException e) {
-          LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", ipAddress);
-          return;
+            LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", ipAddress);
+            return;
         }
-        List<MatchInfo> matches = new ArrayList<>();
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
 
         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-            BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
+                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
 
         matches.add(new MatchInfo(MatchFieldType.eth_type,
-                                  new long[] { 0x0800L }));
+                new long[] { 0x0800L }));
 
         if(prefixLength != 0) {
-          matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
-             destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
+            matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
+                    destPrefix.getHostAddress(), Integer.toString(prefixLength) }));
         }
 
         String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vpnId, ipAddress);
@@ -230,8 +250,8 @@ public class FibRpcServiceImpl implements FibRpcService {
 
         int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef,
-                                               priority, flowRef, 0, 0,
-                                               COOKIE_VM_FIB_TABLE, matches, customInstructions);
+                priority, flowRef, 0, 0,
+                COOKIE_VM_FIB_TABLE, matches, customInstructions);
 
         mdsalManager.installFlow(dpnId, flowEntity);
 
@@ -239,13 +259,13 @@ public class FibRpcServiceImpl implements FibRpcService {
     }
 
     private void makeLFibTableEntry(BigInteger dpId, long serviceId, List<Instruction> customInstructions) {
-        List<MatchInfo> matches = new ArrayList<>();
+        List<MatchInfo> matches = new ArrayList<MatchInfo>();
         matches.add(new MatchInfo(MatchFieldType.eth_type,
                 new long[] { 0x8847L }));
         matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
 
-        List<Instruction> instructions = new ArrayList<>();
-        List<ActionInfo> actionsInfos = new ArrayList<>();
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
         actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
         Instruction writeInstruction = new InstructionInfo(InstructionType.write_actions, actionsInfos).buildInstruction(0);
         instructions.add(writeInstruction);
@@ -265,8 +285,8 @@ public class FibRpcServiceImpl implements FibRpcService {
 
     private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
         return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-            .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-            .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
+                .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
     }
 
     private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
@@ -276,24 +296,25 @@ public class FibRpcServiceImpl implements FibRpcService {
         String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
         InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
         Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
-        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
-            ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
+        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data
+                .entry.vpn.to.dpn.list.IpAddresses
+                ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
 
         if (dpnInVpn.isPresent()) {
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id.child(
-                org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
-                    .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance
+                            .op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
                     new IpAddressesKey(ipAddr)), ipAddress);
         } else {
             MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL,
-                                    getVpnInstanceOpDataIdentifier(rd),
-                                    getVpnInstanceOpData(rd, vpnId));
+                    getVpnInstanceOpDataIdentifier(rd),
+                    getVpnInstanceOpData(rd, vpnId, vpnName));
             VpnToDpnListBuilder vpnToDpnList = new VpnToDpnListBuilder().setDpnId(dpnId);
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses =  new ArrayList<>();
+                    .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses =  new ArrayList<>();
             ipAddresses.add(ipAddress);
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id,
-                              vpnToDpnList.setIpAddresses(ipAddresses).build());
+                    vpnToDpnList.setIpAddresses(ipAddresses).build());
             LOG.debug("populate FIB on new dpn {} for VPN {}", dpnId, vpnName);
             fibManager.populateFibOnNewDpn(dpnId, vpnId, rd);
         }
@@ -308,7 +329,7 @@ public class FibRpcServiceImpl implements FibRpcService {
         Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
         if (dpnInVpn.isPresent()) {
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
+                    .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses = dpnInVpn.get().getIpAddresses();
             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses
                     ipAddress = new IpAddressesBuilder().setIpAddress(ipAddr).build();
 
@@ -323,8 +344,8 @@ public class FibRpcServiceImpl implements FibRpcService {
                     }
                 } else {
                     delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
-                        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                            .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
+                                    .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
                             new IpAddressesKey(ipAddr)));
                 }
             }
@@ -347,7 +368,7 @@ public class FibRpcServiceImpl implements FibRpcService {
     }
 
     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
-                                                                                         getVpnInstanceToVpnIdIdentifier(String vpnName) {
+    getVpnInstanceToVpnIdIdentifier(String vpnName) {
         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
@@ -356,21 +377,21 @@ public class FibRpcServiceImpl implements FibRpcService {
 
     static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
         return InstanceIdentifier.builder(VpnInstanceOpData.class)
-            .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
-            .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
+                .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
     }
 
     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
         return InstanceIdentifier.builder(VpnInstanceOpData.class)
-            .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
     }
 
-    static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId) {
-        return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).build();
+    static VpnInstanceOpDataEntry getVpnInstanceOpData(String rd, long vpnId, String vpnName) {
+        return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).build();
     }
 
     static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path) {
+                                              InstanceIdentifier<T> path) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
         tx.delete(datastoreType, path);
         tx.submit();
@@ -379,9 +400,9 @@ public class FibRpcServiceImpl implements FibRpcService {
     static long getVpnId(DataBroker broker, String vpnName) {
 
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> id
-            = getVpnInstanceToVpnIdIdentifier(vpnName);
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance> vpnInstance
-            = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+                = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
 
         long vpnId = -1;
         if(vpnInstance.isPresent()) {
@@ -390,4 +411,5 @@ public class FibRpcServiceImpl implements FibRpcService {
         return vpnId;
     }
 
+
 }
index d2803c51fce8e3fa7621dafb66d1b7289a87ab18..c290393373cfe40a95a1c4f2e13619ed25627b7b 100644 (file)
@@ -16,16 +16,31 @@ 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.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
+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.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.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;
@@ -33,13 +48,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
 public class FibUtil {
     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
-    static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                   InstanceIdentifier<T> path) {
+    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+                                                          InstanceIdentifier<T> path) {
 
         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
 
@@ -76,7 +93,8 @@ public class FibUtil {
     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
                 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).augmentation(
-                        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build();
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build();
     }
 
     static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
@@ -87,7 +105,8 @@ public class FibUtil {
 
     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface.class)
-                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class,
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
+                        .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class,
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
     }
 
@@ -96,7 +115,7 @@ public class FibUtil {
                 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).build();
     }
 
-    static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
+    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();
@@ -104,10 +123,23 @@ public class FibUtil {
 
     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute.class)
-                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute.class,
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn
+                        .class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to
+                        .extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
+                        .rev130911.vpn.to.extraroute.vpn.Extraroute.class,
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build();
     }
 
+    static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
+        return InstanceIdentifier.builder(VpnInstanceOpData.class)
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
+    }
+
+    static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
+        return read(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
     static String getNextHopLabelKey(String rd, String prefix){
         String key = rd + FibConstants.SEPARATOR + prefix;
         return key;
@@ -126,17 +158,14 @@ public class FibUtil {
         }
     }
 
-    static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to
-            .vpn.id.VpnInstance>
+    static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
     getVpnInstanceToVpnIdIdentifier(String vpnName) {
         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
-                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
-                .VpnInstance.class,
-                        new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
-                                .VpnInstanceKey(vpnName)).build();
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
     }
 
-    static long getVpnId(DataBroker broker, String vpnName) {
+    public static long getVpnId(DataBroker broker, String vpnName) {
 
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
                 .VpnInstance> id
@@ -152,15 +181,229 @@ public class FibUtil {
         return vpnId;
     }
 
+    /**
+     * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher
+     *
+     * @param broker
+     * @param rd
+     * @return
+     */
+    public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = getVpnInstanceOpData(broker, rd);
+        return Optional.fromNullable(vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get().getVpnInstanceName()
+                : null);
+    }
+
+    static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
+        InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
+
+        Optional<InterVpnLinks> interVpnLinksOpData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
+                interVpnLinksIid);
+
+        return ( interVpnLinksOpData.isPresent() ) ? interVpnLinksOpData.get().getInterVpnLink()
+                : new ArrayList<InterVpnLink>();
+    }
+
+    /**
+     * Returns the instance identifier for a given vpnLinkName
+     *
+     * @param vpnLinkName
+     * @return
+     */
+    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
+     * @param vpnLinkName
+     * @return
+     */
+    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
+     * @param vpnLinkName
+     * @return
+     */
+    public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
+        InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
+        return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
+    }
+
+    /**
+     * Retrieves the InterVpnLink in which the VPN, represented by its Uuid,
+     * participates
+     *
+     * @param dataBroker
+     * @param vpnUuid
+     * @return The InterVpnLink or Optional.absent() if the VPN does not
+     *         participate in an InterVpnLink
+     */
+    public static Optional<InterVpnLink> getInterVpnLinkByVpnUuid(DataBroker dataBroker, String vpnUuid) {
+        List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
+        for (InterVpnLink interVpnLink : interVpnLinkList) {
+            if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
+                    || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid)) {
+                LOG.debug("InterVpnLink found for VPN {}. Details: vpn1=( uuid={} endpoint={})  vpn2=( uuid={} endpoint={} ))",
+                        vpnUuid, interVpnLink.getFirstEndpoint().getVpnUuid(),
+                        interVpnLink.getFirstEndpoint().getIpAddress(), interVpnLink.getSecondEndpoint().getVpnUuid(),
+                        interVpnLink.getSecondEndpoint().getIpAddress());
+                return Optional.fromNullable(interVpnLink);
+            }
+        }
+        LOG.debug("Could not find a suitable InterVpnLink for VpnUuid={}", vpnUuid);
+        return Optional.absent();
+    }
+
+    /**
+     * Retrieves the InterVpnLink in which the VPN, represented by its
+     * Route-Distinguisher, participates.
+     *
+     * @param dataBroker
+     * @param rd
+     * @return The InterVpnLink or Optional.absent() if the VPN does not
+     *         participate in an InterVpnLink
+     */
+    public static Optional<InterVpnLink> getInterVpnLinkByRd(DataBroker dataBroker, String rd) {
+        Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
+        if ( !vpnId.isPresent() ) {
+            LOG.debug("Could not find vpnId for RouteDistinguisher {}", rd);
+            return Optional.absent();
+        }
+
+        return getInterVpnLinkByVpnUuid(dataBroker, vpnId.get());
+    }
+
+    /**
+     * Checks if the route-distinguisher is involved in any inter-vpn-link, which is returned if its found.
+     *
+     * @param dataBroker
+     * @param rd
+     * @return
+     */
+    public static Optional<InterVpnLink> getActiveInterVpnLinkFromRd(DataBroker dataBroker, String rd) {
+
+        Optional<InterVpnLink> interVpnLink = getInterVpnLinkByRd(dataBroker, rd);
+        if ( interVpnLink.isPresent() ) {
+            if ( isInterVpnLinkActive(dataBroker, interVpnLink.get().getName()) ) {
+                return interVpnLink;
+            } else {
+                LOG.warn("InterVpnLink for RouteDistinguisher {} exists, but it's in error state. InterVpnLink={}",
+                        rd, interVpnLink.get().getName());
+                return Optional.absent();
+            }
+        }
+        return Optional.absent();
+    }
+
+    /**
+     * Checks if the route-distinguisher is involved in any inter-vpn-link. In that case, this method will return
+     * the endpoint of the other vpn involved in the inter-vpn-link.
+     *
+     * @param dataBroker
+     * @param rd
+     * @return
+     */
+    public static Optional<String> getInterVpnLinkOppositeEndPointIpAddress(DataBroker dataBroker, String rd) {
+        Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
+        if ( !vpnId.isPresent() ) {
+            LOG.debug("Could not find the VpnName for RouteDistinguisher {}", rd);
+            return Optional.absent();
+        }
+        List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
+        if (!interVpnLinkList.isEmpty()) {
+            for (InterVpnLink interVpnLink : interVpnLinkList) {
+                if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnId)) {
+                    return Optional.fromNullable(interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
+                } else if (interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(vpnId)) {
+                    return Optional.fromNullable(interVpnLink.getFirstEndpoint().getIpAddress().getValue());
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
+    /**
+     * Obtains the route-distinguisher for a given vpn-name
+     *
+     * @param broker
+     * @param vpnName
+     * @return
+     */
+    public static String getVpnRd(DataBroker broker, String vpnName) {
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+                .VpnInstance> id
+                = getVpnInstanceToVpnIdIdentifier(vpnName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+                .VpnInstance> vpnInstance
+                = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+
+        String rd = null;
+        if(vpnInstance.isPresent()) {
+            rd = vpnInstance.get().getVrfId();
+        }
+        return rd;
+    }
+
+    /**
+     * Returns a boolean value which indicates if the endpoint's IP received as parameter belongs to any InterVpnLink.
+     *
+     * @param broker
+     * @param endpointIp IP to serch for.
+     * @return
+     */
+    public static boolean getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
+        List<InterVpnLink> allInterVpnLinks = getAllInterVpnLinks(broker);
+        for (InterVpnLink interVpnLink : allInterVpnLinks) {
+            if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
+                    || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    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);
-                }
+                };
             };
 
 }
index 89d93a9b2b0e7ba33f44fd7353c747281db6a440..9239f61ecc1e917326eff3bb941c58f9e6abbf32 100644 (file)
@@ -27,7 +27,7 @@ public enum L3VPNTransportTypes {
         this.transportType = transportType;
     }
 
-    private static final Map<String, L3VPNTransportTypes> strToTypeMap = new HashMap<>();
+    private static final Map<String, L3VPNTransportTypes> strToTypeMap = new HashMap<String, L3VPNTransportTypes>();
     static {
         for (L3VPNTransportTypes type : L3VPNTransportTypes.values()) {
             strToTypeMap.put(type.transportType, type);
index b4f2917808151342a2f0cd36d6f08004f97b888c..ba7ccbad42562939fb8cefe48272af25b526f909 100644 (file)
@@ -94,25 +94,31 @@ public class NexthopManager implements AutoCloseable {
     private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool";
     private static final long FIXED_DELAY_IN_MILLISECONDS = 4000;
     private L3VPNTransportTypes configuredTransportTypeL3VPN = L3VPNTransportTypes.Invalid;
+    private Long waitTimeForSyncInstall;
 
     private static final FutureCallback<Void> DEFAULT_CALLBACK =
-        new FutureCallback<Void>() {
-            public void onSuccess(Void result) {
-                LOG.debug("Success in Datastore write operation");
-            }
-            public void onFailure(Throwable error) {
-                LOG.error("Error in Datastore write operation", error);
-            }
-        };
+            new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(Void result) {
+                    LOG.debug("Success in Datastore write operation");
+                }
+                @Override
+                public void onFailure(Throwable error) {
+                    LOG.error("Error in Datastore write operation", error);
+                };
+            };
 
     /**
-    * Provides nexthop functions
-    * Creates group ID pool
-    *
-    * @param db - dataBroker reference
-    */
+     * Provides nexthop functions
+     * Creates group ID pool
+     *
+     * @param db - dataBroker reference
+     */
     public NexthopManager(final DataBroker db) {
         broker = db;
+        waitTimeForSyncInstall = Long.getLong("wait.time.sync.install");
+        if (waitTimeForSyncInstall == null)
+            waitTimeForSyncInstall = 1000L;
     }
 
     @Override
@@ -139,10 +145,10 @@ public class NexthopManager implements AutoCloseable {
 
     protected void createNexthopPointerPool() {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
-            .setPoolName(NEXTHOP_ID_POOL_NAME)
-            .setLow(150000L)
-            .setHigh(175000L)
-            .build();
+                .setPoolName(NEXTHOP_ID_POOL_NAME)
+                .setLow(150000L)
+                .setHigh(175000L)
+                .build();
         //TODO: Error handling
         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
         LOG.trace("NextHopPointerPool result : {}", result);
@@ -167,8 +173,8 @@ public class NexthopManager implements AutoCloseable {
 
     protected long createNextHopPointer(String nexthopKey) {
         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
-            .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
-            .build();
+                .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
+                .build();
         //TODO: Proper error handling once IdManager code is complete
         try {
             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
@@ -182,8 +188,8 @@ public class NexthopManager implements AutoCloseable {
 
     protected void removeNextHopPointer(String nexthopKey) {
         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
-                                       setPoolName(NEXTHOP_ID_POOL_NAME)
-                                       .setIdKey(nexthopKey).build();
+                setPoolName(NEXTHOP_ID_POOL_NAME)
+                .setIdKey(nexthopKey).build();
         try {
             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
             RpcResult<Void> rpcResult = result.get();
@@ -196,30 +202,30 @@ public class NexthopManager implements AutoCloseable {
     }
 
     protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
-        List<ActionInfo> listActionInfo = new ArrayList<>();
+        List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
         try {
             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
-                interfaceManager.getEgressActionsForInterface(
-                    new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
+                    interfaceManager.getEgressActionsForInterface(
+                            new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
             if(!rpcResult.isSuccessful()) {
                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
             } else {
                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
-                    rpcResult.getResult().getAction();
+                        rpcResult.getResult().getAction();
                 for (Action action : actions) {
                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
                     if (actionClass instanceof OutputActionCase) {
                         listActionInfo.add(new ActionInfo(ActionType.output,
-                                                          new String[] {((OutputActionCase)actionClass).getOutputAction()
-                                                                            .getOutputNodeConnector().getValue()}));
+                                new String[] {((OutputActionCase)actionClass).getOutputAction()
+                                        .getOutputNodeConnector().getValue()}));
                     } else if (actionClass instanceof PushVlanActionCase) {
                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
                     } else if (actionClass instanceof SetFieldCase) {
                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
-                                                              new String[] { Long.toString(vlanVid) }));
+                                    new String[] { Long.toString(vlanVid) }));
                         }
                     }
                 }
@@ -232,11 +238,13 @@ public class NexthopManager implements AutoCloseable {
 
     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
+        Future<RpcResult<GetTunnelInterfaceNameOutput>> result;
         try {
-            Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
-                                                                                 .setSourceDpid(srcDpId)
-                                                                                 .setDestinationDpid(dstDpId)
-                                                                                .setTunnelType(tunType).build());
+            result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
+                    .setSourceDpid(srcDpId)
+                    .setDestinationDpid(dstDpId)
+                    .setTunnelType(tunType)
+                    .build());
             RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
             if(!rpcResult.isSuccessful()) {
                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
@@ -246,17 +254,20 @@ public class NexthopManager implements AutoCloseable {
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId, e);
         }
-        
         return null;
     }
 
-    protected String getTunnelInterfaceName(BigInteger srcDpId, IpAddress dstIp) {
+
+
+    protected String getTunnelInterfaceName(BigInteger srcDpId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress dstIp) {
         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
+        Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result;
         try {
-            Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
-                                                                                 .setSourceDpid(srcDpId)
-                                                                                 .setDestinationIp(dstIp)
-                                                                                .setTunnelType(tunType).build());
+            result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
+                    .setSourceDpid(srcDpId)
+                    .setDestinationIp(dstIp)
+                    .setTunnelType(tunType)
+                    .build());
             RpcResult<GetInternalOrExternalInterfaceNameOutput> rpcResult = result.get();
             if(!rpcResult.isSuccessful()) {
                 LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors());
@@ -266,7 +277,6 @@ public class NexthopManager implements AutoCloseable {
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstIp, e);
         }
-        
         return null;
     }
 
@@ -276,12 +286,13 @@ public class NexthopManager implements AutoCloseable {
         String nextHopLockStr = new String(vpnId + ipAddress);
         synchronized (nextHopLockStr.intern()) {
             VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
-            LOG.trace("nexthop: {}", nexthop);
+            LOG.trace("nexthop: {} retrieved for vpnId {}, prefix {}, ifName {} on dpn {}", nexthop,
+                    vpnId, ipAddress, ifName, dpnId);
             if (nexthop == null) {
                 Optional<Adjacency> adjacencyData =
                         read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress));
                 String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
-                List<BucketInfo> listBucketInfo = new ArrayList<>();
+                List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
                 List<ActionInfo> listActionInfo = getEgressActionsForInterface(ifName);
                 BucketInfo bucket = new BucketInfo(listActionInfo);
                 // MAC re-write
@@ -294,13 +305,20 @@ public class NexthopManager implements AutoCloseable {
                 }
                 listBucketInfo.add(bucket);
                 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
-                        dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
-
-                //update MD-SAL DS
-                addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
+                        dpnId, groupId, ipAddress, GroupTypes.GroupAll, listBucketInfo);
+                LOG.trace("Install LNH Group: id {}, mac address {}, interface {} for prefix {}", groupId, macAddress, ifName, ipAddress);
 
                 // install Group
                 mdsalManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS);
+                try{
+                    LOG.info("Sleeping for {} to wait for the groups to get programmed.", waitTimeForSyncInstall);
+                    Thread.sleep(waitTimeForSyncInstall);
+                }catch(InterruptedException error){
+                    LOG.warn("Error while waiting for group {} to install.", groupId);
+                    LOG.debug("{}", error);
+                }
+                //update MD-SAL DS
+                addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
 
             } else {
                 //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1
@@ -318,7 +336,7 @@ public class NexthopManager implements AutoCloseable {
     protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) {
 
         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
-            L3nexthop.class)
+                L3nexthop.class)
                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
 
         // Add nexthop to vpn node
@@ -349,8 +367,8 @@ public class NexthopManager implements AutoCloseable {
 
         // check if vpn node is there
         InstanceIdentifierBuilder<VpnNexthops> idBuilder =
-            InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
-                                                              new VpnNexthopsKey(vpnId));
+                InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
+                        new VpnNexthopsKey(vpnId));
         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
         Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
         if (vpnNexthops.isPresent()) {
@@ -369,19 +387,18 @@ public class NexthopManager implements AutoCloseable {
     }
 
 
-    public String getRemoteNextHopPointer(BigInteger localDpnId, BigInteger remoteDpnId,
-                                                    long vpnId, String prefixIp, String nextHopIp) {
+    public String getRemoteNextHopPointer(BigInteger remoteDpnId, long vpnId, String prefixIp, String nextHopIp) {
         String tunnelIfName = null;
-        LOG.trace("getRemoteNextHopPointer: input [localDpnId {} remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]",
-                  localDpnId, remoteDpnId, vpnId, prefixIp, nextHopIp);
+        LOG.trace("getRemoteNextHopPointer: input [remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]",
+                remoteDpnId, vpnId, prefixIp, nextHopIp);
 
-        LOG.trace("getRemoteNextHopPointer: Calling ITM with localDpnId {} ", localDpnId);
         if (nextHopIp != null && !nextHopIp.isEmpty()) {
             try{
                 // here use the config for tunnel type param
-                tunnelIfName = getTunnelInterfaceName(remoteDpnId, IpAddressBuilder.getDefaultInstance(nextHopIp));
-            }catch(Exception ex){
-            LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage());
+                tunnelIfName = getTunnelInterfaceName(remoteDpnId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
+                        .ns.yang.ietf.inet.types.rev130715.IpAddressBuilder.getDefaultInstance(nextHopIp));
+            } catch(Exception ex){
+                LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage());
             }
         }
         return tunnelIfName;
@@ -405,7 +422,7 @@ public class NexthopManager implements AutoCloseable {
         delete(LogicalDatastoreType.OPERATIONAL, id);
     }
 
+
     public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
 
         String nextHopLockStr = new String(vpnId + ipAddress);
@@ -415,14 +432,14 @@ public class NexthopManager implements AutoCloseable {
                 int newFlowrefCnt = nh.getFlowrefCount() - 1;
                 if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group
                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
-                            dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
+                            dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupAll, null);
                     // remove Group ...
                     mdsalManager.removeGroup(groupEntity);
                     //update MD-SAL DS
                     removeVpnNexthopFromDS(vpnId, ipAddress);
                     //release groupId
                     removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
-                    LOG.debug("Local Next hop for {} on dpn {} successfully deleted", ipAddress, dpnId);
+                    LOG.debug("Local Next hop {} for {} {} on dpn {} successfully deleted", nh.getEgressPointer(), vpnId, ipAddress, dpnId);
                 } else {
                     //just update the flowrefCount of the vpnNexthop
                     VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build();
@@ -439,7 +456,7 @@ public class NexthopManager implements AutoCloseable {
 
 
     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path) {
+                                                    InstanceIdentifier<T> path) {
 
         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
 
@@ -454,14 +471,14 @@ public class NexthopManager implements AutoCloseable {
     }
 
     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+                                                   InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
         tx.merge(datastoreType, path, data, true);
         Futures.addCallback(tx.submit(), callback);
     }
 
     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
+                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
         tx.merge(datastoreType, path, data, true);
         tx.submit();
@@ -475,8 +492,8 @@ public class NexthopManager implements AutoCloseable {
 
     private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
         return InstanceIdentifier.builder(VpnInterfaces.class)
-            .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
-                Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
+                .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
+                        Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
     }
 
     InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
@@ -485,7 +502,6 @@ public class NexthopManager implements AutoCloseable {
                         Adjacencies.class).build();
     }
 
-
     public void setConfTransType(String service,String transportType) {
 
         if (!service.toUpperCase().equals("L3VPN")) {
@@ -557,7 +573,7 @@ public class NexthopManager implements AutoCloseable {
         return  confTransType;
     }
 
-    Class<? extends TunnelTypeBase> getReqTunType(String transportType) {
+    public Class<? extends TunnelTypeBase> getReqTunType(String transportType) {
         if (transportType.equals("VXLAN")) {
             return TunnelTypeVxlan.class;
         } else if (transportType.equals("GRE")) {
@@ -566,4 +582,16 @@ public class NexthopManager implements AutoCloseable {
             return TunnelTypeMplsOverGre.class;
         }
     }
+
+    public String getTransportTypeStr ( String tunType) {
+        if (tunType.equals(TunnelTypeVxlan.class.toString())) {
+            return ITMConstants.TUNNEL_TYPE_VXLAN;
+        } else if (tunType.equals(TunnelTypeGre.class.toString())) {
+            return ITMConstants.TUNNEL_TYPE_GRE;
+        } else if (tunType.equals(TunnelTypeMplsOverGre.class.toString())){
+            return ITMConstants.TUNNEL_TYPE_MPLS_OVER_GRE;
+        } else {
+            return ITMConstants.TUNNEL_TYPE_INVALID;
+        }
+    }
 }
index 90565b64be377021a186b1eff65e05ca16a6a77d..5364660ec03ef44d805261ef064993da25bcec88 100644 (file)
@@ -16,6 +16,7 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.junit.runner.RunWith;
@@ -27,6 +28,7 @@ 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.netvirt.bgpmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
 import org.opendaylight.netvirt.fibmanager.FibManager;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
@@ -72,18 +74,21 @@ public class FibManagerTest {
   VrfEntry vrfEntry;
   InstanceIdentifier<VrfEntry> identifier;
   VrfEntryBuilder vrfbuilder;
+  private static final String testVpnInstanceName = "95486250-4ad7-418f-9030-2df37f98ad24";
   private static final String testRd = "100:1";
   private static final String prefix = "1.1.2.3";
   private static final String nexthop = "1.1.1.1";
   private static final int label = 10;
+  RouteOrigin origin = RouteOrigin.STATIC;
   BigInteger Dpn;
   private static final long vpnId = 101L;
   private static final long vpnIntfCnt = 2;
+  private static final Boolean isCleanupComplete = Boolean.FALSE;
 
   private void SetupMocks() {
     Dpn = BigInteger.valueOf(100000L);
     identifier = buildVrfEntryId(testRd, prefix);
-    vrfEntry = buildVrfEntry(testRd, prefix, nexthop, label);
+    vrfEntry = buildVrfEntry(testRd, prefix, Arrays.asList(nexthop), label, origin);
     fibmgr.setMdsalManager(mdsalManager);
     fibmgr.setVpnmanager(vpnmanager);
     when(vrfTableKey.getRouteDistinguisher()).thenReturn(testRd);
@@ -92,13 +97,14 @@ public class FibManagerTest {
   @Before
   public void setUp() throws Exception {
     when(
-        dataBroker.registerDataChangeListener(any(LogicalDatastoreType.class),
-            any(InstanceIdentifier.class), any(DataChangeListener.class),
-            any(DataChangeScope.class))).thenReturn(dataChangeListenerRegistration);
+            dataBroker.registerDataChangeListener(any(LogicalDatastoreType.class),
+                    any(InstanceIdentifier.class), any(DataChangeListener.class),
+                    any(DataChangeScope.class))).thenReturn(dataChangeListenerRegistration);
     dataChangeEvent = new MockDataChangedEvent();
     vrfbuilder = new VrfEntryBuilder();
     fibmgr = new FibManager(dataBroker) {
 
+      @Override
       protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
         return new VpnInstanceOpDataEntry() {
 
@@ -117,9 +123,17 @@ public class FibManagerTest {
             return testRd;
           }
 
+          @Override
+          public String getVpnInstanceName() {
+            return testVpnInstanceName;
+          }
+
           @Override
           public Long getVpnInterfaceCount() { return vpnIntfCnt; }
 
+          @Override
+          public Boolean isCleanupComplete(){return isCleanupComplete;}
+
           @Override
           public List<VpnToDpnList> getVpnToDpnList() {
             List <VpnToDpnList> vpnToDpnLists =  new ArrayList<>();
@@ -144,7 +158,7 @@ public class FibManagerTest {
 
               @Override
               public <E extends Augmentation<VpnToDpnList>> E getAugmentation(
-                  Class<E> augmentationType) {
+                      Class<E> augmentationType) {
                 return null;
               }
 
@@ -183,23 +197,24 @@ public class FibManagerTest {
     //Mockito.verify(mdsalManager, Mockito.times(2)).installFlow(any(FlowEntity.class));
   }
 
-  private VrfEntry buildVrfEntry(String rd, String prefix, String nexthop, int label) {
-    return new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddress(nexthop)
-        .setLabel((long) label).build();
+  private VrfEntry buildVrfEntry(String rd, String prefix, List<String> nextHopList, int label, RouteOrigin origin) {
+
+    return new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(nextHopList)
+            .setLabel((long) label).setOrigin(origin.getValue()).build();
   }
 
   public static InstanceIdentifier<VrfTables> buildVrfTableId(String rd) {
     InstanceIdentifierBuilder<VrfTables> idBuilder =
-        InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
+            InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
     InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
     return vrfTableId;
   }
 
   public static InstanceIdentifier<VrfEntry> buildVrfEntryId(String rd, String prefix) {
     InstanceIdentifierBuilder<VrfEntry> idBuilder =
-        InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
-            .child(VrfEntry.class, new VrfEntryKey(prefix));
+            InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
+                    .child(VrfEntry.class, new VrfEntryKey(prefix));
     InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
     return vrfEntryId;
   }
-}
+}
\ No newline at end of file
index 119da723472ac65dd19f29e4d9738d2af9287f07..bf8688a43cc568129f8fbfc936ed1dd2d365cab2 100644 (file)
@@ -14,7 +14,7 @@ import org.opendaylight.netvirt.fibmanager.L3VPNTransportTypes;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 
 @Command(scope = "vpnservice", name = "configureTransportType", description = "Configure Preferred Transport Type for L3VPN service")
-public class confTransportL3VPNCommand  extends OsgiCommandSupport {
+public class confTransportL3VPNCommand extends OsgiCommandSupport {
     private IFibManager fibManager;
 
     @Option(name = "-s", aliases = {"--service"}, description = "Service", required = false, multiValued = false)
@@ -42,7 +42,7 @@ public class confTransportL3VPNCommand  extends OsgiCommandSupport {
             return null;
         }
 
-        String cachedTransType = fibManager.getReqTransType();
+        String cachedTransType = fibManager.getConfTransType();
         if (cachedTransType.equals(transportType.toUpperCase())) {
             System.out.println("Transport type already configured as " + cachedTransType);
             return null;
@@ -51,7 +51,6 @@ public class confTransportL3VPNCommand  extends OsgiCommandSupport {
         if ((cachedTransType.equals(L3VPNTransportTypes.Invalid.getTransportType())) ||
                 (!fibManager.isVPNConfigured())) {
             fibManager.setConfTransType(service, transportType.toUpperCase());
-            System.out.println("Setting it to " + transportType.toUpperCase() + "writing into the config DS as well.");
             fibManager.writeConfTransTypeConfigDS();
         } else {
             System.out.println( "VPN service already configured with " + cachedTransType +
@@ -60,4 +59,6 @@ public class confTransportL3VPNCommand  extends OsgiCommandSupport {
         }
         return null;
     }
-}
+
+
+}
\ No newline at end of file
diff --git a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/inter-vpn-link.yang
new file mode 100644 (file)
index 0000000..0639588
--- /dev/null
@@ -0,0 +1,122 @@
+module inter-vpn-link {
+
+  namespace "urn:opendaylight:params:xml:ns:yang:netvirt:inter-vpn-link";
+  prefix "inter-vpn-link";
+
+  import ietf-inet-types { prefix inet; revision-date "2013-07-15"; }
+
+  import ietf-yang-types { prefix yang; }
+
+  import config { prefix config; revision-date 2013-04-05; }
+
+  description
+    "Service definition for inter-vpn-link project";
+
+  revision "2016-03-11" {
+      description
+        "Initial revision";
+    }
+
+  grouping vpn-endpoint-attribs {
+      leaf vpn-uuid {
+          mandatory "true";
+          type yang:uuid;
+          description "UUID of the VPN to which this endpoint belongs to";
+      }
+
+      leaf ip-address {
+          mandatory "true";
+          type inet:ipv4-address;
+          description "IP address of the endpoint";
+       }
+  }
+
+
+  grouping vpn-endpoint-state-attribs {
+      leaf vpn-uuid {
+          type yang:uuid;
+          description "UUID of the VPN to which this endpoint belongs to";
+      }
+
+      leaf-list dp-id {
+          type uint64;
+
+          description "list of DPNs where this endpoint of the Link has been instantiated";
+      }
+
+      leaf lport-tag {
+          type uint16;
+
+      }
+  }
+
+  container inter-vpn-links {
+      list inter-vpn-link {
+          key "name";
+          max-elements "unbounded";
+          min-elements "0";
+
+          leaf name {
+              mandatory "true";
+              type string;
+              description "Inter VPN link name";
+          }
+
+
+          container first-endpoint {
+              uses vpn-endpoint-attribs;
+          }
+
+         container second-endpoint {
+              uses vpn-endpoint-attribs;
+          }
+
+          leaf bgp-routes-leaking {
+              mandatory "true";
+              type boolean;
+              description "Flag to enable the leaking of BGP routes learnt from one VPN to another VPN";
+          }
+
+          must "first-endpoint and second-endpoint";  // To ensure both endpoints are present
+      }
+  }
+
+  container inter-vpn-link-states {
+      list inter-vpn-link-state {
+          key "inter-vpn-link-name";
+
+          leaf inter-vpn-link-name {
+              type string;
+          }
+
+          leaf state {
+              type enumeration {
+                  enum active;
+                  enum error;
+              }
+              description "Holds the current state of the InterVPN Link";
+          }
+
+          container first-endpoint-state {
+              uses vpn-endpoint-state-attribs;
+          }
+
+          container second-endpoint-state {
+              uses vpn-endpoint-state-attribs;
+          }
+
+          leaf error-description {
+              type string;
+          }
+       }
+   }
+
+  notification inter-vpn-link-creation-error {
+      container inter-vpn-link-creation-error-message {
+          leaf error-message {
+              type "string";
+          }
+      }
+  }
+
+}
index 76dc9af1e38dad2b8c684c2650ab8f4405146cb5..cec1e7c5abcf343ad1aaa350f3c3d9bbfaf63b06 100644 (file)
@@ -102,6 +102,9 @@ module odl-l3vpn {
         list vpn-instance-op-data-entry {
            key vrf-id;
            leaf vpn-id { type uint32;}
+           leaf vpn-instance-name {
+              type string;
+           }
            leaf vrf-id {
               description
                  "The vrf-id command configures a route distinguisher (RD)
@@ -130,6 +133,7 @@ module odl-l3vpn {
                   }
                }
            }
+           leaf cleanup_complete { type boolean;}
         }
     }
 
index cd0ab785fd239c3809e4600160d96715cffe9754..d7dea34601140411fe58204032496f209e0d8e42 100644 (file)
@@ -57,10 +57,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 
 import java.math.BigInteger;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
-import java.util.concurrent.*;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 
 import com.google.common.base.Optional;
 
@@ -741,7 +746,7 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
             String nexthop, int label) {
 
         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
-                    setNextHopAddress(nexthop).setLabel((long)label).build();
+                    setNextHopAddressList(Arrays.asList(nexthop)).setLabel((long)label).build();
         LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nexthop, label);
 
         List<VrfEntry> vrfEntryList = new ArrayList<>();
@@ -763,7 +768,8 @@ public class VpnInterfaceManager extends AbstractDataChangeListener<VpnInterface
         SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
 
         VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).
-                setNextHopAddress(nexthop).setLabel((long)label).addAugmentation(SubnetRoute.class,route).build();
+                setNextHopAddressList(Arrays.asList(nexthop)).setLabel((long)label).addAugmentation(SubnetRoute
+                .class,route).build();
         LOG.debug("Created vrfEntry for {} nexthop {} label {} and elantag {}", prefix, nexthop, label, elantag);
 
         List<VrfEntry> vrfEntryList = new ArrayList<VrfEntry>();