MRI version bumpup for Aluminium
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalRoutersListener.java
index ca833d5c1a3d6993e8f4bcf12e13de740659db17..3280c781c26824c2cc83964802865169cf76bccd 100644 (file)
@@ -7,12 +7,11 @@
  */
 package org.opendaylight.netvirt.natservice.internal;
 
-import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 
-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 com.google.common.util.concurrent.MoreExecutors;
 import java.math.BigInteger;
@@ -28,18 +27,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.infra.Datastore.Configuration;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
@@ -77,16 +73,21 @@ import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 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.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
@@ -114,6 +115,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
 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.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
@@ -151,7 +153,7 @@ import org.slf4j.LoggerFactory;
 
 
 @Singleton
-public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
+public class ExternalRoutersListener extends AbstractAsyncDataTreeChangeListener<Routers> {
     private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
 
     private static final Uint64 COOKIE_TUNNEL = Uint64.valueOf("9000000", 16).intern();
@@ -202,7 +204,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                    final JobCoordinator coordinator,
                                    final NatOverVxlanUtil natOverVxlanUtil,
                                    final IInterfaceManager interfaceManager) {
-        super(Routers.class, ExternalRoutersListener.class);
+        super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(ExtRouters.class)
+                .child(Routers.class),
+                Executors.newListeningSingleThreadExecutor("ExternalRoutersListener", LOG));
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
@@ -231,29 +235,32 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             this.natMode = NatMode.Controller;
             this.snatPuntTimeout = 0;
         }
+        init();
     }
 
-    @Override
-    @PostConstruct
     public void init() {
         LOG.info("{} init", getClass().getSimpleName());
         // This class handles ExternalRouters for Controller SNAT mode.
         // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
         if (natMode == NatMode.Controller) {
-            registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
             NatUtil.createGroupIdPool(idManager);
         }
     }
 
     @Override
-    protected InstanceIdentifier<Routers> getWildCardPath() {
-        return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
+    @PreDestroy
+    public void close() {
+        super.close();
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+    public void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
         // Populate the router-id-name container
         String routerName = routers.getRouterName();
         LOG.info("add : external router event for {}", routerName);
@@ -306,12 +313,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
 
         if (bgpVpnId != NatConstants.INVALID_ID) {
-            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
-                    extNwProvType);
+            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId,
+                routers.getNetworkId(),false, confTx, extNwProvType);
         } else {
             // write metadata and punt
             installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
-            handlePrimaryNaptSwitch(primarySwitchId, routerName, routerId, confTx);
+            handlePrimaryNaptSwitch(primarySwitchId, routerName, routerId, routers.getNetworkId(), confTx);
             // Now install entries in SNAT tables to point to Primary for each router
             List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
             for (Uint64 dpnId : switches) {
@@ -331,6 +338,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             for (String externalIpAddrPrefix : externalIps) {
                 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
                     + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+                externalIpAddrPrefix = NatUtil.validateAndAddNetworkMask(externalIpAddrPrefix);
                 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
                 );
             }
@@ -401,7 +409,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     protected void subnetRegisterMapping(Routers routerEntry, Uint32 segmentId) {
         LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
-        List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
+        List<String> externalIps = NatUtil.getIpsListFromExternalIps(
+                new ArrayList<ExternalIps>(routerEntry.getExternalIps().values()));
         int counter = 0;
         int extIpCounter = externalIps.size();
         LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
@@ -420,9 +429,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             try {
                 sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                                 LogicalDatastoreType.CONFIGURATION, subnetmapId);
-            } catch (ReadFailedException e) {
+            } catch (InterruptedException | ExecutionException e) {
                 LOG.error("Failed to read SubnetMap for  subnetmap Id {}", subnetmapId, e);
-                sn = Optional.absent();
+                sn = Optional.empty();
             }
             if (sn.isPresent()) {
                 // subnets
@@ -502,7 +511,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     bgpVpnId, bgpVpnName);
                 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
                     .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
-                confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
+                confTx.mergeParentStructurePut(getRoutersIdentifier(bgpVpnId), rtrs);
             }
             if (create) {
                 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
@@ -928,7 +937,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return listBucketInfo;
     }
 
-    protected void handlePrimaryNaptSwitch(Uint64 dpnId, String routerName, Uint32 routerId,
+    protected void handlePrimaryNaptSwitch(Uint64 dpnId, String routerName, Uint32 routerId, Uuid externalNwUuid,
         TypedWriteTransaction<Configuration> confTx) {
 
        /*
@@ -953,12 +962,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         if (networkId != null) {
             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
             if (vpnUuid != null) {
-                Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                Uint32 extVpnId = NatUtil.getExternalVpnIdForExtNetwork(dataBroker, externalNwUuid);
                 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
                     installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
                     //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
-                    if (vpnId != NatConstants.INVALID_ID) {
-                        installNaptPfibEntry(dpnId, vpnId, null);
+                    if (extVpnId != null && extVpnId != NatConstants.INVALID_ID) {
+                        installNaptPfibEntry(dpnId, extVpnId, null);
                     }
                     return Collections.emptyList();
                 });
@@ -1012,6 +1021,31 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
             return;
         }
+        Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(
+                new ArrayList<ExternalIps>(router.getExternalIps().values()));
+        // FLAT/VLAN case having external-subnet as VPN
+        String externalSubnetVpn = null;
+        if (externalSubnetList != null && !externalSubnetList.isEmpty()) {
+            Boolean isExternalIpsAdvertized = Boolean.FALSE;
+            for (Uuid externalSubnetId : externalSubnetList) {
+                Optional<Subnets> externalSubnet = NatUtil
+                    .getOptionalExternalSubnets(dataBroker, externalSubnetId);
+                // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
+                if (externalSubnet.isPresent()) {
+                    externalSubnetVpn = externalSubnetId.getValue();
+                    advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
+                        externalSubnetVpn, routerId, routerName,
+                        externalIp, networkId, router, confTx);
+                    isExternalIpsAdvertized = Boolean.TRUE;
+                }
+            }
+            if (isExternalIpsAdvertized) {
+                LOG.trace("External Ips {} advertized for Router {}", router.getExternalIps(), routerName);
+                return;
+            }
+        }
+
+        // VXVLAN/GRE case having Internet-VPN
         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
         if (vpnName == null) {
             LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
@@ -1177,20 +1211,22 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         matches.add(MatchEthernetType.MPLS_UNICAST);
         matches.add(new MatchMplsLabel(serviceId.longValue()));
 
-        List<Instruction> instructions = new ArrayList<>();
+        Map<InstructionKey, Instruction> instructionsMap = new HashMap<InstructionKey, Instruction>();
+        int instructionKey = 0;
         List<ActionInfo> actionsInfos = new ArrayList<>();
         //NAT is required for IPv4 only. Hence always etherType will be IPv4
         actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
         Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
-        instructions.add(writeInstruction);
-        instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
+        instructionsMap.put(new InstructionKey(++instructionKey), writeInstruction);
+        instructionsMap.put(new InstructionKey(++instructionKey),
+                new InstructionGotoTable(tableId).buildInstruction(1));
 
         // Install the flow entry in L3_LFIB_TABLE
         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
             10, flowRef, 0, 0,
-            COOKIE_VM_LFIB_TABLE, matches, instructions);
+            COOKIE_VM_LFIB_TABLE, matches, instructionsMap);
 
         mdsalManager.addFlow(confTx, dpId, flowEntity);
 
@@ -1211,13 +1247,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         } else {
             mkMatches.add(new MatchTunnelId(Uint64.valueOf(serviceId)));
         }
-
+        Map<InstructionKey, Instruction> customInstructionsMap = new HashMap<InstructionKey, Instruction>();
+        int instructionKey = 0;
+        for (Instruction instructionObj : customInstructions) {
+            customInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
+        }
         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
             getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
                 NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
                 String.format("%s:%s", "TST Flow Entry ", serviceId), 0, 0,
                 Uint64.valueOf(COOKIE_TUNNEL.toJava().add(BigInteger.valueOf(serviceId.longValue()))),
-                mkMatches, customInstructions);
+                mkMatches, customInstructionsMap);
 
         mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
     }
@@ -1233,7 +1273,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     @Override
-    protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+    public void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
         LOG.trace("update : origRouter: {} updatedRouter: {}", original, update);
         String routerName = original.getRouterName();
         Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
@@ -1279,7 +1322,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                             Uuid networkUuid = original.getNetworkId();
                             LOG.info("update : SNAT disabled for Router {}", routerName);
                             Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-                            handleDisableSnat(original, networkUuid, externalIps, false, null,
+                            final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
+                            handleDisableSnat(original, networkUuid, externalIps, false, vpnName,
                                     dpnId, routerId, removeFlowInvTx);
                         }  else if (updatedSNATEnabled) {
                             LOG.info("update : SNAT enabled for Router {}", routerName);
@@ -1311,8 +1355,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     }
                     //Check if the Update is on External IPs
                     LOG.debug("update : Checking if this is update on External IPs for router {}", routerName);
-                    List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
-                    List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
+                    List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(
+                            new ArrayList<ExternalIps>(original.getExternalIps().values()));
+                    List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(
+                            new ArrayList<ExternalIps>(update.getExternalIps().values()));
 
                     //Check if the External IPs are removed during the update.
                     Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
@@ -1394,16 +1440,16 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                 ipPortMapping = SingleTransactionDataBroker
                                             .syncReadOptional(dataBroker,
                                                     LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
-                            } catch (ReadFailedException e) {
+                            } catch (InterruptedException | ExecutionException e) {
                                 LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
-                                ipPortMapping = Optional.absent();
+                                ipPortMapping = Optional.empty();
                             }
 
                             if (ipPortMapping.isPresent()) {
                                 for (IntextIpProtocolType intextIpProtocolType :
-                                        ipPortMapping.get().nonnullIntextIpProtocolType()) {
+                                        ipPortMapping.get().nonnullIntextIpProtocolType().values()) {
                                     ProtocolTypes protoType = intextIpProtocolType.getProtocol();
-                                    for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
+                                    for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                                         IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
                                         if (ipPortExternal.getIpAddress().equals(externalIp)) {
                                             List<String> removedInternalIpPorts =
@@ -1616,14 +1662,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         try {
             externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                         LogicalDatastoreType.OPERATIONAL, id);
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
-            externalCountersData = Optional.absent();
+            externalCountersData = Optional.empty();
         }
         if (externalCountersData.isPresent()) {
             ExternalIpsCounter externalIpsCounters = externalCountersData.get();
-            for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters()) {
-                for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter()) {
+            for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters().values()) {
+                for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter().values()) {
                     if (externalIpCount.getExternalIp().equals(externalIp)) {
                         if (externalIpCount.getCounter().toJava() != 0) {
                             return true;
@@ -1719,7 +1765,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     @Override
-    protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+    public void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
         LOG.trace("remove : Router delete method");
         /*
         ROUTER DELETE SCENARIO
@@ -1772,7 +1821,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     return;
                 } else {
                     Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-                    handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
+                    final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
+                    handleDisableSnat(router, networkUuid, externalIps, true, vpnName, primarySwitchId,
                             routerId, tx);
                 }
                 if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, routerName)
@@ -1809,7 +1859,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("handleDisableSnat : External Network Provider Type missing");
                 return;
             }
-            Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
+            Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(
+                    new ArrayList<ExternalIps>(router.getExternalIps().values()));
             removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
                     externalSubnetList, removeFlowInvTx, extNwProvType);
             removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
@@ -1853,9 +1904,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             try {
                 rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                                 LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
-            } catch (ReadFailedException e) {
+            } catch (InterruptedException | ExecutionException e) {
                 LOG.error("Failed to read NAPT switch for router {}", routerName, e);
-                rtrToNapt = Optional.absent();
+                rtrToNapt = Optional.empty();
             }
             if (rtrToNapt.isPresent()) {
                 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
@@ -2048,9 +2099,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             return;
         }
 
-        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
+        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
             String protocol = intextIpProtocolType.getProtocol().name();
-            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
+            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                 String ipPortInternal = ipPortMap.getIpPortInternal();
                 String[] ipPortParts = ipPortInternal.split(":");
                 if (ipPortParts.length != 2) {
@@ -2159,9 +2210,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
                 return;
             }
-            for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
+            for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
                 String protocol = intextIpProtocolType.getProtocol().name();
-                for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
+                for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                     String ipPortInternal = ipPortMap.getIpPortInternal();
                     String[] ipPortParts = ipPortInternal.split(":");
                     if (ipPortParts.length != 2) {
@@ -2285,6 +2336,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         //Remove custom FIB routes
         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
         for (String extIp : externalIps) {
+            extIp = NatUtil.validateAndAddNetworkMask(extIp);
             clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
         }
     }
@@ -2329,6 +2381,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
         final Uint32 label = tempLabel;
         final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
+        RemoveFibEntryInput input = null;
         if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
             LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
             Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
@@ -2343,9 +2396,19 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             }
         }
         final String externalVpn = vpnName;
-        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(externalVpn)
+        if (label != null && label.toJava() <= 0) {
+            LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
+                extIp, routerId);
+            input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
+                .setSourceDpid(dpnId).setIpAddress(externalIp)
+                .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
+        } else {
+            input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
                 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
                 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
+            removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
+            removeLFibTableEntry(dpnId, label, removeFlowInvTx);
+        }
         ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
 
         removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
@@ -2358,11 +2421,20 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
                 Futures.transformAsync(future, result -> {
                     //Release label
-                    if (result.isSuccessful()) {
+                    if (result.isSuccessful() && label != null && label.toJava() > 0) {
                         NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
                         RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
                             .setVpnName(externalVpn).setIpPrefix(externalIp).build();
-                        return vpnService.removeVpnLabel(labelInput);
+                        Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
+                        if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
+                            String errMsg = String.format(
+                                    "ExternalRoutersListener: RPC call to remove VPN label "
+                                            + "on dpn %s for prefix %s failed for vpn %s - %s",
+                                    dpnId, externalIp, result.getErrors());
+                            LOG.error(errMsg);
+                            return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                        }
+                        return JdkFutureAdapters.listenInPoolThread(labelFuture1);
                     } else {
                         String errMsg =
                             String.format("RPC call to remove custom FIB entries on dpn %s for "
@@ -2466,7 +2538,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                         if (result.isSuccessful()) {
                             RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
                                     .setVpnName(vpnName).setIpPrefix(externalIp).build();
-                            return vpnService.removeVpnLabel(labelInput);
+                            Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService
+                                    .removeVpnLabel(labelInput);
+                            if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
+                                String errMsg = String.format(
+                                        "RPC call to remove VPN label on dpn %s for prefix %s "
+                                                + "failed for vpn %s - %s", dpnId, externalIp, vpnName,
+                                        result.getErrors());
+                                LOG.error(errMsg);
+                                return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                            }
+                            return JdkFutureAdapters.listenInPoolThread(labelFuture1);
                         } else {
                             String errMsg =
                                     String.format("RPC call to remove custom FIB entries on dpn %s for "
@@ -2542,6 +2624,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
         NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName);
+        NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, vpnName), externalIp);
     }
 
     private void removeTunnelTableEntry(Uint64 dpnId, Uint32 serviceId,
@@ -2567,7 +2650,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
      * @param routerId - router id
      * @param bgpVpnName BGP VPN name
      */
-    public void changeLocalVpnIdToBgpVpnId(String routerName, Uint32 routerId, String bgpVpnName,
+    public void changeLocalVpnIdToBgpVpnId(String routerName, Uint32 routerId, String extNetwork, String bgpVpnName,
             TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
         LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
@@ -2590,8 +2673,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
                 // Get the group ID
                 Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
-                        extNwProvType);
+                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, new Uuid(extNetwork),
+                    true, writeFlowInvTx, extNwProvType);
             }
         }
     }
@@ -2603,7 +2686,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
      * @param routerId - router id
      * @param bgpVpnName BGP VPN name
      */
-    public void changeBgpVpnIdToLocalVpnId(String routerName, Uint32 routerId, String bgpVpnName,
+    public void changeBgpVpnIdToLocalVpnId(String routerName, Uint32 routerId, String bgpVpnName, String extNetwork,
             TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
         LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
@@ -2618,8 +2701,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
             // Get the group ID
             Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
-                    writeFlowInvTx, extNwProvType);
+            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId,
+                new Uuid(extNetwork), true, writeFlowInvTx, extNwProvType);
         }
     }
 
@@ -2632,14 +2715,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     .syncReadOptional(dataBroker,
                             LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
             return routerData.isPresent() && routerData.get().isEnableSnat();
-        } catch (ReadFailedException e) {
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("Failed to read data for router id {}", routerUuid, e);
             return false;
         }
     }
 
     public void installFlowsWithUpdatedVpnId(Uint64 primarySwitchId, String routerName, Uint32 bgpVpnId,
-                                             Uint32 routerId, boolean isSnatCfgd,
+                                             Uint32 routerId, Uuid extNwUuid, boolean isSnatCfgd,
                                              TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
 
         Uint32 changedVpnId = bgpVpnId;
@@ -2710,10 +2793,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
                 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
                         primarySwitchId);
-                Uint32 vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
-                //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
-                if (vpnId != NatConstants.INVALID_ID) {
-                    installNaptPfibEntry(primarySwitchId, vpnId, confTx);
+                //Get the VPN ID from the ExternalNetworks model
+                Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, extNwUuid);
+                if (vpnUuid != null) {
+                    Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                    //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table
+                    // matching on the VPN ID.
+                    if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
+                        installNaptPfibEntry(primarySwitchId, vpnId, confTx);
+                    }
+                } else {
+                    LOG.error("NAT Service : vpnUuid is null");
                 }
             }
         }
@@ -2736,8 +2826,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     routerId);
             return;
         }
-        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType()) {
-            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap()) {
+        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
+            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                 String ipPortInternal = ipPortMap.getIpPortInternal();
                 String[] ipPortParts = ipPortInternal.split(":");
                 if (ipPortParts.length != 2) {
@@ -2937,11 +3027,6 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    @Override
-    protected ExternalRoutersListener getDataTreeChangeListener() {
-        return ExternalRoutersListener.this;
-    }
-
     protected void installNaptPfibEntriesForExternalSubnets(String routerName, Uint64 dpnId,
                                                         @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
         Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,