Support for SNAT and DNAT features in L3 forwarding services.
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / NaptManager.java
diff --git a/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java b/natservice/natservice-impl/src/main/java/org/opendaylight/vpnservice/natservice/internal/NaptManager.java
new file mode 100644 (file)
index 0000000..db6a2b1
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * 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
+ */
+
+/*
+ * Created eyugsar 2016/12/1
+ */
+
+package org.opendaylight.vpnservice.natservice.internal;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutionException;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.net.util.SubnetUtils;
+import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.SnatintIpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternalBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.router.id.name.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+public class NaptManager  {
+    private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
+    private final DataBroker broker;
+    private IdManagerService idManager;
+    private static final long LOW_PORT = 49152L;
+    private static final long HIGH_PORT = 65535L;
+    private static boolean EXTSUBNET_FLAG = false;
+    private static boolean NEXT_EXTIP_FLAG = false;
+
+    public NaptManager(final DataBroker db) {
+        this.broker = db;
+    }
+
+    public void setIdManager(IdManagerService idManager) {
+        this.idManager = idManager;
+    }
+
+    protected void createNaptPortPool(String PoolName) {
+         LOG.debug("NAPT Service : createPortPool requested for : {}", PoolName);
+         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+             .setPoolName(PoolName)
+             .setLow(LOW_PORT)
+             .setHigh(HIGH_PORT)
+             .build();
+         try {
+             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+             if ((result != null) && (result.get().isSuccessful())) {
+                 LOG.debug("NAPT Service : Created PortPool");
+             } else {
+                 LOG.error("NAPT Service : Unable to create PortPool");
+             }
+         } catch (InterruptedException | ExecutionException e) {
+             LOG.error("Failed to create PortPool for NAPT Service",e);
+         }
+    }
+
+     // 1. napt service functions
+     /**
+      * this method is used to inform this service of what external IP address to be used
+      * as mapping when requested one for the internal IP address given in the input
+      * @param segmentId – segmentation in which the mapping to be used. Eg; routerid
+      * @param internal subnet prefix or ip address
+      * @param external subnet prefix or ip address
+      */
+
+      public void registerMapping(long segmentId, IPAddress internal, IPAddress external) {
+
+          LOG.debug("NAPT Service : registerMapping called with segmentid {}, internalIp {}, prefix {}, externalIp {} and prefix {} ", segmentId, internal.getIpAddress(),
+                internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength());
+        // Create Pool per ExternalIp and not for all IPs in the subnet. Create new Pools during getExternalAddressMapping if exhausted.
+        String externalIpPool;
+        if (external.getPrefixLength() !=0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) {  // subnet case
+            String externalSubnet = new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+            LOG.debug("NAPT Service : externalSubnet is : {}", externalSubnet);
+            SubnetUtils subnetUtils = new SubnetUtils(externalSubnet);
+            SubnetInfo subnetInfo = subnetUtils.getInfo();
+            externalIpPool = subnetInfo.getLowAddress();
+        } else {  // ip case
+            externalIpPool = external.getIpAddress();
+        }
+        createNaptPortPool(externalIpPool);
+
+        // Store the ip to ip map in Operational DS
+        String internalIp = internal.getIpAddress();
+        if(internal.getPrefixLength() != 0) {
+            internalIp =  new StringBuilder(64).append(internal.getIpAddress()).append("/").append(internal.getPrefixLength()).toString();
+        }
+        String externalIp = external.getIpAddress();
+        if(external.getPrefixLength() != 0) {
+            externalIp =  new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
+        }
+        IpMap ipm = new IpMapBuilder().setKey(new IpMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp).build();
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getIpMapIdentifier(segmentId, internalIp), ipm);
+        LOG.debug("NAPT Service : registerMapping exit after updating DS with internalIP {}, externalIP {}", internalIp, externalIp);
+     }
+
+
+     /**
+      * 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 sourceAddress - internal ip address/port pair
+      * @return external ip address/port
+      */
+     public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) {
+         LOG.debug("NAPT Service : getExternalAddressMapping called with segmentId {}, internalIp {} and port {}",
+                 segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
+        /*
+         1. Get Internal IP, Port in IP:Port format
+         2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
+         3. If True return SessionAddress of ExternalIp and Port
+         4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
+         */
+
+         //SessionAddress externalIpPort = new SessionAddress();
+         String internalIpPort = new StringBuilder(64).append(sourceAddress.getIpAddress()).append(":").append(sourceAddress.getPortNumber()).toString();
+
+         // First check existing Port Map.
+         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort ,protocol);
+         if(existingIpPort != null) {
+             // populate externalIpPort from IpPortMap and return
+             LOG.debug("NAPT Service : getExternalAddressMapping successfully returning existingIpPort as {} and {}", existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
+             return existingIpPort;
+         } else {
+             // Now check in ip-map
+             String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
+             if(externalIp == null) {
+                 LOG.error("NAPT Service : getExternalAddressMapping, Unexpected error, internal to external ip map does not exist");
+                 return null;
+             } else {
+                 /* Logic assuming internalIp is always ip and not subnet
+                  * case 1: externalIp is ip
+                  *        a) goto externalIp pool and getPort and return
+                  *        b) else return error
+                  * case 2: externalIp is subnet
+                  *        a) Take first externalIp and goto that Pool and getPort
+                  *             if port -> return
+                  *             else Take second externalIp and create that Pool and getPort
+                  *             if port ->return
+                  *             else
+                  *             Continue same with third externalIp till we exhaust subnet
+                  *        b) Nothing worked return error
+                  */
+                 SubnetUtils externalIpSubnet;
+                 List<String> allIps = new ArrayList<String>();
+                 String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
+                 if( !externalIp.contains(subnetPrefix) ) {
+                    EXTSUBNET_FLAG = true;
+                    externalIpSubnet = new SubnetUtils(externalIp);
+                    allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
+                    LOG.debug("NAPT Service : total count of externalIps available {}", externalIpSubnet.getInfo().getAddressCount());
+                 } else {
+                     LOG.debug("NAPT Service : getExternalAddress single ip case");
+                     if(externalIp.contains(subnetPrefix)) {
+                         String[] externalIpSplit = externalIp.split("/");
+                         String extIp = externalIpSplit[0];
+                         externalIp = extIp; //remove /32 what we got from checkIpMap
+                     }
+                     allIps.add(externalIp);
+                 }
+
+                 for(String extIp : allIps) {
+                    LOG.info("NAPT Service : Looping externalIPs with externalIP now as {}", extIp);
+                    if(NEXT_EXTIP_FLAG) {
+                        createNaptPortPool(extIp);
+                        LOG.debug("NAPT Service : Created Pool for next Ext IP {}", extIp);
+                    }
+                    AllocateIdInput getIdInput = new AllocateIdInputBuilder()
+                        .setPoolName(extIp).setIdKey(internalIpPort)
+                        .build();
+                     try {
+                        Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
+                        RpcResult<AllocateIdOutput> rpcResult;
+                        if ((result != null) && (result.get().isSuccessful())) {
+                            LOG.debug("NAPT Service : Got id from idManager");
+                            rpcResult = result.get();
+                        } else {
+                            LOG.error("NAPT Service : getExternalAddressMapping, idManager could not allocate id retry if subnet");
+                            if(!EXTSUBNET_FLAG) {
+                                LOG.error("NAPT Service : getExternalAddressMapping returning null for single IP case, may be ports exhausted");
+                                return null;
+                            }
+                            LOG.debug("NAPT Service : Could be ports exhausted case, try with another externalIP if possible");
+                            NEXT_EXTIP_FLAG = true;
+                            continue;
+                        }
+                        int extPort= rpcResult.getResult().getIdValue().intValue();
+                        SessionAddress externalIpPort = new SessionAddress(extIp, extPort);
+                        // Write to ip-port-map before returning
+                        IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
+                        IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build();
+                        IpPortMap ipm = new IpPortMapBuilder().setKey(new IpPortMapKey(internalIpPort))
+                                .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
+                        LOG.debug("NAPT Service : getExternalAddressMapping writing into ip-port-map with externalIP {} and port {}",
+                                ipPortExt.getIpAddress(), ipPortExt.getPortNum());
+                        try {
+                            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+                                           getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
+                        } catch (UncheckedExecutionException uee) {
+                            LOG.error("NAPT Service : Failed to write into ip-port-map with exception {}", uee.getMessage() );
+                        }
+
+                         // Write to snat-internal-ip-port-info
+                         String internalIpAddress = sourceAddress.getIpAddress();
+                         int ipPort = sourceAddress.getPortNumber();
+                         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+                         List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,internalIpAddress,protocolType);
+                         if (portList == null) {
+                             portList = Lists.newArrayList();
+                         }
+                         portList.add(ipPort);
+
+                         IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+                         IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+                         try {
+                             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType), intIpProtocolType);
+                         } catch (Exception ex) {
+                             LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+                         }
+
+                         LOG.debug("NAPT Service : getExternalAddressMapping successfully returning externalIP {} and port {}",
+                                         externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+                        return externalIpPort;
+                    } catch(InterruptedException | ExecutionException  e) {
+                        LOG.error("NAPT Service : getExternalAddressMapping, Exception caught  {}",e);
+                        return null;
+                    }
+                }// end of for loop
+             }// end of else ipmap present
+         }// end of else check ipmap
+         LOG.error("NAPT Service: getExternalAddressMapping returning null, nothing worked or externalIPs exhausted");
+         return null;
+     }
+
+
+     /**
+      * 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
+      * @return true if mapping exist and the mapping is removed successfully
+      */
+
+     public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+
+         LOG.debug("NAPT Service : releaseAddressMapping called with segmentId {}, internalIP {}, port {}", segmentId, address.getIpAddress(), address.getPortNumber());
+         // delete entry from IpPort Map and IP Map if exists
+         String internalIpPort = new StringBuilder(64).append(address.getIpAddress()).append(":").append(address.getPortNumber()).toString();
+         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+         if(existingIpPort != null) {
+             // delete the entry from IpPortMap DS
+             try {
+                 removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+             } catch (Exception e){
+                 LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" , internalIpPort, segmentId, e);
+                 return false;
+             }
+         } else {
+             LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+             return false;
+         }
+         String existingIp = checkIpMap(segmentId, address.getIpAddress());
+         if(existingIp != null) {
+             // delete the entry from IpMap DS
+             try {
+                 removeFromIpMapDS(segmentId, address.getIpAddress());
+             } catch (Exception e){
+                 LOG.error("NAPT Service : Removal of  ipmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+                 return false;
+             }
+             //delete the entry from snatIntIpportinfo
+             try {
+                 removeFromSnatIpPortDS(segmentId, address.getIpAddress());
+             } catch (Exception e){
+                 LOG.error("NAPT Service : releaseAddressMapping failed, Removal of snatipportmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
+                 return false;
+             }
+         } else {
+             LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpMap DS", segmentId, internalIpPort);
+             return false;
+         }
+         // Finally release port from idmanager
+         removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+
+         LOG.debug("NAPT Service : Exit of releaseAddressMapping successfully for segmentId {} and internalIpPort {}", segmentId, internalIpPort);  
+         return true;
+
+     }
+
+    protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
+        String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
+        SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
+        if(existingIpPort != null) {
+            // delete the entry from IpPortMap DS
+            try {
+                removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
+                // Finally release port from idmanager
+                removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
+            } catch (Exception e){
+                LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" ,
+                        internalIpPort, segmentId, e);
+            }
+        } else {
+            LOG.error("NAPT Service : releaseIpExtPortMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
+        }
+
+        //delete the entry of port for InternalIp from snatIntIpportMappingDS
+        try {
+            removeSnatIntIpPortDS(segmentId,address, protocol);
+        } catch (Exception e){
+            LOG.error("NAPT Service : releaseSnatIpPortMapping failed, Removal of snatipportmap {} for router {} failed {}" ,
+                    address.getIpAddress(), segmentId, e);
+        }
+    }
+
+     /**
+      * removes the internal ip to external ip mapping if present
+      * @param segmentId
+      * @return true if successfully removed
+      */
+     public boolean removeMapping(long segmentId) {
+         try {
+             removeIpMappingForRouterID(segmentId);
+         } catch (Exception e){
+             LOG.error("NAPT Service : Removal of  IPMapping for router {} failed {}" , segmentId, e);
+             return false;
+         }
+
+         //TODO :  This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
+        return false;
+     }
+
+     // 2. Utility functions
+     protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
+         InstanceIdentifier<IpMap> id = InstanceIdentifier.builder(
+                 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segid)).child(IpMap.class, new IpMapKey(internal)).build();
+         return id;
+     }
+
+    public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
+        InstanceIdentifier id = getIpMapList(routerId);
+        Optional<IpMapping> ipMappingListData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (ipMappingListData.isPresent()) {
+            IpMapping ipMapping = ipMappingListData.get();
+            return ipMapping.getIpMap();
+        }
+        return null;
+    }
+
+    protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
+        InstanceIdentifier<IpMapping> id = InstanceIdentifier.builder(
+                IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
+        return id;
+    }
+
+     protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal, NAPTEntryEvent.Protocol protocol) {
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         InstanceIdentifier<IpPortMap> id = InstanceIdentifier.builder(
+                 IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segid)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)).
+                 child(IpPortMap.class, new IpPortMapKey(internal)).build();
+         return id;
+     }
+
+     protected SessionAddress checkIpPortMap(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+
+         LOG.debug("NAPT Service : checkIpPortMap called with segmentId {} and internalIpPort {}", segmentId, internalIpPort);
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         // check if ip-port-map node is there
+         InstanceIdentifierBuilder<IntextIpProtocolType> idBuilder =
+                         InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType));
+         InstanceIdentifier<IntextIpProtocolType> id = idBuilder.build();
+         Optional<IntextIpProtocolType> intextIpProtocolType = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
+         if (intextIpProtocolType.isPresent()) {
+               List<IpPortMap> ipPortMaps = intextIpProtocolType.get().getIpPortMap();
+               for (IpPortMap ipPortMap : ipPortMaps) {
+                    if (ipPortMap.getIpPortInternal().equals(internalIpPort)) {
+                       LOG.debug("NAPT Service : IpPortMap : {}", ipPortMap);
+                       SessionAddress externalIpPort = new SessionAddress(ipPortMap.getIpPortExternal().getIpAddress(),
+                                ipPortMap.getIpPortExternal().getPortNum());
+                       LOG.debug("NAPT Service : checkIpPortMap returning successfully externalIP {} and port {}",
+                               externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
+                       return externalIpPort;
+                    }
+               }
+         }
+         // return null if not found
+         LOG.error("NAPT Service : no-entry in checkIpPortMap, returning NULL [should be OK] for segmentId {} and internalIPPort {}", segmentId, internalIpPort);
+         return null;
+     }
+
+     protected String checkIpMap(long segmentId, String internalIp) {
+
+         LOG.debug("NAPT Service : checkIpMap called with segmentId {} and internalIp {}", segmentId, internalIp);
+         String externalIp;
+         // check if ip-map node is there
+         InstanceIdentifierBuilder<IpMapping> idBuilder =
+                         InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
+         InstanceIdentifier<IpMapping> id = idBuilder.build();
+         Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
+         if (ipMapping.isPresent()) {
+               List<IpMap> ipMaps = ipMapping.get().getIpMap();
+               for (IpMap ipMap : ipMaps) {
+                    if (ipMap.getInternalIp().equals(internalIp)) {
+                       LOG.debug("NAPT Service : IpMap : {}", ipMap);
+                       externalIp = ipMap.getExternalIp().toString();
+                       LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+                       return externalIp;
+                    } else if (ipMap.getInternalIp().contains("/")) { // subnet case
+                        SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
+                        SubnetInfo subnetInfo = subnetUtils.getInfo();
+                        if (subnetInfo.isInRange(internalIp)) {
+                            LOG.debug("NAPT Service : internalIp {} found to be IpMap of internalIpSubnet {}", internalIp, ipMap.getInternalIp());
+                            externalIp = ipMap.getExternalIp().toString();
+                            LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
+                            return externalIp;
+                        }
+                    }
+               }
+         }
+         // return null if not found
+         LOG.error("NAPT Service : checkIpMap failed, returning NULL for segmentId {} and internalIp {}", segmentId, internalIp);
+         return null;
+      }
+
+    protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address,NAPTEntryEvent.Protocol protocol) {
+        LOG.trace("NAPT Service : removeSnatIntIpPortDS method called for IntIpport {} of router {} ",address,segmentId);
+        ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+        List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,address.getIpAddress(),protocolType);
+        if (portList == null || portList.isEmpty() || !portList.contains(address.getPortNumber())) {
+           LOG.debug("Internal IP {} for port {} entry not found in SnatIntIpPort DS",address.getIpAddress(),address.getPortNumber());
+           return;
+        }
+        LOG.trace("NAPT Service : PortList {} retrieved for InternalIp {} of router {}",portList,address.getIpAddress(),segmentId);
+        Integer port = address.getPortNumber();
+        portList.remove(port);
+
+        IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
+        IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
+        try {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType), intIpProtocolType);
+        } catch (Exception ex) {
+            LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
+        }
+        LOG.debug("NAPT Service : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore : {}"
+                ,address.getIpAddress(),address.getPortNumber(),segmentId);
+    }
+
+    protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
+        InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
+                (IntipPortMap.class, new IntipPortMapKey(segmentId)).child(IpPort.class, new IpPortKey(internalIp)).build();
+        // remove from SnatIpPortDS
+        LOG.debug("NAPT Service : Removing SnatIpPort from datastore : {}", intIp);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
+
+    }
+
+    protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
+         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
+         InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
+                 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
+                 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
+         InstanceIdentifier<IpPortMap> id = idBuilder.build();
+         // remove from ipportmap DS
+         LOG.debug("NAPT Service : Removing ipportmap from datastore : {}", id);
+         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+    }
+
+     protected void removeFromIpMapDS(long segmentId, String internalIp) {
+         InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+                 .child(IpMapping.class, new IpMappingKey(segmentId))
+                 .child(IpMap.class, new IpMapKey(internalIp));
+         InstanceIdentifier<IpMap> id = idBuilder.build();
+         // remove from ipmap DS
+         LOG.debug("NAPT Service : Removing ipmap from datastore : {}", id);
+         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+     }
+
+    private void removeIpMappingForRouterID(long segmentId) {
+        InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
+                .child(IpMapping.class, new IpMappingKey(segmentId));
+        InstanceIdentifier<IpMapping> id = idBuilder.build();
+        // remove from ipmap DS
+        LOG.debug("NAPT Service : Removing ipmap from datastore : {}", id);
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
+     protected void removePortFromPool(String internalIpPort, String externalIp) {
+         LOG.debug("NAPT Service : removePortFromPool method called");
+         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
+                                        setPoolName(externalIp)
+                                        .setIdKey(internalIpPort).build();
+         try {
+             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
+             RpcResult<Void> rpcResult = result.get();
+             if(!rpcResult.isSuccessful()) {
+                 LOG.error("NAPT Service : idmanager failed to remove port from pool {}", rpcResult.getErrors());
+             }
+             LOG.debug("NAPT Service : Removed port from pool for InternalIpPort {} with externalIp {}",internalIpPort,externalIp);
+         } catch (InterruptedException | ExecutionException e) {
+             LOG.error("NAPT Service : idmanager failed with Exception {} when removing entry in pool with key {}, ", e, internalIpPort);
+         }
+     }
+}
\ No newline at end of file