Bug 6786: L3VPN is not honoring VTEP add or delete in operational cloud 03/48603/8
authorehvkand <hanamantagoud.v.kandagal@ericsson.com>
Mon, 21 Nov 2016 06:03:15 +0000 (11:33 +0530)
committerHANAMANTAGOUD V Kandagal <hanamantagoud.v.kandagal@ericsson.com>
Mon, 28 Nov 2016 16:32:26 +0000 (22:02 +0530)
As part of making L3VPN honor VTEP add-delete operation , this is a third
set of changes.

This code review contains following fixes :

1. When tunnel UP event is received upon TEP add , VpnInterfaces Adj and
VRF entry is updated as a part of DJC. There exists a race condition
between DJC and populateInternalRoutesOnDpn . In
populateInternalRoutesOnDpn , if remote NH list is empty , remote route is
not populated. With the fix , handleRemoteRoute is called with
updateVpnInterfaceOnTepAdd method to populate the route on remote DPN.

2. When tunnel EP is deleted on a DPN , VPN gets two deletion event. One
for a DPN on which tunnel EP was deleted and another for other-end DPN.
Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
Dont update the adj for vpninterfaces for a DPN on which TEP is not
deleted. DPN on which TEP is deleted , endpoint IP will be null.

3. When tep is added on a DPN , tunnelinterfacestatechange listener gets
event with srcDpn , destDpn. When a FIB entries of srcDpn are being
programmed on destDpn , get egress action failed because tunnel interface
on destDPN may not be created yet. Hence FIB entry creation logic is
modified. FIB entries of destDPN are populated on srcDpn.

4. When TEP is deleted on DPN1 , 2 TEP delete events are received. One for
a DPN1 and another for DPN2. For DPN2 , TEP configuration is intact , but
tunnel is down. Only VRF entries of prefixes on DPN1 will be modified.

Change-Id: I4f9dc18f211464dc80874c944f5c200622a3feb3
Signed-off-by: HANAMANTAGOUD V Kandagal <hanamantagoud.v.kandagal@ericsson.com>
Signed-off-by: ehvkand <hanamantagoud.v.kandagal@ericsson.com>
Signed-off-by: HANAMANTAGOUD V Kandagal <hanamantagoud.v.kandagal@ericsson.com>
vpnservice/fibmanager/fibmanager-api/src/main/java/org/opendaylight/netvirt/fibmanager/api/IFibManager.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibManagerImpl.java
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/TunnelInterfaceStateListener.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java
vpnservice/vpnmanager/vpnmanager-impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnSubnetRouteHandler.java

index 836842086ec7632c1280b93d5179aabcfc82b479..e98e82f81ee06311042c3c136ee010ac78600b49 100644 (file)
@@ -39,12 +39,13 @@ public interface IFibManager {
     void writeConfTransTypeConfigDS();
     String getReqTransType();
     String getTransportTypeStr(String tunType);
-    void handleRemoteRoute(boolean action, BigInteger localDpnId,
-                           BigInteger remoteDpnId, long vpnId,
-                           String rd, String destPrefix,
-                           String localNextHopIp,
-                           String remoteNextHopIP);
 
+    void manageRemoteRouteOnDPN(final boolean action,
+                                BigInteger localDpnId,
+                                long vpnId,
+                                String  rd,
+                                String destPrefix,
+                                String destTepIp);
 
     void addOrUpdateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
                              int label, RouteOrigin origin, WriteTransaction writeConfigTxn);
index b8c159628fd7d39f23f487d9c82df81ef001a3ea..c02ba0498cf97f0fbac6139343c2137b37711c04 100755 (executable)
@@ -139,11 +139,13 @@ public class FibManagerImpl implements IFibManager {
     }
 
     @Override
-    public void handleRemoteRoute(boolean action, BigInteger localDpnId, BigInteger remoteDpnId,
-                                  long vpnId, String rd, String destPrefix, String localNextHopIp,
-                                  String remoteNextHopIP) {
-        vrfEntryListener.handleRemoteRoute(action, localDpnId, remoteDpnId, vpnId, rd, destPrefix,
-                localNextHopIp, remoteNextHopIP);
+    public void manageRemoteRouteOnDPN(boolean action,
+                                       BigInteger DpnId,
+                                       long vpnId,
+                                       String  rd,
+                                       String destPrefix,
+                                       String destTepIp) {
+        vrfEntryListener.manageRemoteRouteOnDPN(action, DpnId, vpnId,rd, destPrefix, destTepIp);
     }
 
     @Override
index c258ae0f206d8bd535b6ec98e447e20dccf9c5f4..8ca1a0eeb04855f14e782c9dc496fb8d0eac2245 100755 (executable)
@@ -265,6 +265,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                         (updateNhList != null) && (!updateNhList.isEmpty()))) {
                     // TODO(vivek): Though ugly, Not handling this code now, as each
                     // tep add event will invoke flow addition
+                    LOG.trace("Original VRF entry NH is null for destprefix {}. This event is IGNORED here.", update.getDestPrefix());
                     return;
                 }
 
@@ -272,36 +273,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 // has nexthop empty'ed out, route needs to be removed from remote Dpns
                 if (((updateNhList == null) || (updateNhList.isEmpty()) &&
                         (origNhList != null) && (!origNhList.isEmpty()))) {
-
-                    final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
-                    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 List<BigInteger> localDpnIdList = getDpnIdForPrefix(dataBroker, vpnId, rd, update);
-
-                    if (vpnToDpnList != null) {
-                        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                        dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + update.getDestPrefix(),
-                                new Callable<List<ListenableFuture<Void>>>() {
-                                    @Override
-                                    public List<ListenableFuture<Void>> call() throws Exception {
-                                        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-                                        for (VpnToDpnList vpnDpn : vpnToDpnList) {
-                                            // delete subnet route on all dpns if nexthop for subnetroute changed from null
-                                            // to a valid value.
-                                            if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
-                                                deleteRemoteRoute(BigInteger.ZERO, vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, update, tx);
-                                            }
-                                        }
-                                        List<ListenableFuture<Void>> futures = new ArrayList<>();
-                                        futures.add(tx.submit());
-                                        return futures;
-                                    }
-                                });
-                    }
+                    LOG.trace("Original VRF entry had valid NH for destprefix {}. This event is IGNORED here.", update.getDestPrefix());
                     return;
                 }
             }
@@ -375,7 +347,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     rd, vrfEntry.getDestPrefix(), elanTag);
             if (vpnToDpnList != null) {
                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+                dataStoreCoordinator.enqueueJob("FIB-"+ rd.toString() + "-" + vrfEntry.getDestPrefix(),
                         new Callable<List<ListenableFuture<Void>>>() {
                             @Override
                             public List<ListenableFuture<Void>> call() throws Exception {
@@ -408,7 +380,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
 
         if (vpnToDpnList != null) {
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+            dataStoreCoordinator.enqueueJob("FIB-"+ rd.toString() + "-" + vrfEntry.getDestPrefix(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -879,7 +851,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. LFib and Terminating table entries will not be created.", rd, vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpnId);
             }
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
+            dataStoreCoordinator.enqueueJob("FIB-"+ vpnId.toString() + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -1066,7 +1038,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         if (localNextHopInfo != null) {
             final BigInteger dpnId = localNextHopInfo.getDpnId();;
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
+            dataStoreCoordinator.enqueueJob("FIB-"+ vpnId.toString() + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -1129,8 +1101,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
             tx = dataBroker.newWriteOnlyTransaction();
         }
         String rd = vrfTableKey.getRouteDistinguisher();
-        LOG.debug(  "createremotefibentry: adding route {} for rd {} with transaction {}",
-                vrfEntry.getDestPrefix(), rd, tx);
+        LOG.debug(  "createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
+                vrfEntry.getDestPrefix(), rd, remoteDpnId);
         /********************************************/
         List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
 
@@ -1395,7 +1367,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                     rd, vrfEntry.getDestPrefix(), elanTag);
             if (vpnToDpnList != null) {
                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-                dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
+                dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
                         new Callable<List<ListenableFuture<Void>>>() {
                             @Override
                             public List<ListenableFuture<Void>> call() throws Exception {
@@ -1449,7 +1421,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                 vrfTableKey.getRouteDistinguisher(), vrfEntry);
         if (vpnToDpnList != null) {
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
+            dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -1885,24 +1857,20 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         }
     }
 
-    public void handleRemoteRoute(final boolean action, final BigInteger localDpnId, final BigInteger remoteDpnId,
-                                  final long vpnId, final String  rd, final String destPrefix ,
-                                  final String localNextHopIP, final String remoteNextHopIp) {
-
+    public void manageRemoteRouteOnDPN(final boolean action,
+                                       final BigInteger localDpnId,
+                                       final long vpnId,
+                                       final String  rd,
+                                       final String destPrefix,
+                                       final String destTepIp) {
         final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
 
         if (vpnInstance == null) {
-            LOG.error("VpnInstance for rd {} not present for handleRemoteRoute for prefix {}", rd, destPrefix);
+            LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
             return;
         }
-
         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-        dataStoreCoordinator.enqueueJob(  "FIB" + rd.toString()
-                        + "local dpid" + localDpnId
-                        + "remote dpid" + remoteDpnId
-                        + "vpnId" + vpnId
-                        + "localNHIp" + localNextHopIP
-                        + "remoteNHIp" + remoteNextHopIp,
+        dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
                 new Callable<List<ListenableFuture<Void>>>() {
                     @Override
                     public List<ListenableFuture<Void>> call() throws Exception {
@@ -1913,15 +1881,24 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                             VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
                             if (vrfEntry == null)
                                 return futures;
-                            LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
-                                            "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
-                                    action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
+                            LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
+                                    action, localDpnId, vpnId, rd, destPrefix);
+                            List<String> nhList = new ArrayList<String>();
+                            List<String> nextHopAddressList = vrfEntry.getNextHopAddressList();
+                            VrfEntry modVrfEntry;
+                            if (nextHopAddressList == null || (nextHopAddressList.isEmpty())) {
+                                nhList = Arrays.asList(destTepIp);
+                                modVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(nhList).build();
+                            } else {
+                                modVrfEntry = vrfEntry;
+                            }
+
                             if (action == true) {
-                                LOG.trace("handleRemoteRoute updated(add)  vrfEntry :: {}", vrfEntry);
-                                createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
+                                LOG.trace("manageRemoteRouteOnDPN updated(add)  vrfEntry :: {}", modVrfEntry);
+                                createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
                             } else {
-                                LOG.trace("handleRemoteRoute updated(remove)  vrfEntry :: {}", vrfEntry);
-                                deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
+                                LOG.trace("manageRemoteRouteOnDPN updated(remove)  vrfEntry :: {}", modVrfEntry);
+                                deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
                             }
                             futures.add(writeTransaction.submit());
                         }
@@ -1993,7 +1970,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
         if (vrfTable.isPresent()) {
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
+            dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -2028,7 +2005,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
         if (vrfTable.isPresent()) {
             DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
+            dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
                     new Callable<List<ListenableFuture<Void>>>() {
                         @Override
                         public List<ListenableFuture<Void>> call() throws Exception {
@@ -2090,7 +2067,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                             final VrfEntry vrfEntry, String rd) {
         List<AdjacencyResult> adjacencyList = new ArrayList<>();
         List<String> prefixIpList = new ArrayList<>();
-        LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}",
+        LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
                 remoteDpnId, vpnId, vrfEntry);
         try {
             if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
index 368e821f7eca4529cae9c0e1a695dbb901af79c1..a30217a30583d76aa4df7ed17ae294a2283a0e17 100644 (file)
@@ -407,13 +407,4 @@ module odl-l3vpn {
             leaf router-name { type string; }
         }
     }
-
-    container dpn-to-vtep-map {
-        config false;
-        list dpn-to-vtep {
-            key dpnId;
-            leaf dpnId { type uint64;}
-            leaf vtepip { type string; }
-        }
-    }
 }
index cc00c9b96865afcba03bd83370d6a7ea712796bb..a4886c57c24b5066fcbda357e8fe94142cda0505 100644 (file)
@@ -40,12 +40,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.I
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpnToVtepMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
 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.dpn.to.vtep.map.DpnToVtep;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.to.vtep.map.DpnToVtepBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.to.vtep.map.DpnToVtepKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
@@ -163,6 +159,10 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
         final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
         String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
+        String rd;
+        BigInteger remoteDpnId = null;
+        boolean isTepDeletedOnDpn = false;
+
         LOG.trace("Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp, destTepIp);
         int tunTypeVal = getTunnelType(stateTunnelList);
 
@@ -170,33 +170,14 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
 
         try {
             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
-                // Maintain a Dpn-To-Vtep Op DS to avoid repeatedly calling updateVpnInterfaceOnTepAdd
-                // method for every tunnel-add event sent by ITM when TEP is added.
-                // Since TEP is common for all the (N-1) tunnels for a given Dpn , no need to update
-                // the VpnInterface Adj NextHop for every tunnel event.
-                InstanceIdentifier<DpnToVtep> DpnToVtepId =
-                        InstanceIdentifier.builder(DpnToVtepMap.class).child(DpnToVtep.class, new DpnToVtepKey(srcDpnId)).build();
-                Optional<DpnToVtep> entry = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, DpnToVtepId);
-
-                if (entry.isPresent()) {
-                    String vtepIp = entry.get().getVtepip();
-                    if (!vtepIp.equals(srcTepIp)) {
-                        // Entry found for DpnId. Unlikely to hit this code.
-                        LOG.error (" Tunnel ADD event already received for Dpn {} with a changed VTEP IP {}", srcDpnId, srcTepIp);
-                        return;
-                    }
-                } else {
-                    LOG.trace(" Tunnel ADD event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
-                    // Entry not found. Create the entry for the DpnId
-                    DpnToVtepBuilder dpnToVtepBuilder = new DpnToVtepBuilder().setKey(new DpnToVtepKey(srcDpnId)).setVtepip(srcTepIp);
-                    VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, DpnToVtepId, dpnToVtepBuilder.build());
-                }
+                LOG.trace(" Tunnel ADD event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
             } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
-
+                LOG.trace(" Tunnel DELETE event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
                 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
                 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
-                // Handle only the DPN on which it was deleted , ignore other event.
-                // DPN on which TEP is deleted , endpoint IP will be null.
+                // Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
+                // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted.
+                // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted.
                 String endpointIpForDPN = null;
                 try {
                     endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
@@ -205,50 +186,49 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                     endpointIpForDPN = null;
                 }
 
-                if (endpointIpForDPN != null) {
-                    LOG.trace("Ignore Tunnel DELETE event received for Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
-                    return;
-                }
-
-                InstanceIdentifier<DpnToVtep> DpnToVtepId =
-                        InstanceIdentifier.builder(DpnToVtepMap.class).child(DpnToVtep.class, new DpnToVtepKey(srcDpnId)).build();
-                Optional<DpnToVtep> entry = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, DpnToVtepId);
-                if (entry.isPresent()) {
-                    String vtepIp = entry.get().getVtepip();
-                    if (vtepIp.equals(srcTepIp)) {
-                        LOG.trace(" Tunnel DELETE event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
-                        // Entry found for DpnId. Delete the entry.
-                        VpnUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, DpnToVtepId);
-                    } else {
-                        // Unlikely to hit this condition
-                        LOG.error(" Tunnel DELETE event received for Dpn {} with different VTEP Ip {} than expected VTEP Ip {}", srcDpnId, srcTepIp, vtepIp);
-                        return;
-                    }
-                } else {
-                    LOG.trace(" Tunnel DELETE event already received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
+                if (endpointIpForDPN == null) {
+                    LOG.trace("Tunnel TEP is deleted on Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
+                    isTepDeletedOnDpn = true;
                 }
             }
 
-            // Get the list of VpnInterfaces from Intf Mgr for a given DPN.
+            // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted
             Future<RpcResult<GetDpnInterfaceListOutput>> result;
-            List<String> interfacelist = new ArrayList<>();
+            List<String> srcDpninterfacelist = new ArrayList<>();
+            List<String> destDpninterfacelist = new ArrayList<>();
             try {
                 result = intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build());
                 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
                 if (!rpcResult.isSuccessful()) {
                     LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId, rpcResult.getErrors());
                 } else {
-                    interfacelist = rpcResult.getResult().getInterfacesList();
+                    srcDpninterfacelist = rpcResult.getResult().getInterfacesList();
                 }
             } catch (Exception e) {
                 LOG.warn("Exception {} when querying for GetDpnInterfaceList for dpnid {}, trace {}", e, srcDpnId, e.getStackTrace());
             }
 
+            // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
+            if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
+                remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
+                try {
+                    result = intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
+                    RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
+                    if (!rpcResult.isSuccessful()) {
+                        LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId, rpcResult.getErrors());
+                    } else {
+                        destDpninterfacelist = rpcResult.getResult().getInterfacesList();
+                    }
+                } catch (Exception e) {
+                    LOG.warn("Exception {} when querying for GetDpnInterfaceList for dpnid {}, trace {}", e, srcDpnId, e.getStackTrace());
+                }
+            }
+
             /*
-             * Iterate over the list of VpnInterface for a given Dpn and read the adj.
+             * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj.
              * Update the adjacencies with the updated nexthop.
              */
-            Iterator<String> interfacelistIter = interfacelist.iterator();
+            Iterator<String> interfacelistIter = srcDpninterfacelist.iterator();
             String intfName = null;
             List<Uuid> subnetList = new ArrayList<Uuid>();
             Map<Long, String> vpnIdRdMap = new HashMap<Long, String>();
@@ -262,11 +242,10 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
                     dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
                             new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
                                     vpnInterfaceManager,
-                                    tunTypeVal,
                                     tunnelAction,
-                                    action,
                                     vpnInterface,
-                                    stateTunnelList));
+                                    stateTunnelList,
+                                    isTepDeletedOnDpn));
 
                     // Populate the List of subnets
                     InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
@@ -281,42 +260,65 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
 
                     //Populate the map for VpnId-to-Rd
                     long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
-                    String rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
+                    rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
                     vpnIdRdMap.put(vpnId, rd);
                 }
             }
 
+            /*
+             * Iterate over the list of VpnInterface for destDPN and get the prefix .
+             * Create remote rule for each of those prefix on srcDPN.
+             */
+            interfacelistIter = destDpninterfacelist.iterator();
+            while (interfacelistIter.hasNext()) {
+                intfName = interfacelistIter.next();
+                final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
+                if (vpnInterface != null) {
+                    List<Adjacency> adjList = vpnInterface.getAugmentation(Adjacencies.class).getAdjacency();
+                    String prefix = null;
+                    long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
+                    if (vpnIdRdMap.containsKey(vpnId)) {
+                        rd = vpnIdRdMap.get(vpnId);
+                        LOG.trace(" Remote DpnId {} VpnId {} rd {} VpnInterface {}", remoteDpnId, vpnId, rd , vpnInterface);
+                        for (Adjacency adj : adjList) {
+                            prefix = adj.getIpAddress();
+                            if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD) &&
+                                    (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
+                                fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp);
+                            }
+
+                            if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) &&
+                                    (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
+                                fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp);
+                            }
+                        }
+                    }
+                }
+            }
+
             //Iterate over the VpnId-to-Rd map.
             Iterator<Map.Entry<Long, String>> entries = vpnIdRdMap.entrySet().iterator();
             while (entries.hasNext()) {
                 Map.Entry<Long, String> entry = entries.next();
                 Long vpnId = entry.getKey();
-                String rd = entry.getValue();
-                if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
-                    if(tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                        fibManager.populateInternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                    }
-                    if(tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
-                        fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                    }
-                } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
-                    if(tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
-                        fibManager.cleanUpInternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                    }
-                    if(tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
-                        fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
-                    }
+                rd = entry.getValue();
+                if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD) &&
+                        (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
+                    fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
+                } else if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) &&
+                        (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
+                    fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
                 }
             }
 
-            if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
+            if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
                 for (Uuid subnetId : subnetList) {
                     // Populate the List of subnets
                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
                 }
             }
 
-            if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
+            if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
                 for (Uuid subnetId : subnetList) {
                     // Populate the List of subnets
                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
@@ -331,46 +333,38 @@ public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBas
 
 
     private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
-        private int tunTypeVal;
         private VpnInterface vpnInterface;
         private StateTunnelList stateTunnelList;
-        private TunnelInterfaceStateListener.UpdateRouteAction action;
         private VpnInterfaceManager vpnInterfaceManager;
         private  DataBroker broker;
         private TunnelAction tunnelAction;
+        private boolean isTepDeletedOnDpn;
 
         UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
                                         VpnInterfaceManager vpnInterfaceManager,
-                                        int tunTypeVal,
                                         TunnelAction tunnelAction,
-                                        TunnelInterfaceStateListener.UpdateRouteAction action,
                                         VpnInterface vpnInterface,
-                                        StateTunnelList stateTunnelList) {
+                                        StateTunnelList stateTunnelList,
+                                        boolean isTepDeletedOnDpn) {
             this.broker = broker;
             this.vpnInterfaceManager = vpnInterfaceManager;
-            this.tunTypeVal = tunTypeVal;
             this.stateTunnelList = stateTunnelList;
             this.vpnInterface = vpnInterface;
-            this.action = action;
             this.tunnelAction = tunnelAction;
+            this.isTepDeletedOnDpn = isTepDeletedOnDpn;
         }
 
         public List<ListenableFuture<Void>> call() throws Exception {
-            WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
-            WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
 
             if(tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
-                vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList, writeOperTxn, writeConfigTxn);
+                vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
             }
 
-            if(tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
-                vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, writeOperTxn, writeConfigTxn);
+            if((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
+                vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
             }
 
-            List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
-            futures.add(writeOperTxn.submit());
-            futures.add(writeConfigTxn.submit());
-            return futures;
+            return null;
         }
     }
 
index 50a4bc587e6dbd58f484826d22eb18e521b5cdf3..e8be0a16d61c160fb4647b8861655fdee81bab5c 100755 (executable)
@@ -725,11 +725,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     public void updateVpnInterfaceOnTepAdd(VpnInterface vpnInterface,
-                                           StateTunnelList stateTunnelList,
-                                           WriteTransaction writeOperTxn,
-                                           WriteTransaction writeCfgTxn) {
+                                           StateTunnelList stateTunnelList) {
 
         String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
+        BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
         String rd = getRouteDistinguisher(vpnInterface.getVpnInstanceName());
         rd = (rd != null) ? rd : vpnInterface.getVpnInstanceName();
         Adjacencies adjacencies = vpnInterface.getAugmentation(Adjacencies.class);
@@ -738,6 +737,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         long label = 0;
         List<String> nhList = new ArrayList<String>();
         boolean nextHopAdded = false;
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
 
         if (adjList != null) {
             List<Adjacency> value = new ArrayList<>();
@@ -751,34 +751,46 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     List<String> nextHopList = adj.getNextHopIpList();
                     // Incase nextHopList contains some other TEP IP ,
                     // it needs to be updated with new one.
-                    if ((nextHopList != null) && (!nextHopList.isEmpty())) {
-                        if (!nextHopList.get(0).equalsIgnoreCase((srcTepIp))) {
-                            nextHopAdded = true;
-                        }
-                    }
                     // Incase nextHopIp was null at the time of VpnInterface creation,
                     // it needs to be updated with new one.
-                    if((nextHopList == null) || (nextHopList.isEmpty())) {
+                    if (nextHopList != null && (!nextHopList.isEmpty()) &&
+                            (nextHopList.get(0).equalsIgnoreCase(srcTepIp))){
+                            /* everything right already */
+                    } else {
+                        /* update the adjacency here itself */
                         nextHopAdded = true;
+                        LOG.trace("NextHopList to be updated {}",nhList);
+                        // Update the VpnInterface Op DS with new nextHopList
+                        value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
+                        Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
+                        VpnInterface opInterface = new VpnInterfaceBuilder(vpnInterface).setKey(new VpnInterfaceKey(vpnInterface.getName()))
+                                .addAugmentation(Adjacencies.class, aug).build();
+                        InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
+                        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
                     }
                 }
+
                 if (nextHopAdded) {
-                    LOG.trace("NextHopList to be updated {}",nhList);
-                    // Update the VpnInterface Op DS with new nextHopList
-                    value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
-                    Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
-                    VpnInterface opInterface = new VpnInterfaceBuilder(vpnInterface).setKey(new VpnInterfaceKey(vpnInterface.getName()))
-                            .addAugmentation(Adjacencies.class, aug).build();
-                    InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
-                    writeOperTxn.put(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, true);
+                    LOG.info("Updating label mapper : label {} dpn {} prefix {} nexthoplist {} vpnid {} rd {}", label, srcDpnId , prefix, nhList, vpnId, rd);
+                    updateLabelMapper(label, nhList);
 
                     // Update the VRF entry with nextHop
-                    fibManager.updateFibEntry(dataBroker, rd, prefix, nhList, writeCfgTxn);
-
+                    fibManager.updateFibEntry(dataBroker, rd, prefix, nhList, null);
+
+                    //Get the list of VPN's importing this route(prefix) .
+                    // Then update the VRF entry with nhList
+                    List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnInterface.getVpnInstanceName());
+                    for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
+                        String vpnRd = vpn.getVrfId();
+                        if (vpnRd != null) {
+                            LOG.debug("Exporting route with rd {} prefix {} nhList {} label {} to VPN {}", vpnRd, prefix, nhList, label, vpn);
+                            fibManager.updateFibEntry(dataBroker, vpnRd, prefix, nhList, null);
+                        }
+                    }
                     // Advertise the prefix to BGP only for external vpn
                     // since there is a nexthop change.
                     try {
-                        if (rd != null) {
+                        if (!rd.equalsIgnoreCase(vpnInterface.getVpnInstanceName())) {
                             bgpManager.advertisePrefix(rd, prefix, nhList, (int)label);
                         }
                     } catch (Exception ex) {
@@ -790,8 +802,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     public void updateVpnInterfaceOnTepDelete(VpnInterface vpnInterface,
-                                              WriteTransaction writeOperTxn,
-                                              WriteTransaction writeCfgTxn) {
+                                              StateTunnelList stateTunnelList) {
 
         String rd = getRouteDistinguisher(vpnInterface.getVpnInstanceName());
         rd = (rd != null) ? rd : vpnInterface.getVpnInstanceName();
@@ -801,6 +812,8 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         long label = 0;
         List<String> nhList = new ArrayList<String>();
         boolean isNextHopRemoveReqd = false;
+        BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
+        long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
 
         if (adjList != null) {
             List<Adjacency> value = new ArrayList<>();
@@ -814,27 +827,37 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                     // If nextHopList is already cleaned , no need to modify again
                     if((nextHopList != null) & (!nextHopList.isEmpty())) {
                         isNextHopRemoveReqd = true;
-                    } else if ((nextHopList == null) || (nextHopList.isEmpty())){
-                        LOG.trace("NextHopList is already cleared for interface {} ", vpnInterface);
-                        isNextHopRemoveReqd = false;
+                        value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
+                        Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
+
+                        VpnInterface opInterface = new VpnInterfaceBuilder(vpnInterface).setKey(new VpnInterfaceKey(vpnInterface.getName()))
+                                .addAugmentation(Adjacencies.class, aug).build();
+                        InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
+                        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface);
                     }
                 }
 
                 if(isNextHopRemoveReqd) {
-                    value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
-                    Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(value);
-
-                    VpnInterface opInterface = new VpnInterfaceBuilder(vpnInterface).setKey(new VpnInterfaceKey(vpnInterface.getName()))
-                            .addAugmentation(Adjacencies.class, aug).build();
-                    InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
-                    writeOperTxn.put(LogicalDatastoreType.OPERATIONAL, interfaceId, opInterface, true);
+                    LOG.info("Updating label mapper : label {} dpn {} prefix {} nexthoplist {} vpnid {} rd {}", label, srcDpnId , prefix, nhList, vpnId, rd);
+                    updateLabelMapper(label, nhList);
 
                     // Update the VRF entry with emtpy nextHop
-                    fibManager.updateFibEntry(dataBroker, rd, prefix, new ArrayList<String>() /* empty */, writeCfgTxn);
+                    fibManager.updateFibEntry(dataBroker, rd, prefix, new ArrayList<String>() /* empty */, null);
+
+                    //Get the list of VPN's importing this route(prefix) .
+                    // Then update the VRF entry with nhList
+                    List<VpnInstanceOpDataEntry> vpnsToImportRoute = getVpnsImportingMyRoute(vpnInterface.getVpnInstanceName());
+                    for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
+                        String vpnRd = vpn.getVrfId();
+                        if (vpnRd != null) {
+                            LOG.debug("Exporting route with rd {} prefix {} nhList {} label {} to VPN {}", vpnRd, prefix, nhList, label, vpn);
+                            fibManager.updateFibEntry(dataBroker, vpnRd, prefix, nhList, null);
+                        }
+                    }
 
                     // Withdraw prefix from BGP only for external vpn.
                     try {
-                        if (rd != null) {
+                        if (!rd.equalsIgnoreCase(vpnInterface.getVpnInstanceName())) {
                             bgpManager.withdrawPrefix(rd, prefix);
                         }
                     } catch (Exception ex) {
@@ -1487,6 +1510,18 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         }
     }
 
+    private void updateLabelMapper(Long label, List<String> nextHopIpList) {
+        Preconditions.checkNotNull(label, "label cannot be null or empty!");
+
+        InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
+                .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
+        Optional<LabelRouteInfo> opResult = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
+        if (opResult.isPresent()) {
+            LabelRouteInfo labelRouteInfo = new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
+            MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid, labelRouteInfo);
+        }
+    }
+
     public void addSubnetRouteFibEntryToDS(String rd, String vpnName, String prefix, String nextHop, int label,
                                                         long elantag, BigInteger dpnId, WriteTransaction writeTxn) {
         SubnetRoute route = new SubnetRouteBuilder().setElantag(elantag).build();
index 6a4f0b7e1c4c59271831227cda8cf43a6e66f7ac..660763337b4cca4f3bb577a38edd2e729ca2ef76 100644 (file)
@@ -81,6 +81,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         String vpnName = notification.getVpnName();
         String subnetIp = notification.getSubnetIp();
         Long elanTag = notification.getElanTag();
+        boolean isRouteAdvertised = false;
 
         Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
         Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
@@ -206,8 +207,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {} to vpn {}", subnetIp, vpnName);
                             return;
                         }
-                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                        isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                        if (isRouteAdvertised) {
+                            subOpBuilder.setRouteAdvState(TaskState.Done);
+                        } else {
+                            subOpBuilder.setNhDpnId(null);
+                            subOpBuilder.setRouteAdvState(TaskState.Na);
+                        }
                     } catch (Exception ex) {
                         logger.error("onSubnetAddedToVpn: FIB rules and Advertising nhDpnId " + nhDpnId +
                                 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
@@ -344,6 +350,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     public void onPortAddedToSubnet(PortAddedToSubnet notification) {
         Uuid subnetId = notification.getSubnetId();
         Uuid portId = notification.getPortId();
+        boolean isRouteAdvertised = false;
 
         logger.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
@@ -411,8 +418,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             logger.error("Unable to fetch label from Id Manager. Bailing out of handling addition of port {} to subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName);
                             return;
                         }
-                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                        isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                        if (isRouteAdvertised) {
+                            subOpBuilder.setRouteAdvState(TaskState.Done);
+                        } else {
+                            subOpBuilder.setNhDpnId(null);
+                            subOpBuilder.setRouteAdvState(TaskState.Na);
+                        }
                     } catch (Exception ex) {
                         logger.error("onPortAddedToSubnet: Advertising NextHopDPN "+ nhDpnId +
                                 " information for subnet " + subnetId.getValue() + " to BGP failed {}", ex);
@@ -437,6 +449,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
         Uuid subnetId = notification.getSubnetId();
         Uuid portId = notification.getPortId();
+        boolean isRouteAdvertised = false;
 
         logger.info("onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
@@ -501,8 +514,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                                     logger.error("Unable to fetch label from Id Manager. Bailing out of handling removal  of port {} from subnet {} in vpn {}", portId.getValue(), subnetIp, vpnName);
                                     return;
                                 }
-                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                                subOpBuilder.setRouteAdvState(TaskState.Done);
+                                isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                                if (isRouteAdvertised) {
+                                    subOpBuilder.setRouteAdvState(TaskState.Done);
+                                } else {
+                                    subOpBuilder.setNhDpnId(null);
+                                    subOpBuilder.setRouteAdvState(TaskState.Na);
+                                }
                             } catch (Exception ex) {
                                 logger.error("onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN " + dpnId +
                                         " information for subnet " + subnetId.getValue() +
@@ -530,6 +548,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         logger.info("onInterfaceUp: Port " + intfName);
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         SubnetToDpn subDpn = null;
+        boolean isRouteAdvertised = false;
         PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
         if (portOpEntry == null) {
             logger.info("onInterfaceUp: Port " + intfName  + "is part of a subnet not in VPN, ignoring");
@@ -583,8 +602,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface up event for port {} for subnet {} in vpn {}", intfName, subnetIp, vpnName);
                             return;
                         }
-                        addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                        isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                        if(isRouteAdvertised) {
+                            subOpBuilder.setRouteAdvState(TaskState.Done);
+                        } else {
+                            subOpBuilder.setNhDpnId(null);
+                            subOpBuilder.setRouteAdvState(TaskState.Na);
+                        }
                     } catch (Exception ex) {
                         logger.error("onInterfaceUp: Advertising NextHopDPN " + nhDpnId + " information for subnet " +
                                 subnetId.getValue() + " to BGP failed {}" + ex);
@@ -605,6 +629,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     }
 
     public void onInterfaceDown(final BigInteger dpnId, final String interfaceName) {
+        boolean isRouteAdvertised = false;
         logger.info("onInterfaceDown: Port " + interfaceName);
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(interfaceName);
@@ -669,8 +694,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                                     logger.error("Unable to fetch label from Id Manager. Bailing out of handling interface down event for port {} in subnet {} for vpn {}", interfaceName, subnetIp, vpnName);
                                     return;
                                 }
-                                addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                                subOpBuilder.setRouteAdvState(TaskState.Done);
+                                isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                                if(isRouteAdvertised) {
+                                    subOpBuilder.setRouteAdvState(TaskState.Done);
+                                } else {
+                                    subOpBuilder.setNhDpnId(null);
+                                    subOpBuilder.setRouteAdvState(TaskState.Na);
+                                }
                             } catch (Exception ex) {
                                 logger.error("onInterfaceDown: Swapping Withdrawing NextHopDPN " + dpnId + " information for subnet " +
                                         subnetId.getValue() + " to BGP failed {}" + ex);
@@ -702,6 +732,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     }
 
     public void updateSubnetRouteOnTunnelUpEvent(Uuid subnetId, BigInteger dpnId) {
+        boolean isRouteAdvertised = false;
         logger.info("updateSubnetRouteOnTunnelUpEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString());
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -730,9 +761,13 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                                 try {
                                     subOpBuilder.setNhDpnId(dpnId);
                                     int label = getLabel(rd, subnetIp);
-                                    addSubnetRouteToFib(rd, subnetIp, dpnId, vpnName, elanTag, label, subnetId);
-                                    //advertiseSubnetRouteToBgp(rd, subnetIp, dpnId, vpnName, elanTag, label);
-                                    subOpBuilder.setRouteAdvState(TaskState.Done);
+                                    isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, dpnId, vpnName, elanTag, label, subnetId);
+                                    if(isRouteAdvertised) {
+                                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                                    } else {
+                                        subOpBuilder.setNhDpnId(null);
+                                        subOpBuilder.setRouteAdvState(TaskState.Na);
+                                    }
                                 } catch(Exception ex) {
                                     logger.error("updateSubnetRouteOnTunnelUpEvent: Advertising NextHopDPN " + dpnId + " information for subnet " +
                                             subnetId.getValue() + " to BGP failed {}" + ex);
@@ -740,11 +775,11 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             }
                         }
                     }
+                    subOpEntry = subOpBuilder.build();
+                    MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                    logger.info("updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up on dpn {} for subnet {}",
+                            dpnId.toString(), subnetId.getValue());
                 }
-                subOpEntry = subOpBuilder.build();
-                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                logger.info("updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up on dpn {} for subnet {}",
-                        dpnId.toString(), subnetId.getValue());
             } catch (Exception ex) {
                 logger.error("Creation of SubnetOpDataEntry for subnet " +
                         subnetId.getValue() + " failed {}" + ex);
@@ -773,58 +808,15 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                     return;
                 }
                 SubnetOpDataEntry subOpEntry = null;
-                List<SubnetToDpn> subDpnList = null;
                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                long elanTag = subOpBuilder.getElanTag();
                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
-                    subDpnList = subOpBuilder.getSubnetToDpn();
-                    List<BigInteger> dpnIdList = new ArrayList<BigInteger>();
-
-                    Iterator<SubnetToDpn> subNetIt = subDpnList.iterator();
-                    while (subNetIt.hasNext()) {
-                        SubnetToDpn subnetToDpn = subNetIt.next();
-                        if (!subnetToDpn.getDpnId().equals(dpnId)) {
-                            dpnIdList.add(subnetToDpn.getDpnId());
-                        }
-                    }
-                    if (dpnIdList.isEmpty()) {
-                        subOpBuilder.setNhDpnId(null);
-                        try {
-                            // Withdraw route from BGP for this subnet
-                            deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
-                            //withdrawSubnetRoutefromBgp(rd, subnetIp);
-                            subOpBuilder.setRouteAdvState(TaskState.Na);
-                        } catch (Exception ex) {
-                            logger.error("updateSubnetRouteOnTunnelDownEvent: Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet " +
-                                    subnetId.getValue() + " from BGP failed {}" + ex);
-                            subOpBuilder.setRouteAdvState(TaskState.Pending);
-                        }
-                    } else {
-                        logger.debug("DpnList {} to choose the next bestfit dpn", dpnIdList);
-                        // current nhdpn not reachable from dc-gw, so we need to swap the NHDpnId
-                        nhDpnId = dpnIdList.get(0);
-                        subOpBuilder.setNhDpnId(nhDpnId);
-                        logger.debug("updateSubnetRouteOnTunnelDownEvent: Swapping the Designated DPN to " + nhDpnId.toString() + " for subnet " + subnetId.getValue());
-                        try {
-                            //update the VRF entry for the subnetroute.
-                            int label = getLabel(rd, subnetIp);
-                            addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                            subOpBuilder.setRouteAdvState(TaskState.Done);
-                        } catch (Exception ex) {
-                            logger.error("updateSubnetRouteOnTunnelDownEvent: Swapping Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet " +
-                                    subnetId.getValue() + " to BGP failed {}" + ex);
-                            subOpBuilder.setRouteAdvState(TaskState.Pending);
-                        }
-                    }
+                    electNewDPNForSubNetRoute(subOpBuilder, dpnId, subnetId);
+                    subOpEntry = subOpBuilder.build();
+                    MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                    logger.info("updateSubnetRouteOnTunnelDownEvent: Updated subnetopdataentry to OP Datastore tunnnel down on dpn {} for subnet {}",
+                            dpnId.toString(), subnetId.getValue());
                 }
-                subOpEntry = subOpBuilder.build();
-                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                logger.info("updateSubnetRouteOnTunnelDownEvent: Updated subnetopdataentry to OP Datastore tunnnel down on dpn {} for subnet {}",
-                        dpnId.toString(), subnetId.getValue());
             } catch (Exception ex) {
                 logger.error("Updation of SubnetOpDataEntry for subnet " +
                         subnetId.getValue() + " failed {}" + ex);
@@ -836,7 +828,7 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         }
     }
 
-    private void addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
+    private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
                                      Long elanTag, int label, Uuid subnetId) throws Exception {
         Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
         Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
@@ -847,15 +839,14 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
             nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
         } catch (Exception e) {
             logger.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
-            return;
+            return false;
         }
         if (nexthopIp != null) {
             VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp), VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp));
             vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId, null);
             try {
-                // BGPManager (inside ODL) requires a withdraw followed by advertise
-                // due to bugs with ClusterDataChangeListener used by BGPManager.
-                //bgpManager.withdrawPrefix(rd, subnetIp);
+                //BGP manager will handle withdraw and advertise internally if prefix
+                //already exist
                 bgpManager.advertisePrefix(rd, subnetIp, Arrays.asList(nexthopIp), label);
             } catch (Exception e) {
                 logger.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e);
@@ -863,7 +854,9 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
             }
         } else {
             logger.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
+            return false;
         }
+        return true;
     }
 
     private int getLabel(String rd, String subnetIp) {
@@ -884,5 +877,53 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
             throw e;
         }
     }
+
+    private void electNewDPNForSubNetRoute(SubnetOpDataEntryBuilder subOpBuilder , BigInteger dpnId, Uuid subnetId) {
+        List<SubnetToDpn> subDpnList = null;
+        boolean isRouteAdvertised = false;
+        subDpnList = subOpBuilder.getSubnetToDpn();
+        String rd = subOpBuilder.getVrfId();
+        String subnetIp = subOpBuilder.getSubnetCidr();
+        String vpnName = subOpBuilder.getVpnName();
+        long elanTag = subOpBuilder.getElanTag();
+        BigInteger nhDpnId = null;
+        boolean isAlternateDpnSelected = false;
+        Iterator<SubnetToDpn> subNetIt = subDpnList.iterator();
+        int label = getLabel(rd, subnetIp);
+        while (subNetIt.hasNext()) {
+            SubnetToDpn subnetToDpn = subNetIt.next();
+            nhDpnId = subnetToDpn.getDpnId();
+            if (!nhDpnId.equals(dpnId)) {
+                try {
+                    //update the VRF entry for the subnetroute.
+                    isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
+                    if (isRouteAdvertised) {
+                        subOpBuilder.setRouteAdvState(TaskState.Done);
+                        subOpBuilder.setNhDpnId(nhDpnId);
+                        isAlternateDpnSelected = true;
+                        break;
+                    }
+                } catch (Exception ex) {
+                    logger.error("electNewDPNForSubNetRoute: Swapping and trying to configure NextHopDPN {} for subnet {} failed ex {}", dpnId.toString(), subnetId.getValue(), ex);
+                    subOpBuilder.setRouteAdvState(TaskState.Na);
+                }
+            }
+        }
+
+        //If no alternate Dpn is selected as nextHopDpn ,withdraw the subnetroute.
+        if (!isAlternateDpnSelected) {
+            logger.info("No alternate DPN available for subnet {}.Prefix withdrawn from BGP", subnetIp);
+            try {
+                // Withdraw route from BGP for this subnet
+                deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
+                subOpBuilder.setNhDpnId(null);
+                subOpBuilder.setRouteAdvState(TaskState.Na);
+            } catch (Exception ex) {
+                logger.error("electNewDPNForSubNetRoute: Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet " +
+                        subnetId.getValue() + " from BGP failed {}" + ex);
+                subOpBuilder.setRouteAdvState(TaskState.Pending);
+            }
+        }
+    }
 }