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