Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / NaptManager.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 /*
10  * Created eyugsar 2016/12/1
11  */
12
13 package org.opendaylight.vpnservice.natservice.internal;
14
15
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.ExecutionException;
21
22 import com.google.common.collect.Lists;
23 import org.apache.commons.net.util.SubnetUtils;
24 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.*;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.*;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCounters;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.ExternalCountersKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMapping;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
47 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;
48 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;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
58 import org.opendaylight.yangtools.yang.common.RpcResult;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61 import  org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
62
63 import com.google.common.base.Optional;
64 import com.google.common.util.concurrent.UncheckedExecutionException;
65
66 public class NaptManager  {
67     private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
68     private final DataBroker broker;
69     private IdManagerService idManager;
70     private static final long LOW_PORT = 49152L;
71     private static final long HIGH_PORT = 65535L;
72     private static boolean EXTSUBNET_FLAG = false;
73     private static boolean NEXT_EXTIP_FLAG = false;
74
75     public NaptManager(final DataBroker db) {
76         this.broker = db;
77     }
78
79     public void setIdManager(IdManagerService idManager) {
80         this.idManager = idManager;
81     }
82
83     protected void createNaptPortPool(String PoolName) {
84          LOG.debug("NAPT Service : createPortPool requested for : {}", PoolName);
85          CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
86              .setPoolName(PoolName)
87              .setLow(LOW_PORT)
88              .setHigh(HIGH_PORT)
89              .build();
90          try {
91              Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
92              if ((result != null) && (result.get().isSuccessful())) {
93                  LOG.debug("NAPT Service : Created PortPool");
94              } else {
95                  LOG.error("NAPT Service : Unable to create PortPool");
96              }
97          } catch (InterruptedException | ExecutionException e) {
98              LOG.error("Failed to create PortPool for NAPT Service",e);
99          }
100     }
101
102     void removeNaptPortPool(String poolName) {
103         DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
104         LOG.debug("NAPT Service : Remove Napt port pool requested for : {}", poolName);
105         try {
106             Future<RpcResult<Void>> result = idManager.deleteIdPool(deleteIdPoolInput);
107             if ((result != null) && (result.get().isSuccessful())) {
108                 LOG.debug("NAPT Service : Deleted PortPool {}", poolName);
109             } else {
110                 LOG.error("NAPT Service : Unable to delete PortPool {}", poolName);
111             }
112         } catch (InterruptedException | ExecutionException e) {
113             LOG.error("Failed to delete PortPool {} for NAPT Service", poolName, e);
114         }
115     }
116
117      // 1. napt service functions
118      /**
119       * this method is used to inform this service of what external IP address to be used
120       * as mapping when requested one for the internal IP address given in the input
121       * @param segmentId – segmentation in which the mapping to be used. Eg; routerid
122       * @param internal subnet prefix or ip address
123       * @param external subnet prefix or ip address
124       */
125
126       public void registerMapping(long segmentId, IPAddress internal, IPAddress external) {
127
128           LOG.debug("NAPT Service : registerMapping called with segmentid {}, internalIp {}, prefix {}, externalIp {} and prefix {} ", segmentId, internal.getIpAddress(),
129                 internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength());
130         // Create Pool per ExternalIp and not for all IPs in the subnet. Create new Pools during getExternalAddressMapping if exhausted.
131         String externalIpPool;
132         if (external.getPrefixLength() !=0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) {  // subnet case
133             String externalSubnet = new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
134             LOG.debug("NAPT Service : externalSubnet is : {}", externalSubnet);
135             SubnetUtils subnetUtils = new SubnetUtils(externalSubnet);
136             SubnetInfo subnetInfo = subnetUtils.getInfo();
137             externalIpPool = subnetInfo.getLowAddress();
138         } else {  // ip case
139             externalIpPool = external.getIpAddress();
140         }
141         createNaptPortPool(externalIpPool);
142
143         // Store the ip to ip map in Operational DS
144         String internalIp = internal.getIpAddress();
145         if(internal.getPrefixLength() != 0) {
146             internalIp =  new StringBuilder(64).append(internal.getIpAddress()).append("/").append(internal.getPrefixLength()).toString();
147         }
148         String externalIp = external.getIpAddress();
149         if(external.getPrefixLength() != 0) {
150             externalIp =  new StringBuilder(64).append(external.getIpAddress()).append("/").append(external.getPrefixLength()).toString();
151         }
152         updateCounter(segmentId, externalIp, true);
153         //update the actual ip-map
154         IpMap ipm = new IpMapBuilder().setKey(new IpMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp).build();
155         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getIpMapIdentifier(segmentId, internalIp), ipm);
156         LOG.debug("NAPT Service : registerMapping exit after updating DS with internalIP {}, externalIP {}", internalIp, externalIp);
157      }
158
159       public void updateCounter(long segmentId, String externalIp, boolean isAdd){
160           short counter = 0;
161           InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
162           Optional <ExternalIpCounter> externalIpCounter = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
163           if (externalIpCounter.isPresent()) {
164               counter = externalIpCounter.get().getCounter();
165               if(isAdd){
166                   counter++;
167                   LOG.debug("NAT Service : externalIp and counter after increment are {} and {}", externalIp, counter);
168               }else{
169                   if(counter > 0){
170                     counter--;
171                   }
172                   LOG.debug("NAT Service : externalIp and counter after decrement are {} and {}", externalIp, counter);
173               }
174
175           }else if(isAdd){
176               counter = 1;
177           }
178
179           //update the new counter value for this externalIp
180           ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter(counter).build();
181           MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(segmentId, externalIp), externalIpCounterData);
182
183       }
184
185      /**
186       * method to get external ip/port mapping when provided with internal ip/port pair
187       * If already a mapping exist for the given input, then the existing mapping is returned
188       * instead of overwriting with new ip/port pair.
189       * @param segmentId
190       * @param sourceAddress - internal ip address/port pair
191       * @return external ip address/port
192       */
193      public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) {
194          LOG.debug("NAPT Service : getExternalAddressMapping called with segmentId {}, internalIp {} and port {}",
195                  segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
196         /*
197          1. Get Internal IP, Port in IP:Port format
198          2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
199          3. If True return SessionAddress of ExternalIp and Port
200          4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
201          */
202
203          //SessionAddress externalIpPort = new SessionAddress();
204          String internalIpPort = new StringBuilder(64).append(sourceAddress.getIpAddress()).append(":").append(sourceAddress.getPortNumber()).toString();
205
206          // First check existing Port Map.
207          SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
208          if(existingIpPort != null) {
209              // populate externalIpPort from IpPortMap and return
210              LOG.debug("NAPT Service : getExternalAddressMapping successfully returning existingIpPort as {} and {}", existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
211              return existingIpPort;
212          } else {
213              // Now check in ip-map
214              String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
215              if(externalIp == null) {
216                  LOG.error("NAPT Service : getExternalAddressMapping, Unexpected error, internal to external ip map does not exist");
217                  return null;
218              } else {
219                  /* Logic assuming internalIp is always ip and not subnet
220                   * case 1: externalIp is ip
221                   *        a) goto externalIp pool and getPort and return
222                   *        b) else return error
223                   * case 2: externalIp is subnet
224                   *        a) Take first externalIp and goto that Pool and getPort
225                   *             if port -> return
226                   *             else Take second externalIp and create that Pool and getPort
227                   *             if port ->return
228                   *             else
229                   *             Continue same with third externalIp till we exhaust subnet
230                   *        b) Nothing worked return error
231                   */
232                  SubnetUtils externalIpSubnet;
233                  List<String> allIps = new ArrayList<String>();
234                  String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
235                  if( !externalIp.contains(subnetPrefix) ) {
236                     EXTSUBNET_FLAG = true;
237                     externalIpSubnet = new SubnetUtils(externalIp);
238                     allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
239                     LOG.debug("NAPT Service : total count of externalIps available {}", externalIpSubnet.getInfo().getAddressCount());
240                  } else {
241                      LOG.debug("NAPT Service : getExternalAddress single ip case");
242                      if(externalIp.contains(subnetPrefix)) {
243                          String[] externalIpSplit = externalIp.split("/");
244                          String extIp = externalIpSplit[0];
245                          externalIp = extIp; //remove /32 what we got from checkIpMap
246                      }
247                      allIps.add(externalIp);
248                  }
249
250                  for(String extIp : allIps) {
251                     LOG.info("NAPT Service : Looping externalIPs with externalIP now as {}", extIp);
252                     if(NEXT_EXTIP_FLAG) {
253                         createNaptPortPool(extIp);
254                         LOG.debug("NAPT Service : Created Pool for next Ext IP {}", extIp);
255                     }
256                     AllocateIdInput getIdInput = new AllocateIdInputBuilder()
257                         .setPoolName(extIp).setIdKey(internalIpPort)
258                         .build();
259                      try {
260                         Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
261                         RpcResult<AllocateIdOutput> rpcResult;
262                         if ((result != null) && (result.get().isSuccessful())) {
263                             LOG.debug("NAPT Service : Got id from idManager");
264                             rpcResult = result.get();
265                         } else {
266                             LOG.error("NAPT Service : getExternalAddressMapping, idManager could not allocate id retry if subnet");
267                             if(!EXTSUBNET_FLAG) {
268                                 LOG.error("NAPT Service : getExternalAddressMapping returning null for single IP case, may be ports exhausted");
269                                 return null;
270                             }
271                             LOG.debug("NAPT Service : Could be ports exhausted case, try with another externalIP if possible");
272                             NEXT_EXTIP_FLAG = true;
273                             continue;
274                         }
275                         int extPort= rpcResult.getResult().getIdValue().intValue();
276                         SessionAddress externalIpPort = new SessionAddress(extIp, extPort);
277                         // Write to ip-port-map before returning
278                         IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
279                         IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build();
280                         IpPortMap ipm = new IpPortMapBuilder().setKey(new IpPortMapKey(internalIpPort))
281                                 .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
282                         LOG.debug("NAPT Service : getExternalAddressMapping writing into ip-port-map with externalIP {} and port {}",
283                                 ipPortExt.getIpAddress(), ipPortExt.getPortNum());
284                         try {
285                             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
286                                            getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
287                         } catch (UncheckedExecutionException uee) {
288                             LOG.error("NAPT Service : Failed to write into ip-port-map with exception {}", uee.getMessage() );
289                         }
290
291                          // Write to snat-internal-ip-port-info
292                          String internalIpAddress = sourceAddress.getIpAddress();
293                          int ipPort = sourceAddress.getPortNumber();
294                          ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
295                          List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,internalIpAddress,protocolType);
296                          if (portList == null) {
297                              portList = Lists.newArrayList();
298                          }
299                          portList.add(ipPort);
300
301                          IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
302                          IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
303                          try {
304                              MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
305                                      NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType), intIpProtocolType);
306                          } catch (Exception ex) {
307                              LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
308                          }
309
310                          LOG.debug("NAPT Service : getExternalAddressMapping successfully returning externalIP {} and port {}",
311                                          externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
312                         return externalIpPort;
313                     } catch(InterruptedException | ExecutionException  e) {
314                         LOG.error("NAPT Service : getExternalAddressMapping, Exception caught  {}",e);
315                         return null;
316                     }
317                 }// end of for loop
318              }// end of else ipmap present
319          }// end of else check ipmap
320          LOG.error("NAPT Service: getExternalAddressMapping returning null, nothing worked or externalIPs exhausted");
321          return null;
322      }
323
324
325      /**
326       * release the existing mapping of internal ip/port to external ip/port pair
327       * if no mapping exist for given internal ip/port, it returns false
328       * @param segmentId
329       * @param address
330       * @return true if mapping exist and the mapping is removed successfully
331       */
332
333      public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
334
335          LOG.debug("NAPT Service : releaseAddressMapping called with segmentId {}, internalIP {}, port {}", segmentId, address.getIpAddress(), address.getPortNumber());
336          // delete entry from IpPort Map and IP Map if exists
337          String internalIpPort = new StringBuilder(64).append(address.getIpAddress()).append(":").append(address.getPortNumber()).toString();
338          SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
339          if(existingIpPort != null) {
340              // delete the entry from IpPortMap DS
341              try {
342                  removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
343              } catch (Exception e){
344                  LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" , internalIpPort, segmentId, e);
345                  return false;
346              }
347          } else {
348              LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
349              return false;
350          }
351          String existingIp = checkIpMap(segmentId, address.getIpAddress());
352          if(existingIp != null) {
353              // delete the entry from IpMap DS
354              try {
355                  removeFromIpMapDS(segmentId, address.getIpAddress());
356              } catch (Exception e){
357                  LOG.error("NAPT Service : Removal of  ipmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
358                  return false;
359              }
360              //delete the entry from snatIntIpportinfo
361              try {
362                  removeFromSnatIpPortDS(segmentId, address.getIpAddress());
363              } catch (Exception e){
364                  LOG.error("NAPT Service : releaseAddressMapping failed, Removal of snatipportmap {} for router {} failed {}" , address.getIpAddress(), segmentId, e);
365                  return false;
366              }
367          } else {
368              LOG.error("NAPT Service : releaseAddressMapping failed, segmentId {} and internalIpPort {} not found in IpMap DS", segmentId, internalIpPort);
369              return false;
370          }
371          // Finally release port from idmanager
372          removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
373
374          LOG.debug("NAPT Service : Exit of releaseAddressMapping successfully for segmentId {} and internalIpPort {}", segmentId, internalIpPort);  
375          return true;
376
377      }
378
379     protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
380         String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
381         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
382         if(existingIpPort != null) {
383             // delete the entry from IpPortMap DS
384             try {
385                 removeFromIpPortMapDS(segmentId, internalIpPort , protocol);
386                 // Finally release port from idmanager
387                 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
388             } catch (Exception e){
389                 LOG.error("NAPT Service : releaseAddressMapping failed, Removal of ipportmap {} for router {} failed {}" ,
390                         internalIpPort, segmentId, e);
391             }
392         } else {
393             LOG.error("NAPT Service : releaseIpExtPortMapping failed, segmentId {} and internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
394         }
395
396         //delete the entry of port for InternalIp from snatIntIpportMappingDS
397         try {
398             removeSnatIntIpPortDS(segmentId,address, protocol);
399         } catch (Exception e){
400             LOG.error("NAPT Service : releaseSnatIpPortMapping failed, Removal of snatipportmap {} for router {} failed {}" ,
401                     address.getIpAddress(), segmentId, e);
402         }
403     }
404
405      /**
406       * removes the internal ip to external ip mapping if present
407       * @param segmentId
408       * @return true if successfully removed
409       */
410      public boolean removeMapping(long segmentId) {
411          try {
412              removeIpMappingForRouterID(segmentId);
413              removeIpPortMappingForRouterID(segmentId);
414              removeIntIpPortMappingForRouterID(segmentId);
415          } catch (Exception e){
416              LOG.error("NAPT Service : Removal of  IPMapping for router {} failed {}" , segmentId, e);
417              return false;
418          }
419
420          //TODO :  This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
421         return false;
422      }
423
424      // 2. Utility functions
425      protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
426          InstanceIdentifier<IpMap> id = InstanceIdentifier.builder(
427                  IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segid)).child(IpMap.class, new IpMapKey(internal)).build();
428          return id;
429      }
430
431      protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
432          InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(segmentId))
433                  .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
434          return id;
435      }
436
437     public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
438         InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
439         Optional<IpMapping> ipMappingListData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
440         if (ipMappingListData.isPresent()) {
441             IpMapping ipMapping = ipMappingListData.get();
442             return ipMapping.getIpMap();
443         }
444         return null;
445     }
446
447     protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
448         InstanceIdentifier<IpMapping> id = InstanceIdentifier.builder(
449                 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
450         return id;
451     }
452
453      protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal, NAPTEntryEvent.Protocol protocol) {
454          ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
455          InstanceIdentifier<IpPortMap> id = InstanceIdentifier.builder(
456                  IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segid)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)).
457                  child(IpPortMap.class, new IpPortMapKey(internal)).build();
458          return id;
459      }
460
461      protected SessionAddress checkIpPortMap(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
462
463          LOG.debug("NAPT Service : checkIpPortMap called with segmentId {} and internalIpPort {}", segmentId, internalIpPort);
464          ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
465          // check if ip-port-map node is there
466          InstanceIdentifierBuilder<IntextIpProtocolType> idBuilder =
467                          InstanceIdentifier.builder(IntextIpPortMap.class).child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType));
468          InstanceIdentifier<IntextIpProtocolType> id = idBuilder.build();
469          Optional<IntextIpProtocolType> intextIpProtocolType = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
470          if (intextIpProtocolType.isPresent()) {
471                List<IpPortMap> ipPortMaps = intextIpProtocolType.get().getIpPortMap();
472                for (IpPortMap ipPortMap : ipPortMaps) {
473                     if (ipPortMap.getIpPortInternal().equals(internalIpPort)) {
474                        LOG.debug("NAPT Service : IpPortMap : {}", ipPortMap);
475                        SessionAddress externalIpPort = new SessionAddress(ipPortMap.getIpPortExternal().getIpAddress(),
476                                 ipPortMap.getIpPortExternal().getPortNum());
477                        LOG.debug("NAPT Service : checkIpPortMap returning successfully externalIP {} and port {}",
478                                externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
479                        return externalIpPort;
480                     }
481                }
482          }
483          // return null if not found
484          LOG.error("NAPT Service : no-entry in checkIpPortMap, returning NULL [should be OK] for segmentId {} and internalIPPort {}", segmentId, internalIpPort);
485          return null;
486      }
487
488      protected String checkIpMap(long segmentId, String internalIp) {
489
490          LOG.debug("NAPT Service : checkIpMap called with segmentId {} and internalIp {}", segmentId, internalIp);
491          String externalIp;
492          // check if ip-map node is there
493          InstanceIdentifierBuilder<IpMapping> idBuilder =
494                          InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
495          InstanceIdentifier<IpMapping> id = idBuilder.build();
496          Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
497          if (ipMapping.isPresent()) {
498                List<IpMap> ipMaps = ipMapping.get().getIpMap();
499                for (IpMap ipMap : ipMaps) {
500                     if (ipMap.getInternalIp().equals(internalIp)) {
501                        LOG.debug("NAPT Service : IpMap : {}", ipMap);
502                        externalIp = ipMap.getExternalIp().toString();
503                        LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
504                        return externalIp;
505                     } else if (ipMap.getInternalIp().contains("/")) { // subnet case
506                         SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
507                         SubnetInfo subnetInfo = subnetUtils.getInfo();
508                         if (subnetInfo.isInRange(internalIp)) {
509                             LOG.debug("NAPT Service : internalIp {} found to be IpMap of internalIpSubnet {}", internalIp, ipMap.getInternalIp());
510                             externalIp = ipMap.getExternalIp().toString();
511                             LOG.debug("NAPT Service : checkIpMap successfully returning externalIp {}", externalIp );
512                             return externalIp;
513                         }
514                     }
515                }
516          }
517          // return null if not found
518          LOG.error("NAPT Service : checkIpMap failed, returning NULL for segmentId {} and internalIp {}", segmentId, internalIp);
519          return null;
520       }
521
522     protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address,NAPTEntryEvent.Protocol protocol) {
523         LOG.trace("NAPT Service : removeSnatIntIpPortDS method called for IntIpport {} of router {} ",address,segmentId);
524         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
525         List<Integer> portList = NatUtil.getInternalIpPortListInfo(broker,segmentId,address.getIpAddress(),protocolType);
526         if (portList == null || portList.isEmpty() || !portList.contains(address.getPortNumber())) {
527            LOG.debug("Internal IP {} for port {} entry not found in SnatIntIpPort DS",address.getIpAddress(),address.getPortNumber());
528            return;
529         }
530         LOG.trace("NAPT Service : PortList {} retrieved for InternalIp {} of router {}",portList,address.getIpAddress(),segmentId);
531         Integer port = address.getPortNumber();
532         portList.remove(port);
533
534         IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
535         IntIpProtoType intIpProtocolType = builder.setKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
536         try {
537             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType), intIpProtocolType);
538         } catch (Exception ex) {
539             LOG.error("NAPT Service : Failed to write into snat-internal-ip-port-info with exception {}", ex.getMessage() );
540         }
541         LOG.debug("NAPT Service : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore : {}"
542                 ,address.getIpAddress(),address.getPortNumber(),segmentId);
543     }
544
545     protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
546         InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
547                 (IntipPortMap.class, new IntipPortMapKey(segmentId)).child(IpPort.class, new IpPortKey(internalIp)).build();
548         // remove from SnatIpPortDS
549         LOG.debug("NAPT Service : Removing SnatIpPort from datastore : {}", intIp);
550         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
551
552     }
553
554     protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
555          ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
556          removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
557     }
558
559     protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
560         InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
561                 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
562                 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
563         InstanceIdentifier<IpPortMap> id = idBuilder.build();
564         // remove from ipportmap DS
565         LOG.debug("NAPT Service : Removing ipportmap from datastore : {}", id);
566         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
567     }
568
569      protected void removeFromIpMapDS(long segmentId, String internalIp) {
570          InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
571                  .child(IpMapping.class, new IpMappingKey(segmentId))
572                  .child(IpMap.class, new IpMapKey(internalIp));
573          InstanceIdentifier<IpMap> id = idBuilder.build();
574          // Get externalIp and decrement the counter
575          String externalIp = null;
576          Optional<IpMap> ipMap = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
577          if (ipMap.isPresent()) {
578              externalIp = ipMap.get().getExternalIp();
579              LOG.debug("NAT Service : externalIP is {}", externalIp);
580          }else{
581              LOG.warn("NAT Service : ipMap not present for the internal IP {}", internalIp);
582          }
583
584          if(externalIp!=null) {
585              updateCounter(segmentId, externalIp, false);
586              // remove from ipmap DS
587              LOG.debug("NAPT Service : Removing ipmap from datastore");
588              MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
589          }else{
590              LOG.warn("NAT Service : externalIp not present for the internal IP {}", internalIp);
591          }
592      }
593
594     private void removeIpMappingForRouterID(long segmentId) {
595         InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
596                 .child(IpMapping.class, new IpMappingKey(segmentId));
597         InstanceIdentifier<IpMapping> id = idBuilder.build();
598         // Get all externalIps and decrement their counters before deleting the ipmap
599         String externalIp = null;
600         Optional<IpMapping> ipMapping = MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
601         if (ipMapping.isPresent()) {
602               List<IpMap> ipMaps = ipMapping.get().getIpMap();
603               for (IpMap ipMap : ipMaps) {
604                   externalIp = ipMap.getExternalIp();
605                   LOG.debug("NAT Service : externalIP is {}", externalIp);
606                   if(externalIp!=null) {
607                       updateCounter(segmentId, externalIp, false);
608                   }
609               }
610         }
611         // remove from ipmap DS
612         LOG.debug("NAPT Service : Removing Ipmap for router {} from datastore",segmentId);
613         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
614     }
615
616     void removeIpPortMappingForRouterID(long segmentId) {
617         InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
618                 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
619         // remove from IntExtIpPortmap DS
620         LOG.debug("NAPT Service : Removing IntExtIpPort map for router {} from datastore",segmentId);
621         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idBuilder);
622     }
623
624     void removeIntIpPortMappingForRouterID(long segmentId) {
625         InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class).child
626                 (IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
627         // remove from SnatIntIpPortmap DS
628         LOG.debug("NAPT Service : Removing SnatIntIpPort from datastore : {}", intIp);
629         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, intIp);
630     }
631
632      void removePortFromPool(String internalIpPort, String externalIp) {
633          LOG.debug("NAPT Service : removePortFromPool method called");
634          ReleaseIdInput idInput = new ReleaseIdInputBuilder().
635                                         setPoolName(externalIp)
636                                         .setIdKey(internalIpPort).build();
637          try {
638              Future<RpcResult<Void>> result = idManager.releaseId(idInput);
639              RpcResult<Void> rpcResult = result.get();
640              if(!rpcResult.isSuccessful()) {
641                  LOG.error("NAPT Service : idmanager failed to remove port from pool {}", rpcResult.getErrors());
642              }
643              LOG.debug("NAPT Service : Removed port from pool for InternalIpPort {} with externalIp {}",internalIpPort,externalIp);
644          } catch (InterruptedException | ExecutionException e) {
645              LOG.error("NAPT Service : idmanager failed with Exception {} when removing entry in pool with key {}, ", e, internalIpPort);
646          }
647      }
648
649     protected void initialiseExternalCounter(Routers routers, long routerId){
650         LOG.debug("NAPT Service : Initialise External IPs counter");
651         List<String> externalIps = routers.getExternalIps();
652
653         //update the new counter value for this externalIp
654         for(String externalIp : externalIps) {
655             String[] IpSplit = externalIp.split("/");
656             String extIp = IpSplit[0];
657             String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
658             if(IpSplit.length==2) {
659                 extPrefix = IpSplit[1];
660             }
661             extIp = extIp + "/" + extPrefix;
662             initialiseNewExternalIpCounter(routerId, extIp);
663         }
664     }
665
666     protected void initialiseNewExternalIpCounter(long routerId, String ExternalIp){
667         ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder().setKey(new ExternalIpCounterKey(ExternalIp)).
668                 setExternalIp(ExternalIp).setCounter((short) 0).build();
669         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(routerId, ExternalIp), externalIpCounterData);
670     }
671
672     protected void removeExternalCounter(long routerId){
673         // Remove from external-counters model
674         InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
675         LOG.debug("NAPT Service : Removing ExternalCounterd from datastore");
676         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
677     }
678
679     protected void removeExternalIpCounter(long routerId, String externalIp){
680         // Remove from external-counters model
681         InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).child(ExternalCounters.class,
682                 new ExternalCountersKey(routerId)).child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
683         LOG.debug("NAPT Service : Removing ExternalIpsCounter from datastore");
684         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
685     }
686
687 }