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