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