07605ca385c28f7c16e0332d85220ba17deadf61
[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.CreateIdPoolInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.SnatintIpPortMap;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCountersKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
67 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;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
77 import org.opendaylight.yangtools.yang.common.RpcResult;
78 import org.opendaylight.yangtools.yang.common.Uint16;
79 import org.opendaylight.yangtools.yang.common.Uint32;
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(Uint32 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(Uint32 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().toJava();
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     @Nullable
225     public SessionAddress getExternalAddressMapping(Uint32 segmentId, SessionAddress sourceAddress,
226                                                     NAPTEntryEvent.Protocol protocol) {
227         LOG.debug("getExternalAddressMapping : called with segmentId {}, internalIp {} and port {}",
228             segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
229         /*
230          1. Get Internal IP, Port in IP:Port format
231          2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
232          3. If True return SessionAddress of ExternalIp and Port
233          4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
234          */
235
236         //SessionAddress externalIpPort = new SessionAddress();
237         String internalIpPort = sourceAddress.getIpAddress() + ":" + sourceAddress.getPortNumber();
238
239         // First check existing Port Map.
240         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
241         if (existingIpPort != null) {
242             // populate externalIpPort from IpPortMap and return
243             LOG.debug("getExternalAddressMapping : successfully returning existingIpPort as {} and {}",
244                 existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
245             return existingIpPort;
246         }
247
248         // Now check in ip-map
249         String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
250         if (externalIp == null) {
251             LOG.error("getExternalAddressMapping : Unexpected error, internal to external "
252                     + "ip map does not exist");
253             return null;
254         }
255
256         /* Logic assuming internalIp is always ip and not subnet
257          * case 1: externalIp is ip
258          *        a) goto externalIp pool and getPort and return
259          *        b) else return error
260          * case 2: externalIp is subnet
261          *        a) Take first externalIp and goto that Pool and getPort
262          *             if port -> return
263          *             else Take second externalIp and create that Pool and getPort
264          *             if port ->return
265          *             else
266          *             Continue same with third externalIp till we exhaust subnet
267          *        b) Nothing worked return error
268          */
269         SubnetUtils externalIpSubnet;
270         List<String> allIps = new ArrayList<>();
271         String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
272         boolean extSubnetFlag = false;
273         if (!externalIp.contains(subnetPrefix)) {
274             extSubnetFlag = true;
275             externalIpSubnet = new SubnetUtils(externalIp);
276             allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
277             LOG.debug("getExternalAddressMapping : total count of externalIps available {}",
278                 externalIpSubnet.getInfo().getAddressCount());
279         } else {
280             LOG.debug("getExternalAddressMapping : getExternalAddress single ip case");
281             if (externalIp.contains(subnetPrefix)) {
282                 //remove /32 what we got from checkIpMap
283                 externalIp = externalIp.substring(0, externalIp.indexOf(subnetPrefix));
284             }
285             allIps.add(externalIp);
286         }
287
288         boolean nextExtIpFlag = false;
289         for (String extIp : allIps) {
290             LOG.info("getExternalAddressMapping : Looping externalIPs with externalIP now as {}", extIp);
291             if (nextExtIpFlag) {
292                 createNaptPortPool(extIp);
293                 LOG.debug("getExternalAddressMapping : Created Pool for next Ext IP {}", extIp);
294             }
295             Uint32 extPort = NatUtil.getUniqueId(idManager, extIp, internalIpPort);
296             if (extPort == NatConstants.INVALID_ID) {
297                 LOG.error("getExternalAddressMapping : getExternalAddressMapping, idManager could not "
298                     + "allocate id retry if subnet");
299                 if (!extSubnetFlag) {
300                     LOG.error("getExternalAddressMapping : getExternalAddressMapping returning null "
301                         + "for single IP case, may be ports exhausted");
302                     return null;
303                 }
304                 LOG.debug("getExternalAddressMapping : Could be ports exhausted case, "
305                     + "try with another externalIP if possible");
306                 nextExtIpFlag = true;
307                 continue;
308             }
309             // Write to ip-port-map before returning
310             IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
311             IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort.intValue()).build();
312             IpPortMap ipm = new IpPortMapBuilder().withKey(new IpPortMapKey(internalIpPort))
313                     .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
314             LOG.debug("getExternalAddressMapping : writing into ip-port-map with "
315                     + "externalIP {} and port {}",
316                     ipPortExt.getIpAddress(), ipPortExt.getPortNum());
317             try {
318                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
319                     getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
320             } catch (UncheckedExecutionException uee) {
321                 LOG.error("getExternalAddressMapping : Failed to write into ip-port-map with exception",
322                     uee);
323             }
324
325             // Write to snat-internal-ip-port-info
326             String internalIpAddress = sourceAddress.getIpAddress();
327             int ipPort = sourceAddress.getPortNumber();
328             ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
329             final ReentrantLock lock = lockFor(segmentId, internalIpAddress, protocolType);
330             lock.lock();
331             try {
332                 List<Uint16> portList = new ArrayList<>(
333                         NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, internalIpAddress,
334                             protocolType));
335                 portList.add(Uint16.valueOf(ipPort));
336
337                 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
338                 IntIpProtoType intIpProtocolType =
339                         builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
340                 try {
341                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
342                         NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType),
343                         intIpProtocolType);
344                 } catch (Exception ex) {
345                     LOG.error("getExternalAddressMapping : Failed to write into snat-internal-ip-port-info "
346                             + "with exception", ex);
347                 }
348             } finally {
349                 lock.unlock();
350             }
351             SessionAddress externalIpPort = new SessionAddress(extIp, extPort.intValue());
352             LOG.debug("getExternalAddressMapping : successfully returning externalIP {} "
353                     + "and port {}", externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
354             return externalIpPort;
355         } // end of for loop
356         LOG.error("getExternalAddressMapping : Unable to handle external IP address and port mapping with segmentId {},"
357                 + "internalIp {} and internalPort {}", segmentId, sourceAddress.getIpAddress(),
358                 sourceAddress.getPortNumber());
359         return null;
360     }
361
362     // TODO Clean up the exception handling
363     @SuppressWarnings("checkstyle:IllegalCatch")
364     protected void releaseIpExtPortMapping(Uint32 segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
365         String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
366         SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
367         if (existingIpPort != null) {
368             // delete the entry from IpPortMap DS
369             try {
370                 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
371                 // Finally release port from idmanager
372                 Uint32 releasedId = NatUtil.releaseId(idManager, existingIpPort.getIpAddress(), internalIpPort);
373                 if (releasedId == NatConstants.INVALID_ID) {
374                     LOG.error("releaseIpExtPortMapping : Unable to release ID for key {}",
375                         existingIpPort.getIpAddress());
376                 }
377             } catch (Exception e) {
378                 LOG.error("releaseIpExtPortMapping : failed, Removal of ipportmap {} for "
379                     + "router {} failed", internalIpPort, segmentId, e);
380             }
381         } else {
382             LOG.error("releaseIpExtPortMapping : failed, segmentId {} and "
383                 + "internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
384         }
385
386         //delete the entry of port for InternalIp from snatIntIpportMappingDS
387         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
388         final ReentrantLock lock = lockFor(segmentId, address.getIpAddress(), protocolType);
389         lock.lock();
390         try {
391             removeSnatIntIpPortDS(segmentId, address, protocolType);
392         } catch (Exception e) {
393             LOG.error("releaseSnatIpPortMapping : failed, Removal of snatipportmap {} for router {} failed",
394                 address.getIpAddress(), segmentId, e);
395         } finally {
396             lock.unlock();
397         }
398     }
399
400     /**
401      * Removes the internal ip to external ip mapping if present.
402      *
403      * @param segmentId - Router ID
404      * @return true if successfully removed
405      */
406     // TODO Clean up the exception handling
407     @SuppressWarnings("checkstyle:IllegalCatch")
408     public boolean removeMapping(Uint32 segmentId) {
409         try {
410             removeIpMappingForRouterID(segmentId);
411             removeIpPortMappingForRouterID(segmentId);
412             removeIntIpPortMappingForRouterID(segmentId);
413         } catch (Exception e) {
414             LOG.error("removeMapping : Removal of  IPMapping for router {} failed", segmentId, e);
415             return false;
416         }
417
418         //TODO :  This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
419         return false;
420     }
421
422     protected InstanceIdentifier<IpMap> getIpMapIdentifier(Uint32 segid, String internal) {
423         return InstanceIdentifier.builder(IntextIpMap.class)
424             .child(IpMapping.class, new IpMappingKey(segid))
425             .child(IpMap.class, new IpMapKey(internal)).build();
426     }
427
428     protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(Uint32 segmentId, String external) {
429         return InstanceIdentifier.builder(ExternalIpsCounter.class)
430             .child(ExternalCounters.class, new ExternalCountersKey(segmentId))
431             .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
432     }
433
434     @NonNull
435     public static List<IpMap> getIpMapList(DataBroker broker, Uint32 routerId) {
436         InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
437         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
438                 LogicalDatastoreType.OPERATIONAL, id).toJavaUtil().map(IpMapping::getIpMap).orElse(
439                 Collections.emptyList());
440     }
441
442     protected static InstanceIdentifier<IpMapping> getIpMapList(Uint32 routerId) {
443         return InstanceIdentifier.builder(
444             IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
445     }
446
447     protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(Uint32 segid, String internal,
448                                                                    NAPTEntryEvent.Protocol protocol) {
449         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
450         return InstanceIdentifier.builder(IntextIpPortMap.class)
451             .child(IpPortMapping.class, new IpPortMappingKey(segid))
452             .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
453             .child(IpPortMap.class, new IpPortMapKey(internal)).build();
454     }
455
456     @Nullable
457     private SessionAddress checkIpPortMap(Uint32 segmentId, String internalIpPort,
458             NAPTEntryEvent.Protocol protocol) {
459         LOG.debug("checkIpPortMap : called with segmentId {} and internalIpPort {}",
460                 segmentId, internalIpPort);
461         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
462         // check if ip-port-map node is there
463         InstanceIdentifierBuilder<IpPortMap> idBuilder =
464                 InstanceIdentifier.builder(IntextIpPortMap.class)
465                 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
466                 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
467                 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
468         InstanceIdentifier<IpPortMap> id = idBuilder.build();
469         Optional<IpPortMap> ipPortMapType =
470                 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
471         if (ipPortMapType.isPresent()) {
472             LOG.debug("checkIpPortMap : {}", ipPortMapType.get());
473             SessionAddress externalIpPort = new SessionAddress(ipPortMapType.get().getIpPortExternal().getIpAddress(),
474                     ipPortMapType.get().getIpPortExternal().getPortNum().toJava());
475             LOG.debug("checkIpPortMap : returning successfully externalIP {} and port {}",
476                     externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
477             return externalIpPort;
478         }
479         // return null if not found
480         LOG.warn("checkIpPortMap : no-entry in checkIpPortMap, returning NULL [should be OK] for "
481                 + "segmentId {} and internalIPPort {}", segmentId, internalIpPort);
482         return null;
483     }
484
485     @Nullable
486     protected String checkIpMap(Uint32 segmentId, String internalIp) {
487         LOG.debug("checkIpMap : called with segmentId {} and internalIp {}", segmentId, internalIp);
488         String externalIp;
489         // check if ip-map node is there
490         InstanceIdentifierBuilder<IpMapping> idBuilder =
491             InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
492         InstanceIdentifier<IpMapping> id = idBuilder.build();
493         Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
494         if (ipMapping.isPresent()) {
495             for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
496                 if (Objects.equals(ipMap.getInternalIp(), internalIp)) {
497                     LOG.debug("checkIpMap : IpMap : {}", ipMap);
498                     externalIp = ipMap.getExternalIp();
499                     LOG.debug("checkIpMap : successfully returning externalIp {}", externalIp);
500                     return externalIp;
501                 } else if (ipMap.getInternalIp().contains("/")) { // subnet case
502                     SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
503                     SubnetInfo subnetInfo = subnetUtils.getInfo();
504                     if (subnetInfo.isInRange(internalIp)) {
505                         LOG.debug("checkIpMap : internalIp {} found to be IpMap of internalIpSubnet {}",
506                             internalIp, ipMap.getInternalIp());
507                         externalIp = ipMap.getExternalIp();
508                         LOG.debug("checkIpMap : checkIpMap successfully returning externalIp {}", externalIp);
509                         return externalIp;
510                     }
511                 }
512             }
513         }
514         // return null if not found
515         LOG.error("checkIpMap : failed, returning NULL for segmentId {} and internalIp {}",
516             segmentId, internalIp);
517         return null;
518     }
519
520     // TODO Clean up the exception handling
521     @SuppressWarnings("checkstyle:IllegalCatch")
522     protected void removeSnatIntIpPortDS(Uint32 segmentId, SessionAddress address, ProtocolTypes protocolType) {
523         LOG.trace("removeSnatIntIpPortDS : method called for IntIpport {} of router {} ",
524             address, segmentId);
525         List<Uint16> portList =
526             NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, address.getIpAddress(), protocolType);
527         if (portList.isEmpty() || !portList.contains(Uint16.valueOf(address.getPortNumber()))) {
528             LOG.error("removeSnatIntIpPortDS : Internal IP {} for port {} entry not found in SnatIntIpPort DS",
529                 address.getIpAddress(), address.getPortNumber());
530             return;
531         }
532         LOG.trace("removeSnatIntIpPortDS : PortList {} retrieved for InternalIp {} of router {}",
533             portList, address.getIpAddress(), segmentId);
534         Integer port = address.getPortNumber();
535         portList.remove(Uint16.valueOf(port));
536
537         IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
538         IntIpProtoType intIpProtocolType =
539             builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
540         try {
541             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
542                 NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType),
543                 intIpProtocolType);
544         } catch (Exception ex) {
545             LOG.error("removeSnatIntIpPortDS : Failed to write into snat-internal-ip-port-info with exception", ex);
546         }
547         LOG.debug("removeSnatIntIpPortDS : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore",
548             address.getIpAddress(), address.getPortNumber(), segmentId);
549     }
550
551     protected void removeFromSnatIpPortDS(Uint32 segmentId, String internalIp) {
552         InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
553             .child(IntipPortMap.class, new IntipPortMapKey(segmentId))
554             .child(IpPort.class, new IpPortKey(internalIp)).build();
555         // remove from SnatIpPortDS
556         LOG.debug("removeFromSnatIpPortDS : Removing SnatIpPort from datastore : {}", intIp);
557         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
558     }
559
560     protected void removeFromIpPortMapDS(Uint32 segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
561         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
562         removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
563     }
564
565     protected void removeFromIpPortMapDS(Uint32 segmentId, String internalIpPort, ProtocolTypes protocolType) {
566         InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
567             .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
568             .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
569             .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
570         InstanceIdentifier<IpPortMap> id = idBuilder.build();
571         // remove from ipportmap DS
572         LOG.debug("removeFromIpPortMapDS : Removing ipportmap from datastore : {}", id);
573         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
574     }
575
576     protected void removeFromIpMapDS(Uint32 segmentId, String internalIp) {
577         InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
578             .child(IpMapping.class, new IpMappingKey(segmentId))
579             .child(IpMap.class, new IpMapKey(internalIp));
580         InstanceIdentifier<IpMap> id = idBuilder.build();
581         // Get externalIp and decrement the counter
582         String externalIp = null;
583         Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
584         if (ipMap.isPresent()) {
585             externalIp = ipMap.get().getExternalIp();
586             LOG.debug("removeFromIpMapDS : externalIP is {}", externalIp);
587         } else {
588             LOG.warn("removeFromIpMapDS : ipMap not present for the internal IP {}", internalIp);
589         }
590
591         if (externalIp != null) {
592             updateCounter(segmentId, externalIp, false);
593             // remove from ipmap DS
594             LOG.debug("removeFromIpMapDS : Removing ipmap from datastore");
595             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
596         } else {
597             LOG.warn("removeFromIpMapDS : externalIp not present for the internal IP {}", internalIp);
598         }
599     }
600
601     protected void removeIntExtIpMapDS(Uint32 segmentId, String internalIp) {
602         InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
603             .child(IpMapping.class, new IpMappingKey(segmentId))
604             .child(IpMap.class, new IpMapKey(internalIp));
605         InstanceIdentifier<IpMap> id = idBuilder.build();
606
607         LOG.debug("removeIntExtIpMapDS : Removing ipmap from datastore");
608         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
609     }
610
611     @Nullable
612     protected String getExternalIpAllocatedForSubnet(Uint32 segmentId, String internalIp) {
613         InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
614             .child(IpMapping.class, new IpMappingKey(segmentId))
615             .child(IpMap.class, new IpMapKey(internalIp));
616         InstanceIdentifier<IpMap> id = idBuilder.build();
617
618         Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
619         if (ipMap.isPresent()) {
620             return ipMap.get().getExternalIp();
621         }
622         return null;
623     }
624
625     private void removeIpMappingForRouterID(Uint32 segmentId) {
626         InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
627             .child(IpMapping.class, new IpMappingKey(segmentId));
628         InstanceIdentifier<IpMapping> id = idBuilder.build();
629         // Get all externalIps and decrement their counters before deleting the ipmap
630         Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
631         if (ipMapping.isPresent()) {
632             for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
633                 String externalIp = ipMap.getExternalIp();
634                 LOG.debug("removeIpMappingForRouterID : externalIP is {}", externalIp);
635                 if (externalIp != null) {
636                     updateCounter(segmentId, externalIp, false);
637                 }
638             }
639             // remove from ipmap DS
640             LOG.debug("removeIpMappingForRouterID : Removing Ipmap for router {} from datastore", segmentId);
641             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
642         }
643     }
644
645     void removeIpPortMappingForRouterID(Uint32 segmentId) {
646         InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
647             .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
648         Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
649                 idBuilder);
650         if (ipPortMapping.isPresent()) {
651             // remove from IntExtIpPortmap DS
652             LOG.debug("removeIpPortMappingForRouterID : Removing IntExtIpPort map for router {} from datastore",
653                     segmentId);
654             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder);
655         }
656     }
657
658     void removeIntIpPortMappingForRouterID(Uint32 segmentId) {
659         InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
660             .child(IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
661         Optional<IntipPortMap> intIpPortMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
662         if (intIpPortMap.isPresent()) {
663             // remove from SnatIntIpPortmap DS
664             LOG.debug("removeIntIpPortMappingForRouterID : Removing SnatIntIpPort from datastore : {}", intIp);
665             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
666         }
667     }
668
669     void removePortFromPool(String internalIpPort, String externalIp) {
670         if (NatUtil.releaseId(idManager, externalIp, internalIpPort) == NatConstants.INVALID_ID) {
671             LOG.error("Unable to release id {} from Pool {}", internalIpPort, externalIp);
672         }
673     }
674
675     protected void initialiseExternalCounter(Routers routers, Uint32 routerId) {
676         LOG.debug("initialiseExternalCounter : Initialise External IPs counter");
677
678         //update the new counter value for this externalIp
679         for (ExternalIps externalIp : routers.nonnullExternalIps()) {
680             String[] ipSplit = externalIp.getIpAddress().split("/");
681             String extIp = ipSplit[0];
682             String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
683             if (ipSplit.length == 2) {
684                 extPrefix = ipSplit[1];
685             }
686             extIp = extIp + "/" + extPrefix;
687             initialiseNewExternalIpCounter(routerId, extIp);
688         }
689     }
690
691     protected void initialiseNewExternalIpCounter(Uint32 routerId, String externalIp) {
692         ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder()
693             .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter((short) 0).build();
694         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
695             getExternalIpsIdentifier(routerId, externalIp), externalIpCounterData);
696     }
697
698     protected void removeExternalCounter(Uint32 routerId) {
699         // Remove from external-counters model
700         InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
701             .child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
702         LOG.debug("removeExternalCounter : Removing ExternalCounterd from datastore");
703         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
704     }
705
706     protected void removeExternalIpCounter(Uint32 routerId, String externalIp) {
707         // Remove from external-counters model
708         InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
709             .child(ExternalCounters.class, new ExternalCountersKey(routerId))
710             .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
711         LOG.debug("removeExternalIpCounter : Removing ExternalIpsCounter from datastore");
712         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
713     }
714
715     private static ReentrantLock lockFor(final Uint32 segmentId, String ipAddress, final ProtocolTypes protocolType) {
716         // FIXME: use an Identifier class instead?
717         String lockName = new StringBuilder()
718             .append(segmentId)
719             .append(NatConstants.COLON_SEPARATOR)
720             .append(ipAddress)
721             .append(NatConstants.COLON_SEPARATOR)
722             .append(protocolType.getName()).toString();
723
724         return JvmGlobalLocks.getLockForString(lockName);
725     }
726 }