Bug 7120 : NAT Support For GRE TEP add/del is missing 21/47621/12
authorSatish Dutt <satishd@altencalsoftlabs.com>
Wed, 26 Oct 2016 15:13:50 +0000 (20:43 +0530)
committerSam Hague <shague@redhat.com>
Thu, 10 Nov 2016 17:18:56 +0000 (17:18 +0000)
Support has been added in the NAT for the GRE TEP changes. Below are the
enhancements :

1) When GRE TEP is deleted :

a) SNAT : If the corresponding DPN was the NAPT switch, then a new NAPT
switch is
re-elected among the other DPNs and rest of the non-NAPT switches point to
the new NAPT switch. The routes to the External Fixed IPs (SNAT IPs) are
updated with the new NAPT switch address.

b) DNAT : If the corressponding DPN was hosting VMs with the Floating IPs,
then
the routes to those FIPs are withdrawn from the BGP and removed from the
controller FIB.

2) When the GRE TEP is added :

a) SNAT : The correponding DPN will be delegated as the non NAPT switch
and made to point to the exsiting NAPT switch. Routes are not altered.

b) DNAT : If the corresponding DPN was hosting VMs with the Floating IPs,
then routes to those FIPs are advertised to the BGP and installed in the
controller FIB.

Change-Id: I0cb968b7beb9ec294cc4bafb6539e2e6cdd1c541
Signed-off-by: Satish Dutt <satishd@altencalsoftlabs.com>
12 files changed:
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/FloatingIPListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/InterfaceStateEventListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptManager.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NaptSwitchHA.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatConstants.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatInterfaceStateChangeListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatRouterInterfaceListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatTunnelInterfaceStateListener.java [new file with mode: 0644]
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/natservice/natservice-impl/src/main/resources/org/opendaylight/blueprint/natservice.xml
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang

index f8df941d7fdaed096e2b72e8dcf4d46391cda4a6..ea627159446a0def3cc0842a4e72f7b8591a285c 100644 (file)
@@ -1380,7 +1380,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    private Long checkExternalIpLabel(long routerId, String externalIp){
+    protected Long checkExternalIpLabel(long routerId, String externalIp){
         List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
         for(IpMap ipMap : ipMaps){
             if(ipMap.getExternalIp().equals(externalIp)){
@@ -1969,7 +1969,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     /**
      * router association to vpn
-     *
+     *@param routerName - Name of router
+     *@param bgpVpnName BGP VPN name
      */
     public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName){
         LOG.debug("NAT Service : Router associated to BGP VPN");
@@ -2000,7 +2001,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     /**
      * router disassociation from vpn
-     *
+     *@param routerName - Name of router
+     *@param bgpVpnName BGP VPN name
      */
     public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName){
         LOG.debug("NAT Service : Router dissociated from BGP VPN");
index 7cb73ac2af03bdfe6df3a6f4768b814276b8b403..6d6b194092c429f0c6dfcdddfc4e4cc894b23c56 100644 (file)
@@ -556,6 +556,46 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<IpMappin
 
     }
 
+    void removeNATFlowEntries(String interfaceName, final IpMapping mapping,
+                              final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName, BigInteger dpnId) {
+
+        if(dpnId.equals(BigInteger.ZERO)) {
+            LOG.info("NAT Service : Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
+            return;
+        }
+
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if(routerId == NatConstants.INVALID_ID) {
+            LOG.warn("NAT Service : Could not retrieve router id for {} to remove NAT Flow entries", routerName);
+            return;
+        }
+
+        //Delete the DNAT and SNAT table entries
+        removeDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId);
+
+        Uuid extNwId = getExtNetworkId(pIdentifier, LogicalDatastoreType.OPERATIONAL);
+        if(extNwId == null) {
+            LOG.error("NAT Service : External network associated with interface {} could not be retrieved", interfaceName);
+            return;
+        }
+        long vpnId = getVpnId(extNwId);
+        if(vpnId < 0) {
+            LOG.error("NAT Service : No VPN associated with ext nw {}. Unable to delete SNAT table entry for fixed ip {}",
+                    extNwId, mapping.getInternalIp());
+            return;
+        }
+        removeSNATTblEntry(dpnId, mapping.getInternalIp(), routerId, mapping.getExternalIp(), vpnId);
+
+        long label = getOperationalIpMapping(routerName, interfaceName, mapping.getInternalIp());
+        if(label < 0) {
+            LOG.error("NAT Service : Could not retrieve label for prefix {} in router {}", mapping.getInternalIp(), routerId);
+            return;
+        }
+        floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, extNwId, mapping.getExternalIp(), mapping.getInternalIp(), (int) label);
+        removeOperationalDS(routerName, interfaceName, mapping.getInternalIp(), mapping.getExternalIp());
+
+    }
+
     void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
         long routerId = NatUtil.getVpnId(dataBroker, routerName);
         if(routerId == NatConstants.INVALID_ID) {
@@ -598,10 +638,14 @@ public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<IpMappin
         //removeSNATTblEntry(dpnId, internalIp, routerId, externalIp);
     }
 
-    private long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
+    protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
         InstanceIdentifier<IpMapping> ipMappingIdentifier = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
         Optional<IpMapping> ipMapping = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ipMappingIdentifier);
         if(ipMapping.isPresent()) {
+            Long label = ipMapping.get().getLabel();
+            if(label == null){
+                return NatConstants.INVALID_ID;
+            }
             return ipMapping.get().getLabel();
         }
         return NatConstants.INVALID_ID;
index 32280987c7002b1dcbe2212a578ed50a591480b0..58a03719dcd87f09aa71c2b364b663a3ee4e9e91 100644 (file)
@@ -102,7 +102,7 @@ public class InterfaceStateEventListener extends AsyncDataTreeChangeListenerBase
 
                 String routerName = getRouterIdForPort(dataBroker, interfaceName);
                 if (routerName != null) {
-                    processInterfaceRemoved(interfaceName, routerName);
+                    processInterfaceRemoved(interfaceName, routerName, dpnId);
                     removeSnatEntriesForPort(interfaceName,routerName);
                 } else {
                     LOG.debug("NAT Service : PORT_REMOVE: Router Id is null either Interface {} is not associated " +
@@ -359,8 +359,8 @@ public class InterfaceStateEventListener extends AsyncDataTreeChangeListenerBase
         }
     }
 
-    private void processInterfaceRemoved(String portName, String rtrId) {
-        LOG.trace("Processing Interface Removed Event for interface {}", portName);
+    private void processInterfaceRemoved(String portName, String rtrId, BigInteger dpnId) {
+        LOG.trace("NAT Service : Processing Interface Removed Event for interface {} on DPN ID {}", portName, dpnId);
         String routerId = getRouterIdForPort(dataBroker, portName);
         List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
         if (ipMappingList == null || ipMappingList.isEmpty()) {
@@ -369,7 +369,8 @@ public class InterfaceStateEventListener extends AsyncDataTreeChangeListenerBase
         }
         InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
         for (IpMapping ipMapping : ipMappingList) {
-            floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
+            LOG.trace("NAT Service : Removing DNAT Flow entries for dpnId {} ", dpnId);
+            floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId, dpnId);
         }
     }
 
index 18113357f39076e0c2a64c98e391bf6bbc3d53a2..56dc5773c93c5c2eedbd6ec88f8474597a32a38f 100644 (file)
@@ -194,8 +194,9 @@ public class NaptManager  {
       * method to get external ip/port mapping when provided with internal ip/port pair
       * If already a mapping exist for the given input, then the existing mapping is returned
       * instead of overwriting with new ip/port pair.
-      * @param segmentId
+      * @param segmentId - Router ID
       * @param sourceAddress - internal ip address/port pair
+      * @param protocol - TCP/UDP
       * @return external ip address/port
       */
      public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) {
@@ -333,8 +334,9 @@ public class NaptManager  {
      /**
       * release the existing mapping of internal ip/port to external ip/port pair
       * if no mapping exist for given internal ip/port, it returns false
-      * @param segmentId
-      * @param address
+      * @param segmentId - Router ID
+      * @param address - Session Address
+      * @param protocol - TCP/UDP
       * @return true if mapping exist and the mapping is removed successfully
       */
 
@@ -412,7 +414,7 @@ public class NaptManager  {
 
      /**
       * removes the internal ip to external ip mapping if present
-      * @param segmentId
+      * @param segmentId - Router ID
       * @return true if successfully removed
       */
      public boolean removeMapping(long segmentId) {
index 96186f64ed1b3a5c5f715b784228a37f79642713..aa5a5fed979e44a1e5cb916c57512c614b3cd7bb 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
@@ -78,6 +79,7 @@ public class NaptSwitchHA {
     private final IBgpManager bgpManager;
     private final VpnRpcService vpnService;
     private final FibRpcService fibService;
+    private final IFibManager fibManager;
     private List<String> externalIpsCache;
     private HashMap<String,Long> externalIpsLabel;
 
@@ -89,7 +91,8 @@ public class NaptSwitchHA {
                         final NAPTSwitchSelector naptSwitchSelector,
                         final IBgpManager bgpManager,
                         final VpnRpcService vpnService,
-                        final FibRpcService fibService) {
+                        final FibRpcService fibService,
+                        final IFibManager fibManager) {
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
         this.externalRouterListener = externalRouterListener;
@@ -100,6 +103,7 @@ public class NaptSwitchHA {
         this.bgpManager = bgpManager;
         this.vpnService = vpnService;
         this.fibService =fibService;
+        this.fibManager = fibManager;
     }
 
     /* This method checks the switch that gone down is a NaptSwitch for a router.
@@ -305,8 +309,11 @@ public class NaptSwitchHA {
         }
         return routerUuidsAsString;
     }
+    public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId,List<String> externalIpCache){
+        return isNaptSwitchDown(routerName, dpnId , naptSwitch, routerVpnId, externalIpCache, true);
+    }
 
-    public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId,List<String> externalIpCache) {
+    public boolean isNaptSwitchDown(String routerName, BigInteger dpnId , BigInteger naptSwitch,Long routerVpnId,List<String> externalIpCache, boolean isClearBgpRts) {
         externalIpsCache = externalIpCache;
         if (!naptSwitch.equals(dpnId)) {
             LOG.debug("DpnId {} is not a naptSwitch {} for Router {}",dpnId, naptSwitch, routerName);
@@ -321,7 +328,8 @@ public class NaptSwitchHA {
         //elect a new NaptSwitch
         naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
         if (naptSwitch.equals(BigInteger.ZERO)) {
-            LOG.info("No napt switch is elected since all the switches for router {} are down",routerName);
+            LOG.error("NAT Service : No napt switch is elected since all the switches for router {} are down. SNAT IS" +
+                    " NOT SUPPORTED FOR ROUTER {}",routerName);
             boolean naptUpdatedStatus = updateNaptSwitch(routerName,naptSwitch);
             if(!naptUpdatedStatus) {
                 LOG.debug("Failed to update naptSwitch {} for router {} in ds", naptSwitch,routerName);
@@ -332,8 +340,18 @@ public class NaptSwitchHA {
                 if (vpnName != null) {
                     //List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
                     //if (externalIps != null) {
-                    for (String externalIp : externalIpsCache) {
-                        externalRouterListener.clearBgpRoutes(externalIp, vpnName);
+                    if(isClearBgpRts){
+                        LOG.debug("NAT Service : Clearing both FIB entries and the BGP routes");
+                        for (String externalIp : externalIpsCache) {
+                            externalRouterListener.clearBgpRoutes(externalIp, vpnName);
+                        }
+                    }else{
+                        LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
+                        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+                        for (String externalIp : externalIpsCache) {
+                            LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
+                            fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
+                        }
                     }
                 } else {
                     LOG.debug("vpn is not associated to extn/w for router {}", routerName);
@@ -490,7 +508,7 @@ public class NaptSwitchHA {
                                 , intportnum, proto, externalAddress, extportNumber,bgpVpnId,ex);
                         return false;
                     }
-                    LOG.debug("Successfully installed a flow in SecondarySwitch {} Outbound NAPT table for router {} " +
+                    LOG.debug("Successfully installed a flow in Primary switch {} Outbound NAPT table for router {} " +
                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
                     //Install the flow in newNaptSwitch Inbound NAPT table.
@@ -503,7 +521,7 @@ public class NaptSwitchHA {
                                 internalIpAddress, intportnum,bgpVpnId);
                         return false;
                     }
-                    LOG.debug("Successfully installed a flow in SecondarySwitch {} Inbound NAPT table for router {} " +
+                    LOG.debug("Successfully installed a flow in Primary switch {} Inbound NAPT table for router {} " +
                             "ipport {}:{} proto {} extIpport {}:{} BgpVpnId {}", newNaptSwitch,routerId, internalIpAddress
                             , intportnum, proto, externalAddress, extportNumber,bgpVpnId);
 
index 1a13692b04f9fcce01400548aa58eb3b57104720..bff09e400b00331925011e7e8806b4d35b6fd7bc 100644 (file)
@@ -37,4 +37,12 @@ public class NatConstants {
     public static final int ADD_FLOW = 0;
     public static final int DEL_FLOW = 1;
 
+    public enum ITMTunnelLocType {
+        Invalid(0), Internal(1), External(2), Hwvtep(3);
+
+        private final int type;
+        ITMTunnelLocType(int id) { this.type = id; }
+        public int getValue() { return type; }
+    }
+
 }
index cd68429c79024cfc352370fa68a4e48d7e7fcfe9..a32afc939fd766cf20cc50c79d6102268c239ff9 100644 (file)
@@ -181,11 +181,13 @@ public class NatInterfaceStateChangeListener extends AsyncDataTreeChangeListener
     void handleRouterInterfacesUpEvent(String routerName, String interfaceName, WriteTransaction writeOperTxn) {
         LOG.debug("NAT Service : Handling UP event for router interface {} in Router {}", interfaceName, routerName);
         NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, interfaceManager, writeOperTxn);
+        NatUtil.addToDpnRoutersMap(dataBroker, routerName, interfaceName, interfaceManager, writeOperTxn);
     }
 
     void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
                                          WriteTransaction writeOperTxn) {
         LOG.debug("NAT Service : Handling DOWN event for router Interface {} in Router {}", interfaceName, routerName);
         NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpnId, writeOperTxn);
+        NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, interfaceManager, writeOperTxn);
     }
 }
index 5c1f81c9d871fd0b936026d87801dc2690199a44..66c40a6e6dc359558412ef25a7b33a97f195c2a4 100644 (file)
@@ -69,6 +69,7 @@ public class NatRouterInterfaceListener extends AsyncDataTreeChangeListenerBase<
         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
         if (interfaceState!= null) {
             NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerId, interfaceName, interfaceManager, writeOperTxn);
+            NatUtil.addToDpnRoutersMap(dataBroker, routerId, interfaceName, interfaceManager, writeOperTxn);
         }else{
             LOG.warn("NAT Service : Interface {} not yet operational to handle router interface add event in router {}",
                     interfaceName, routerId);
@@ -90,6 +91,9 @@ public class NatRouterInterfaceListener extends AsyncDataTreeChangeListenerBase<
         //Delete the NeutronRouterDpnMap from the ODL:L3VPN operational model
         WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
         NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerId, interfaceName, interfaceManager, writeTxn);
+
+        //Delete the DpnRouterMap from the ODL:L3VPN operational model
+        NatUtil.removeFromDpnRoutersMap(dataBroker, routerId, interfaceName, interfaceManager, writeTxn);
         writeTxn.submit();
     }
 
diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatTunnelInterfaceStateListener.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatTunnelInterfaceStateListener.java
new file mode 100644 (file)
index 0000000..e2796ce
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.natservice.internal;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.mdsalutil.*;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.netvirt.fibmanager.api.IFibManager;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class NatTunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener> implements
+        AutoCloseable{
+    private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
+    private final DataBroker dataBroker;
+    private IFibManager fibManager;
+    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private NaptSwitchHA naptSwitchHA;
+    private IMdsalApiManager mdsalManager;
+    private IdManagerService idManager;
+    private IBgpManager bgpManager;
+    private ExternalRoutersListener externalRouterListner;
+    private OdlInterfaceRpcService interfaceService;
+    private FloatingIPListener floatingIPListener;
+    private FibRpcService fibRpcService;
+
+    protected  enum TunnelAction {
+        TUNNEL_EP_ADD,
+        TUNNEL_EP_DELETE,
+        TUNNEL_EP_UPDATE
+    }
+
+    /**
+     * Responsible for listening to tunnel interface state change
+     *
+     * @param dataBroker - dataBroker service reference
+     * @param bgpManager Used to advertise routes to the BGP Router
+     * @param fibManager - FIB Manager
+     * @param defaultRouteProgrammer - Default Route Programmer
+     * @param naptSwitchHA - NAPT Switch HA
+     * @param mdsalManager - MDSAL Manager
+     * @param idManager - ID manager
+     * @param externalRouterListner - External Router Listner
+     * @param interfaceService - Interface Service
+     * @param floatingIPListener -  Floating IP Listner
+     * @param fibRpcService - FIB RPC Service
+     */
+    public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
+                                           final IBgpManager bgpManager,
+                                           final IFibManager fibManager,
+                                           final SNATDefaultRouteProgrammer defaultRouteProgrammer,
+                                           final NaptSwitchHA naptSwitchHA,
+                                           final IMdsalApiManager mdsalManager,
+                                           final IdManagerService idManager,
+                                           final ExternalRoutersListener externalRouterListner,
+                                           final OdlInterfaceRpcService interfaceService,
+                                           final FloatingIPListener floatingIPListener,
+                                           final FibRpcService fibRpcService) {
+        super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
+        this.dataBroker = dataBroker;
+        this.bgpManager = bgpManager;
+        this.fibManager = fibManager;
+        this.defaultRouteProgrammer = defaultRouteProgrammer;
+        this.naptSwitchHA = naptSwitchHA;
+        this.mdsalManager = mdsalManager;
+        this.idManager = idManager;
+        this.externalRouterListner = externalRouterListner;
+        this.interfaceService = interfaceService;
+        this.floatingIPListener = floatingIPListener;
+        this.fibRpcService = fibRpcService;
+    }
+
+    @Override
+    public void init() {
+        LOG.info("{} init", getClass().getSimpleName());
+        registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
+    }
+
+    @Override
+    protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
+        return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
+    }
+
+    @Override
+    protected NatTunnelInterfaceStateListener getDataTreeChangeListener() {
+        return NatTunnelInterfaceStateListener.this;
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<StateTunnelList> instanceIdentifier, StateTunnelList add) {
+        LOG.trace("NAT Service : TEP addtion---- {}", add);
+        hndlTepEvntsForDpn(add, TunnelAction.TUNNEL_EP_ADD);
+    }
+
+    @Override
+    protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
+        LOG.trace("NAT Service : TEP deletion---- {}", del);
+        hndlTepEvntsForDpn(del, TunnelAction.TUNNEL_EP_DELETE);
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
+        LOG.trace("NAT Service : Tunnel updation---- {}", update);
+        //UPDATE IS A SEQUENCE OF DELETE AND ADD EVENTS . DELETE MIGHT HAVE CHANGED THE PRIMARY AND ADVERTISED. SO
+        // NOTHING TO HANDLE
+    }
+
+    private int getTunnelType (StateTunnelList stateTunnelList) {
+        int tunTypeVal = 0;
+        if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
+            tunTypeVal = NatConstants.ITMTunnelLocType.Internal.getValue();
+        } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
+            tunTypeVal = NatConstants.ITMTunnelLocType.External.getValue();
+        } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
+            tunTypeVal = NatConstants.ITMTunnelLocType.Hwvtep.getValue();
+        } else {
+            tunTypeVal = NatConstants.ITMTunnelLocType.Invalid.getValue();
+        }
+        return tunTypeVal;
+    }
+
+    void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, Uuid networkId) {
+        //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
+        //remove miss entry to NAPT switch
+        //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
+
+        //get ExternalIpIn prior
+        List<String> externalIpCache;
+        //HashMap Label
+        HashMap<String,Long> externalIpLabel;
+        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}",routerName);
+            return;
+        }
+        externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker,routerId);
+        externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker,routerId);
+        try {
+            final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+            if (externalVpnName == null) {
+                LOG.error("NAT Service : SNAT -> No VPN associated with ext nw {} in router {}",
+                        networkId, routerId);
+                return;
+            }
+
+            BigInteger naptSwitch = dpnId;
+            boolean naptStatus = naptSwitchHA.isNaptSwitchDown(routerName,dpnId,naptSwitch,routerVpnId,externalIpCache,false);
+            if (!naptStatus) {
+                LOG.debug("NAT Service : SNAT -> NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+                        dpnId, routerName);
+                long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
+                FlowEntity flowEntity = null;
+                try {
+                    flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.DEL_FLOW);
+                    if (flowEntity == null) {
+                        LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {} groupIs {}",routerName,dpnId,groupId);
+                        return;
+                    }
+                    LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity {}",flowEntity);
+                    mdsalManager.removeFlow(flowEntity);
+
+                } catch (Exception ex) {
+                    LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+                    return;
+                }
+                LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+                //remove group
+                GroupEntity groupEntity = null;
+                try {
+                    groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
+                            GroupTypes.GroupAll, null);
+                    LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
+                    mdsalManager.removeGroup(groupEntity);
+                } catch (Exception ex) {
+                    LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}",groupEntity,ex);
+                    return;
+                }
+                LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routerName {}", dpnId, routerName);
+            } else {
+                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, dpnId,externalIpLabel);
+                //remove table 26 flow ppointing to table46
+                FlowEntity flowEntity = null;
+                try {
+                    flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId, NatConstants.DEL_FLOW);
+                    if (flowEntity == null) {
+                        LOG.debug("NAT Service : SNAT -> Failed to populate flowentity for router {} with dpnId {}",routerName,dpnId);
+                        return;
+                    }
+                    LOG.debug("NAT Service : SNAT -> Removing default SNAT miss entry flow entity for router {} with dpnId {} in napt switch {}"
+                            ,routerName,dpnId,naptSwitch);
+                    mdsalManager.removeFlow(flowEntity);
+
+                } catch (Exception ex) {
+                    LOG.debug("NAT Service : SNAT -> Failed to remove default SNAT miss entry flow entity {} : {}",flowEntity,ex);
+                    return;
+                }
+                LOG.debug("NAT Service : SNAT -> Removed default SNAT miss entry flow for dpnID {} with routername {}", dpnId, routerName);
+
+                //best effort to check IntExt model
+                naptSwitchHA.bestEffortDeletion(routerId,routerName,externalIpLabel);
+            }
+        } catch (Exception ex) {
+            LOG.debug("NAT Service : SNAT -> Exception while handling naptSwitch down for router {} : {}",routerName,ex);
+        }
+    }
+
+    private void hndlTepEvntsForDpn(StateTunnelList stateTunnelList, TunnelAction tunnelAction) {
+        final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
+        final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
+        final String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
+        LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
+                destTepIp);
+        int tunTypeVal = getTunnelType(stateTunnelList);
+
+        LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
+
+        try {
+            String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
+            String tunnelType = stateTunnelList.getTransportType().toString();
+            String tunnelName = stateTunnelList.getTunnelInterfaceName();
+
+            if(tunTypeVal == NatConstants.ITMTunnelLocType.Internal.getValue()){
+                LOG.debug("NAT Service : Ignoring TEP event {} for the DPN {} " +
+                        "since its a INTERNAL TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
+                        "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
+                return;
+            }else if(tunTypeVal == NatConstants.ITMTunnelLocType.Invalid.getValue()){
+                LOG.warn("NAT Service : Ignoring TEP event {} for the DPN {} " +
+                        "since its a INVALID TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and " +
+                        "TUNNEL NAME {} ", tunnelAction, srcTepId, tunnelType, srcTepIp, destTepIp, tunnelName);
+                return;
+            }
+
+            switch(tunnelAction){
+                case TUNNEL_EP_ADD:
+                    if(!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
+                        LOG.debug("NAT Service : Unable to process TEP ADD");
+                    }
+                    break;
+                case TUNNEL_EP_DELETE:
+                    if(!handleTepDelForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)){
+                        LOG.debug("NAT Service : Unable to process TEP DEL");
+                    }
+                    break;
+            }
+        } catch (Exception e) {
+            LOG.error("NAT Service : Unable to handle the TEP event.", e);
+            return;
+        }
+    }
+
+    private boolean hndlTepAddForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
+                                               String destTepIp) throws Exception{
+        LOG.trace("NAT Service: TEP ADD ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
+                " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
+
+        InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
+        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
+                .OPERATIONAL, dpnRoutersListId);
+        if (!optionalRouterDpnList.isPresent()) {
+            LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM " +
+                            "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
+                    tunnelType, srcTepIp, destTepIp, tunnelName);
+            return false;
+        }
+
+        List<RoutersList> routersList = optionalRouterDpnList.get().getRoutersList();
+        if(routersList == null) {
+            LOG.debug("NAT Service : Ignoring TEP add for the DPN {} since no routers are associated" +
+                    " for the DPN having the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
+                    "TUNNEL NAME {} ", srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
+            return false;
+        }
+
+        String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
+        for (RoutersList router : routersList) {
+
+            LOG.debug("NAT Service : TEP ADD : DNAT -> Advertising routes for router {} ", router.getRouter());
+            hndlTepAddForDnatInEachRtr(router, nextHopIp, srcDpnId);
+
+            LOG.debug("NAT Service : TEP ADD : SNAT -> Advertising routes for router {} ", router.getRouter());
+            hndlTepAddForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp,
+                    tunnelName, nextHopIp);
+        }
+        return true;
+    }
+
+    private boolean handleTepDelForAllRtrs(BigInteger srcDpnId, String tunnelType, String tunnelName, String srcTepIp,
+                                               String destTepIp) throws Exception{
+
+        LOG.trace("NAT Service: TEP DEL ----- for EXTERNAL/HWVTEP ITM Tunnel, TYPE {} ,State is UP b/w SRC IP" +
+                " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
+
+        // 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.
+        String endpointIpForDPN = null;
+        try {
+            endpointIpForDPN = NatUtil.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
+        } catch (Exception e) {
+                /* this dpn does not have the VTEP */
+            LOG.debug("NAT Service : DPN {} does not have the VTEP", srcDpnId);
+            endpointIpForDPN = null;
+        }
+
+        if (endpointIpForDPN != null) {
+            LOG.trace("NAT Service : Ignore TEP DELETE event received for DPN {} VTEP IP {} since its the other end DPN w.r.t the delted TEP", srcDpnId,
+                    srcTepIp);
+            return false;
+        }
+
+        List<RoutersList> routersList = null;
+        InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
+        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
+                .OPERATIONAL, dpnRoutersListId);
+        if (optionalRouterDpnList.isPresent()) {
+            routersList = optionalRouterDpnList.get().getRoutersList();
+        }else{
+            LOG.warn("NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event for the ITM " +
+                            "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ", srcDpnId,
+                    tunnelType, srcTepIp, destTepIp, tunnelName);
+            return false;
+        }
+
+        if(routersList == null) {
+            LOG.debug("NAT Service : DPN {} does not have the Routers presence", srcDpnId);
+            return false;
+        }
+
+        for (RoutersList router : routersList) {
+            LOG.debug("NAT Service :  TEP DEL : DNAT -> Withdrawing routes for router {} ", router.getRouter());
+            hndlTepDelForDnatInEachRtr(router, srcDpnId);
+            LOG.debug("NAT Service :  TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
+                    router.getRouter());
+            hndlTepDelForSnatInEachRtr(router, srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
+        }
+        return true;
+    }
+
+    private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
+                                        String srcTepIp, String destTepIp, String tunnelName, String nextHopIp){
+
+        /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
+                 Advertise to the BGP about the new route to the external IP having the new TEP IP
+                  added as the next hop IP
+         */
+        String routerName = router.getRouter();
+
+        // Check if this is externalRouter else ignore
+        InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
+        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
+                .CONFIGURATION, extRoutersId);
+        if (!routerData.isPresent()) {
+            LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
+                    routerName);
+            return;
+        }
+
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        if (naptId == null || naptId.equals(BigInteger.ZERO)) {
+            LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since" +
+                    " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
+                    "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
+            return;
+        }
+
+        //Check if the DPN having the router is the NAPT switch
+        if( !naptId.equals(srcDpnId)){
+            /*
+            1) Install default NAT rule from table 21 to 26
+            2) Install the group which forward packet to the tunnel port for the NAPT switch.
+            3) Install the flow 26 which forwards the packet to the group.
+            */
+            if (!hndlTepAddOnNonNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerName, routerId)){
+                LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
+                return;
+            }
+            return;
+        }
+        if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId, routerData, nextHopIp)){
+            LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
+            return;
+        }
+        return;
+    }
+
+    private boolean hndlTepAddOnNonNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp, String destTepIp,
+                                                String tunnelName, String routerName, long routerId){
+
+        /*
+        1) Install default NAT rule from table 21 to 26
+        2) Install the group which forward packet to the tunnel port for the NAPT switch.
+        3) Install the flow 26 which forwards the packet to the group.
+        */
+        LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
+                        "its THE NON NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " + "and TUNNEL NAME {} ",
+                srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
+        LOG.debug("NAT Service : SNAT -> Install default NAT rule from table 21 to 26");
+        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
+        Long vpnId;
+        if (vpnName == null) {
+            LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}",routerId);
+            vpnId = routerId;
+            if (vpnId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : SNAT -> Invalid Internal VPN ID returned for routerName {}",routerId);
+                return false;
+            }
+            LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerName);
+            //Install default entry in FIB to SNAT table
+            LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
+                    " vpn {}...", srcDpnId,routerName,vpnId);
+            defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId);
+
+            LOG.debug("NAT Service : SNAT -> Install the group which forward packet to the tunnel port for the NAPT switch" +
+                    " and the flow 26 which forwards to group");
+            externalRouterListner.handleSwitches(srcDpnId, routerName, srcDpnId);
+        } else {
+            LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) associated to router {}",routerId);
+            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+            if (vpnId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerId);
+                return false;
+            }
+            if (routerId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : SNAT -> Invalid routId returned for routerName {}",routerId);
+                return false;
+            }
+            LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}",vpnId, routerId);
+            //Install default entry in FIB to SNAT table
+            LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
+                    "with vpnId {}...", srcDpnId,routerId,vpnId);
+            defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
+
+            LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
+            List<BucketInfo> bucketInfoForNonNaptSwitches = externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
+            long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
+
+            LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
+                    vpnId, groupId, srcDpnId);
+            FlowEntity flowEntity = externalRouterListner.buildSnatFlowEntityWithUpdatedVpnId(srcDpnId, routerName, groupId, vpnId);
+            mdsalManager.installFlow(flowEntity);
+        }
+        return true;
+    }
+
+    private boolean hndlTepAddOnNaptSwitch(BigInteger srcDpnId, String tunnelType, String srcTepIp,
+                                             String destTepIp, String tunnelName, long routerId,
+                                             Optional<Routers> routerData, String nextHopIp){
+        String routerName = routerData.get().getRouterName();
+        LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since " +
+                "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} " +
+                "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
+
+        Uuid networkId = routerData.get().getNetworkId();
+        if (networkId == null) {
+            LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the " +
+                    "external network", routerName);
+            return false;
+        }
+
+        LOG.debug("NAT Service : SNAT -> Router {} is associated with Ext nw {}", routerId, networkId);
+        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
+        Long vpnId;
+        if (vpnName == null) {
+            LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
+            vpnId = NatUtil.getVpnId(dataBroker, routerId);
+            if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
+                LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
+                return false;
+            }
+            LOG.debug("NAT Service : SNAT -> Retrieved External VPN-ID {} for router {}", vpnId, routerId);
+        } else {
+            LOG.debug("NAT Service : SNAT -> Private BGP VPN associated to router {}", routerId);
+            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+            if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : Invalid vpnId returned for routerName {}", routerName);
+                return false;
+            }
+            LOG.debug("NAT Service : SNAT -> Retrieved vpnId {} for router {}", vpnId, routerId);
+        }
+
+        /*1) Withdraw the old route to the external IP from the BGP which was having the
+             next hop as the old TEP IP.
+          2) Advertise to the BGP about the new route to the external IP having the
+          new TEP IP as the next hop.
+          3) Populate a new FIB entry with the next hop IP as the new TEP IP using the
+          FIB manager.
+        */
+
+        //Withdraw the old route to the external IP from the BGP which was having the
+        //next hop as the old TEP IP.
+        final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+        if (externalVpnName == null) {
+            LOG.error("NAT Service :  SNAT -> No VPN associated with ext nw {} in router {}",
+                    networkId, routerId);
+            return false;
+        }
+        List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        if (externalIps != null) {
+            LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
+            for (String externalIp : externalIps) {
+                String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
+                LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
+                fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
+            }
+        }
+
+        /*
+        Advertise to the BGP about the new route to the external IP having the
+        new TEP IP as the next hop.
+        Populate a new FIB entry with the next hop IP as the new TEP IP using the
+        FIB manager.
+        */
+        String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
+        if (externalIps != null) {
+            for (final String externalIp : externalIps) {
+                Long label = externalRouterListner.checkExternalIpLabel(routerId,
+                        externalIp);
+                if(label == null || label == NatConstants.INVALID_ID){
+                    LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid" );
+                    return false;
+                }
+
+                LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}", externalIp,
+                        nextHopIp);
+                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp, nextHopIp,
+                        label, LOG, RouteOrigin.STATIC);
+
+                LOG.debug("NAT Service : SNAT -> Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port");
+                List<Instruction> customInstructions = new ArrayList<>();
+                customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.INBOUND_NAPT_TABLE }).
+                        buildInstruction(0));
+                CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId).
+                        setInstruction(customInstructions).setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+                Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
+                ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
+
+                Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
+
+                    @Override
+                    public void onFailure(Throwable error) {
+                        LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
+                    }
+
+                    @Override
+                    public void onSuccess(RpcResult<Void> result) {
+                        if(result.isSuccessful()) {
+                            LOG.info("NAT Service : SNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
+                        } else {
+                            LOG.error("NAT Service : SNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}",
+                                    externalIp, srcDpnId, result.getErrors());
+                        }
+                    }
+                });
+            }
+        }
+        return true;
+    }
+
+    private void hndlTepAddForDnatInEachRtr(RoutersList router, String nextHopIp, BigInteger tepAddedDpnId){
+        //DNAT : Advertise the new route to the floating IP having the new TEP IP as the next hop IP
+        final String routerName = router.getRouter();
+
+        InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+        Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
+                .CONFIGURATION, routerPortsId);
+        if (!optRouterPorts.isPresent()) {
+            LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
+                    "FloatinIpInfo", routerName);
+            return;
+        }
+        RouterPorts routerPorts = optRouterPorts.get();
+        List<Ports> interfaces = routerPorts.getPorts();
+
+        Uuid extNwId = routerPorts.getExternalNetworkId();
+        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
+        if (vpnName == null) {
+            LOG.info("NAT Service : DNAT -> No External VPN associated with ext nw {} for router {}",
+                    extNwId, routerName);
+            return;
+        }
+
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        for (Ports port : interfaces) {
+            //Get the DPN on which this interface resides
+            final String interfaceName = port.getPortName();
+            final BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
+            if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
+                LOG.info("NAT Service : DNAT -> Skip processing Floating ip configuration for the port {}, since no DPN present for it", interfaceName);
+                continue;
+            }
+            if(!fipCfgdDpnId.equals(tepAddedDpnId)) {
+                LOG.debug("NAT Service : DNAT -> TEP added DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
+                        tepAddedDpnId, fipCfgdDpnId, interfaceName);
+                continue;
+            }
+            List<IpMapping> ipMapping = port.getIpMapping();
+            for (final IpMapping ipMap : ipMapping) {
+                final String internalIp = ipMap.getInternalIp();
+                final String externalIp = ipMap.getExternalIp();
+                LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured for the port: {}",
+                        externalIp, interfaceName);
+                long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
+                if(label == NatConstants.INVALID_ID){
+                    LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid" );
+                    return;
+                }
+                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", nextHopIp, label, LOG, RouteOrigin.STATIC);
+
+                //Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port
+                List<Instruction> customInstructions = new ArrayList<>();
+                customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PDNAT_TABLE }).buildInstruction(0));
+                CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
+                        .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+                Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
+                ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
+
+                Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
+
+                    @Override
+                    public void onFailure(Throwable error) {
+                        LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
+                    }
+
+                    @Override
+                    public void onSuccess(RpcResult<Void> result) {
+                        if(result.isSuccessful()) {
+                            LOG.info("NAT Service : DNAT -> Successfully installed custom FIB routes for prefix {}", externalIp);
+                        } else {
+                            LOG.error("NAT Service : DNAT -> Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, fipCfgdDpnId, result.getErrors());
+                        }
+                    }
+                });
+
+            }
+        }
+    }
+
+    private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
+                                              String srcTepIp, String destTepIp, String tunnelName){
+        /*SNAT :
+            1) Elect a new switch as the primary NAPT
+            2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
+            3) This will make sure old routes are withdrawn and new routes are advertised.
+         */
+
+        String routerName = router.getRouter();
+        LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router" +
+                " {}", routerName);
+
+        // Check if this is externalRouter else ignore
+        InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
+        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
+                .CONFIGURATION, extRoutersId);
+        if (!routerData.isPresent()) {
+            LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
+                    routerName);
+            return;
+        }
+
+        //Check if the router ID is valid
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("NAT Service : SNAT -> Invalid ROUTER-ID {} returned for routerName {}", routerId, routerName);
+            return;
+        }
+
+        //Check if the DPN having the router is the NAPT switch
+        BigInteger naptId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
+        if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
+            LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since" +
+                    " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and" +
+                    "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
+            return;
+        }
+
+        Uuid networkId = routerData.get().getNetworkId();
+        if(networkId == null) {
+            LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} " +
+                    "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} " +
+                    "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
+            return;
+        }
+
+        LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
+        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
+        Long vpnId;
+        if (vpnName == null) {
+            LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
+            vpnId = routerId;
+
+            //Install default entry in FIB to SNAT table
+            LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with" +
+                    " vpn {}...", dpnId,routerName,vpnId);
+            defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+        } else {
+            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+            if (vpnId == NatConstants.INVALID_ID) {
+                LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
+                return;
+            }
+            LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}", vpnId, routerName);
+            //Install default entry in FIB to SNAT table
+            LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} " +
+                    "with vpnId {}...", dpnId, routerId, vpnId);
+            defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
+        }
+
+        if (routerData.get().isEnableSnat()) {
+            LOG.info("NAT Service : SNAT enabled for router {}", routerId);
+
+            long routerVpnId = routerId;
+            long bgpVpnId = NatConstants.INVALID_ID;
+            Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+            if (bgpVpnUuid != null) {
+                bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+            }
+            if (bgpVpnId != NatConstants.INVALID_ID){
+                LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated to the router {}", bgpVpnId, routerName);
+                routerVpnId = bgpVpnId;
+            }else{
+                LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}", routerVpnId, routerName);
+            }
+            //Re-elect the other available switch as the NAPT switch and program the NAT flows.
+            removeSNATFromDPN(dpnId, routerName ,routerVpnId, networkId);
+        } else {
+            LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
+        }
+    }
+
+    private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId){
+        //DNAT : Withdraw the routes from the BGP
+        String routerName = router.getRouter();
+        LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
+                routerName);
+
+        InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
+        Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType
+                .CONFIGURATION, routerPortsId);
+        if(!optRouterPorts.isPresent()) {
+            LOG.debug("NAT Service : DNAT -> Could not read Router Ports data object with id: {} from DNAT " +
+                            "FloatingIpInfo",
+                    routerName);
+            return;
+        }
+        RouterPorts routerPorts = optRouterPorts.get();
+        List<Ports> interfaces = routerPorts.getPorts();
+        Uuid extNwId = routerPorts.getExternalNetworkId();
+        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
+        if(vpnName == null) {
+            LOG.info("NAT Service : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
+                    extNwId, routerName);
+            return;
+        }
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        for(Ports port : interfaces) {
+            //Get the DPN on which this interface resides
+            String interfaceName = port.getPortName();
+            BigInteger fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
+            if(fipCfgdDpnId.equals(BigInteger.ZERO)) {
+                LOG.info("NAT Service : DNAT -> Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
+                continue;
+            }
+            if(!fipCfgdDpnId.equals(tepDeletedDpnId)) {
+                LOG.info("NAT Service : DNAT -> TEP deleted DPN {} is not the DPN {} which has the floating IP configured for the port: {}",
+                        tepDeletedDpnId, fipCfgdDpnId, interfaceName);
+                continue;
+            }
+            List<IpMapping> ipMapping = port.getIpMapping();
+            for(IpMapping ipMap : ipMapping) {
+                String internalIp = ipMap.getInternalIp();
+                String externalIp = ipMap.getExternalIp();
+                LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} configured for the port: {}",
+                        externalIp, interfaceName);
+                NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
+                long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
+                if(label == NatConstants.INVALID_ID){
+                    LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the MPLS label to the tunnel since label is invalid" );
+                    return;
+                }
+                RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
+                Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
+                ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
+
+                Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
+
+                    @Override
+                    public void onFailure(Throwable error) {
+                        LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing the MPLS label to the tunnel since label is invalid ", error);
+                    }
+
+                    @Override
+                    public void onSuccess(RpcResult<Void> result) {
+                        if(result.isSuccessful()) {
+                            LOG.info("NAT Service : DNAT -> Successfully removed the entry pushing the MPLS label to the tunnel");
+                        } else {
+                            LOG.error("NAT Service : DNAT -> Error in fib rpc call to remove the table 21 entry pushing the MPLS label to the tunnnel due to {}", result.getErrors());
+                        }
+                    }
+                });
+
+            }
+        }
+    }
+}
index b5a2c6fe5c446891e22303a335b7ee9238605b36..4c5b981beb36ee47e9994aeae7703943a21f1f02 100644 (file)
@@ -138,10 +138,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfacesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpnRouters;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
@@ -617,7 +624,7 @@ public class NatUtil {
          * NodeConnectorId is of form 'openflow:dpnid:portnum'
          */
         String[] split = portId.getValue().split(OF_URI_SEPARATOR);
-        if (split.length != 2) {
+        if (split == null || split.length != 3) {
             return null;
         }
         return split[1];
@@ -1102,6 +1109,49 @@ public class NatUtil {
                     routerDpnListBuilder.build(), true);
         }
     }
+
+    static void addToDpnRoutersMap(DataBroker broker, String routerName, String interfaceName,
+                                          OdlInterfaceRpcService ifaceMgrRpcService, WriteTransaction writeOperTxn) {
+        BigInteger dpId = getDpnForInterface(ifaceMgrRpcService, interfaceName);
+        if(dpId.equals(BigInteger.ZERO)) {
+            LOG.warn("NAT Service : Could not retrieve dp id for interface {} to handle router {} association model", interfaceName, routerName);
+            return;
+        }
+
+        LOG.debug("NAT Service : Adding the DPN {} and router {} for the Interface {} in the ODL-L3VPN : " +
+                        "DPNRouters map",
+                dpId, routerName, interfaceName);
+        InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(dpId);
+
+        Optional<DpnRoutersList> optionalDpnRoutersList = read(broker, LogicalDatastoreType.OPERATIONAL, dpnRoutersListIdentifier);
+
+        if (optionalDpnRoutersList.isPresent()) {
+            RoutersList routersList = new RoutersListBuilder().setKey(new RoutersListKey(routerName)).setRouter(routerName)
+                    .build();
+            List<RoutersList> routersListFromDs = optionalDpnRoutersList.get().getRoutersList();
+            if(!routersListFromDs.contains(routersList)) {
+                LOG.debug("NAT Service : Router {} not present for the DPN {}" +
+                        " in the ODL-L3VPN : DPNRouters map", routerName, dpId);
+                writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, dpnRoutersListIdentifier.child(RoutersList.class, new
+                        RoutersListKey(routerName)), routersList, true);
+            }else{
+                LOG.debug("NAT Service : Router {} already mapped to the DPN {} in the ODL-L3VPN : DPNRouters map",
+                        routerName, dpId);
+            }
+        } else {
+            LOG.debug("NAT Service : Building new DPNRoutersList for the Router {} present in the DPN {} " +
+                    "ODL-L3VPN : DPNRouters map", routerName, dpId);
+            DpnRoutersListBuilder dpnRoutersListBuilder = new DpnRoutersListBuilder();
+            dpnRoutersListBuilder.setDpnId(dpId);
+            RoutersListBuilder routersListBuilder = new RoutersListBuilder();
+            routersListBuilder.setRouter(routerName);
+            dpnRoutersListBuilder.setRoutersList(Arrays.asList(routersListBuilder.build()));
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
+                    getDpnRoutersId(dpId),
+                    dpnRoutersListBuilder.build(), true);
+        }
+    }
+
     static void removeFromNeutronRouterDpnsMap(DataBroker broker, String routerName, String interfaceName,
                                                   BigInteger dpId, WriteTransaction writeOperTxn) {
         if(dpId.equals(BigInteger.ZERO)) {
@@ -1181,6 +1231,113 @@ public class NatUtil {
             }
         }
     }
+
+    static void removeFromDpnRoutersMap(DataBroker broker, String routerName, String vpnInterfaceName,
+                                        OdlInterfaceRpcService ifaceMgrRpcService, WriteTransaction writeOperTxn) {
+        BigInteger dpId = getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
+        if (dpId.equals(BigInteger.ZERO)) {
+            LOG.warn("NAT Service : removeFromDpnRoutersMap() : Could not retrieve DPN ID for interface {} to handle router {} dissociation model",
+                    vpnInterfaceName, routerName);
+            return;
+        }
+        removeFromDpnRoutersMap(broker, routerName, vpnInterfaceName, dpId, ifaceMgrRpcService, writeOperTxn);
+    }
+
+    static void removeFromDpnRoutersMap(DataBroker broker, String routerName, String vpnInterfaceName, BigInteger curDpnId,
+                                           OdlInterfaceRpcService ifaceMgrRpcService, WriteTransaction writeOperTxn) {
+        /*
+            1) Get the DpnRoutersList for the DPN.
+            2) Get the RoutersList identifier for the DPN and router.
+            3) Get the VPN interfaces for the router (routerList) through which it is connected to the DPN.
+            4) If the removed VPN interface is the only interface through which the router is connected to the DPN,
+             then remove RouterList.
+         */
+
+        LOG.debug("NAT Service : removeFromDpnRoutersMap() : Removing the DPN {} and router {} for the Interface {}" +
+                " in the ODL-L3VPN : DPNRouters map", curDpnId, routerName, vpnInterfaceName);
+
+        //Get the dpn-routers-list instance for the current DPN.
+        InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(curDpnId);
+        Optional<DpnRoutersList> dpnRoutersListData = read(broker, LogicalDatastoreType.OPERATIONAL,
+                dpnRoutersListIdentifier);
+
+        if (dpnRoutersListData == null || !dpnRoutersListData.isPresent()) {
+            LOG.debug("NAT Service : dpn-routers-list is not present for DPN {} in the ODL-L3VPN:dpn-routers model",
+                    curDpnId);
+            return;
+        }
+
+        //Get the routers-list instance for the router on the current DPN only
+        InstanceIdentifier<RoutersList> routersListIdentifier = getRoutersList(curDpnId, routerName);
+        Optional<RoutersList> routersListData = read(broker, LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+
+        if (routersListData == null || !routersListData.isPresent()) {
+            LOG.debug("NAT Service : routers-list is not present for the DPN {} in the ODL-L3VPN:dpn-routers model",
+                    curDpnId);
+            return;
+        }
+
+        LOG.debug("NAT Service : Get the interfaces for the router {} from the NeutronVPN - router-interfaces-map",
+                routerName);
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.
+                interfaces.map.RouterInterfaces> routerInterfacesId = getRoutersInterfacesIdentifier(routerName);
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.
+                RouterInterfaces> routerInterfacesData = read(broker, LogicalDatastoreType.CONFIGURATION,
+                routerInterfacesId);
+
+        if (routerInterfacesData == null || !routerInterfacesData.isPresent()) {
+            LOG.debug("NAT Service : Unable to get the routers list for the DPN {}. Possibly all subnets removed" +
+                    " from router {} OR Router {} has been deleted. Hence DPN router model WILL be cleared ", curDpnId,
+                    routerName, routerName);
+            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+            return;
+        }
+
+        //Get the VM interfaces for the router on the current DPN only.
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces> vmInterfaces =
+                routerInterfacesData.get().getInterfaces();
+        if (vmInterfaces == null) {
+            LOG.debug("NAT Service : VM interfaces are not present for the router {} in the NeutronVPN - router-interfaces-map", routerName);
+            return;
+        }
+
+        //If the removed VPN interface is the only interface through which the router is connected to the DPN, then remove RouterList.
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.router.interfaces.Interfaces vmInterface :
+                vmInterfaces) {
+            String vmInterfaceName = vmInterface.getInterfaceId();
+            BigInteger vmDpnId = getDpnForInterface(ifaceMgrRpcService, vmInterfaceName);
+            if (vmDpnId.equals(BigInteger.ZERO) || !vmDpnId.equals(curDpnId)) {
+                LOG.debug("NAT Service : DPN ID {} for the removed interface {} is not the same as that of the DPN ID for the checked interface {} ",
+                        curDpnId, vpnInterfaceName, vmDpnId, vmInterfaceName);
+                continue;
+            }
+            if(!vmInterfaceName.equalsIgnoreCase(vpnInterfaceName)) {
+                LOG.debug("NAT Service : Router {} is present in the DPN {} through the other interface {} " +
+                        "Hence DPN router model WOULD NOT be cleared", routerName, curDpnId, vmInterfaceName);
+                return;
+            }
+        }
+        LOG.debug("NAT Service : Router {} is present in the DPN {} only through the interface {} " +
+                "Hence DPN router model WILL be cleared. Possibly last VM for the router " +
+                "deleted in the DPN", routerName, curDpnId);
+        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+
+    }
+
+    private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces>
+        getRoutersInterfacesIdentifier(String routerName){
+        return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfaces.class,
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.router.interfaces.map.RouterInterfacesKey(new Uuid(routerName)))
+                .build();
+    }
+
+    private static InstanceIdentifier<RoutersList> getRoutersList(BigInteger dpnId, String routerName) {
+        return InstanceIdentifier.builder(DpnRouters.class)
+                .child(DpnRoutersList.class, new DpnRoutersListKey(dpnId))
+                .child(RoutersList.class, new RoutersListKey(routerName)).build();
+    }
+
     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
         BigInteger nodeId = BigInteger.ZERO;
         try {
@@ -1194,10 +1351,10 @@ public class NatUtil {
             if (dpIdResult.isSuccessful()) {
                 nodeId = dpIdResult.getResult().getDpid();
             } else {
-                LOG.error("Could not retrieve DPN Id for interface {}", ifName);
+                LOG.error("NAT Service : Could not retrieve DPN Id for interface {}", ifName);
             }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Exception when getting dpn for interface {}", ifName,  e);
+        } catch (NullPointerException | InterruptedException | ExecutionException e) {
+            LOG.error("NAT Service : Exception when getting dpn for interface {}", ifName,  e);
         }
         return nodeId;
     }
@@ -1393,6 +1550,11 @@ public class NatUtil {
         return false;
     }
 
+    static InstanceIdentifier<DpnRoutersList> getDpnRoutersId(BigInteger dpnId) {
+        return InstanceIdentifier.builder(DpnRouters.class)
+                .child(DpnRoutersList.class, new DpnRoutersListKey(dpnId)).build();
+    }
+
     static InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
         return InstanceIdentifier.builder(NeutronRouterDpns.class)
                 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
index 2a9241fbefb958ff87dbcce7b7124f554890bc87..b9c1edae7efc6c9766d67ee2d767b13039920151 100644 (file)
     <argument ref="bgpManager" />
     <argument ref="vpnRpcService" />
     <argument ref="fibRpcService" />
+    <argument ref="fibManager" />
   </bean>
 
   <bean id="natNodeEventListener"
     <argument ref="odlInterfaceRpcService" />
   </bean>
 
+  <bean id="natTunnelInterfaceStateListener"
+        class="org.opendaylight.netvirt.natservice.internal.NatTunnelInterfaceStateListener"
+        init-method="init" destroy-method="close">
+    <argument ref="dataBroker" />
+    <argument ref="bgpManager" />
+    <argument ref="fibManager" />
+    <argument ref="sNATDefaultRouteProgrammer" />
+    <argument ref="naptSwitchHA" />
+    <argument ref="mdsalUtils" />
+    <argument ref="idManagerService" />
+    <argument ref="externalRoutersListener" />
+    <argument ref="odlInterfaceRpcService" />
+    <argument ref="floatingIPListener" />
+    <argument ref="fibRpcService" />
+  </bean>
+
 </blueprint>
index c18eb6efc541b0b71e465e710439f863cfe5ddf1..7d35cf51bb4fd8a01d088e80a40cd5c1f6cdea50 100644 (file)
@@ -387,6 +387,18 @@ module odl-l3vpn {
         }
     }
 
+    /* container to maintain mapping between DPN(s) and the routers */
+    container dpn-routers {
+        config false;
+        list dpn-routers-list {
+            key dpn-id;
+            leaf dpn-id { type uint64;}
+            list routers-list {
+                key router;
+                leaf router { type string;}
+            }
+        }
+    }
 
     container router-interfaces {
         list router-interface {