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