2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
10 * Created eyugsar 2016/12/1
12 package org.opendaylight.netvirt.natservice.internal;
14 import static org.opendaylight.netvirt.natservice.internal.NatUtil.requireNonNullElse;
16 import com.google.common.base.Optional;
17 import com.google.common.util.concurrent.UncheckedExecutionException;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Objects;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Future;
25 import java.util.concurrent.locks.ReentrantLock;
26 import javax.annotation.Nonnull;
27 import javax.annotation.Nullable;
28 import javax.inject.Inject;
29 import javax.inject.Singleton;
30 import org.apache.commons.net.util.SubnetUtils;
31 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.utils.JvmGlobalLocks;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.SnatintIpPortMap;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCountersKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
74 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;
75 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;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
83 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
85 import org.opendaylight.yangtools.yang.common.RpcResult;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
90 public class NaptManager {
91 private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
93 private static final long LOW_PORT = 49152L;
94 private static final long HIGH_PORT = 65535L;
96 private final DataBroker dataBroker;
97 private final IdManagerService idManager;
100 public NaptManager(final DataBroker dataBroker, final IdManagerService idManager) {
101 this.dataBroker = dataBroker;
102 this.idManager = idManager;
105 protected void createNaptPortPool(String poolName) {
106 LOG.debug("createNaptPortPool : requested for : {}", poolName);
107 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
108 .setPoolName(poolName)
113 Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
114 if (result != null && result.get().isSuccessful()) {
115 LOG.debug("createNaptPortPool : Created PortPool :{}", poolName);
117 LOG.error("createNaptPortPool : Unable to create PortPool : {}", poolName);
119 } catch (InterruptedException | ExecutionException e) {
120 LOG.error("createNaptPortPool : Failed to create PortPool for NAPT Service", e);
124 void removeNaptPortPool(String poolName) {
125 DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
126 LOG.debug("removeNaptPortPool : Remove Napt port pool requested for : {}", poolName);
128 Future<RpcResult<DeleteIdPoolOutput>> result = idManager.deleteIdPool(deleteIdPoolInput);
129 if (result != null && result.get().isSuccessful()) {
130 LOG.debug("removeNaptPortPool : Deleted PortPool {}", poolName);
132 LOG.error("removeNaptPortPool : Unable to delete PortPool {}", poolName);
134 } catch (InterruptedException | ExecutionException e) {
135 LOG.error("removeNaptPortPool : Failed to delete PortPool {} for NAPT Service", poolName, e);
139 // 1. napt service functions
142 * This method is used to inform this service of what external IP address to be used
143 * as mapping when requested one for the internal IP address given in the input.
145 * @param segmentId – segmentation in which the mapping to be used. Eg; routerid
146 * @param internal subnet prefix or ip address
147 * @param external subnet prefix or ip address
150 public void registerMapping(long segmentId, IPAddress internal, IPAddress external) {
151 LOG.debug("registerMapping : called with segmentid {}, internalIp {}, prefix {}, externalIp {} "
152 + "and prefix {} ", segmentId, internal.getIpAddress(),
153 internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength());
154 // Create Pool per ExternalIp and not for all IPs in the subnet.
155 // Create new Pools during getExternalAddressMapping if exhausted.
156 String externalIpPool;
158 if (external.getPrefixLength() != 0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) {
159 String externalSubnet = external.getIpAddress() + "/" + external.getPrefixLength();
160 LOG.debug("registerMapping : externalSubnet is : {}", externalSubnet);
161 SubnetUtils subnetUtils = new SubnetUtils(externalSubnet);
162 SubnetInfo subnetInfo = subnetUtils.getInfo();
163 externalIpPool = subnetInfo.getLowAddress();
165 externalIpPool = external.getIpAddress();
167 createNaptPortPool(externalIpPool);
169 // Store the ip to ip map in Operational DS
170 String internalIp = internal.getIpAddress();
171 if (internal.getPrefixLength() != 0) {
172 internalIp = internal.getIpAddress() + "/" + internal.getPrefixLength();
174 String externalIp = external.getIpAddress();
175 if (external.getPrefixLength() != 0) {
176 externalIp = external.getIpAddress() + "/" + external.getPrefixLength();
178 updateCounter(segmentId, externalIp, true);
179 //update the actual ip-map
180 IpMap ipm = new IpMapBuilder().withKey(new IpMapKey(internalIp)).setInternalIp(internalIp)
181 .setExternalIp(externalIp).build();
182 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
183 getIpMapIdentifier(segmentId, internalIp), ipm);
184 LOG.debug("registerMapping : registerMapping exit after updating DS with internalIP {}, externalIP {}",
185 internalIp, externalIp);
188 public void updateCounter(long segmentId, String externalIp, boolean isAdd) {
190 InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
191 .child(ExternalCounters.class, new ExternalCountersKey(segmentId))
192 .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
193 Optional<ExternalIpCounter> externalIpCounter =
194 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
195 if (externalIpCounter.isPresent()) {
196 counter = externalIpCounter.get().getCounter();
199 LOG.debug("updateCounter : externalIp and counter after increment are {} and {}", externalIp, counter);
204 LOG.debug("updateCounter : externalIp and counter after decrement are {} and {}", externalIp, counter);
211 //update the new counter value for this externalIp
212 ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder()
213 .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter(counter).build();
214 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
215 getExternalIpsIdentifier(segmentId, externalIp), externalIpCounterData);
219 * method to get external ip/port mapping when provided with internal ip/port pair
220 * If already a mapping exist for the given input, then the existing mapping is returned
221 * instead of overwriting with new ip/port pair.
223 * @param segmentId - Router ID
224 * @param sourceAddress - internal ip address/port pair
225 * @param protocol - TCP/UDP
226 * @return external ip address/port
228 // TODO Clean up the exception handling
229 @SuppressWarnings("checkstyle:IllegalCatch")
231 public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress,
232 NAPTEntryEvent.Protocol protocol) {
233 LOG.debug("getExternalAddressMapping : called with segmentId {}, internalIp {} and port {}",
234 segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber());
236 1. Get Internal IP, Port in IP:Port format
237 2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port
238 3. If True return SessionAddress of ExternalIp and Port
239 4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port
242 //SessionAddress externalIpPort = new SessionAddress();
243 String internalIpPort = sourceAddress.getIpAddress() + ":" + sourceAddress.getPortNumber();
245 // First check existing Port Map.
246 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
247 if (existingIpPort != null) {
248 // populate externalIpPort from IpPortMap and return
249 LOG.debug("getExternalAddressMapping : successfully returning existingIpPort as {} and {}",
250 existingIpPort.getIpAddress(), existingIpPort.getPortNumber());
251 return existingIpPort;
254 // Now check in ip-map
255 String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress());
256 if (externalIp == null) {
257 LOG.error("getExternalAddressMapping : Unexpected error, internal to external "
258 + "ip map does not exist");
262 /* Logic assuming internalIp is always ip and not subnet
263 * case 1: externalIp is ip
264 * a) goto externalIp pool and getPort and return
265 * b) else return error
266 * case 2: externalIp is subnet
267 * a) Take first externalIp and goto that Pool and getPort
269 * else Take second externalIp and create that Pool and getPort
272 * Continue same with third externalIp till we exhaust subnet
273 * b) Nothing worked return error
275 SubnetUtils externalIpSubnet;
276 List<String> allIps = new ArrayList<>();
277 String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX);
278 boolean extSubnetFlag = false;
279 if (!externalIp.contains(subnetPrefix)) {
280 extSubnetFlag = true;
281 externalIpSubnet = new SubnetUtils(externalIp);
282 allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses());
283 LOG.debug("getExternalAddressMapping : total count of externalIps available {}",
284 externalIpSubnet.getInfo().getAddressCount());
286 LOG.debug("getExternalAddressMapping : getExternalAddress single ip case");
287 if (externalIp.contains(subnetPrefix)) {
288 //remove /32 what we got from checkIpMap
289 externalIp = externalIp.substring(0, externalIp.indexOf(subnetPrefix));
291 allIps.add(externalIp);
294 boolean nextExtIpFlag = false;
295 for (String extIp : allIps) {
296 LOG.info("getExternalAddressMapping : Looping externalIPs with externalIP now as {}", extIp);
298 createNaptPortPool(extIp);
299 LOG.debug("getExternalAddressMapping : Created Pool for next Ext IP {}", extIp);
301 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
302 .setPoolName(extIp).setIdKey(internalIpPort)
305 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
306 RpcResult<AllocateIdOutput> rpcResult;
307 if (result != null && result.get().isSuccessful()) {
308 LOG.debug("getExternalAddressMapping : Got id from idManager");
309 rpcResult = result.get();
311 LOG.error("getExternalAddressMapping : getExternalAddressMapping, idManager could not "
312 + "allocate id retry if subnet");
313 if (!extSubnetFlag) {
314 LOG.error("getExternalAddressMapping : getExternalAddressMapping returning null "
315 + "for single IP case, may be ports exhausted");
318 LOG.debug("getExternalAddressMapping : Could be ports exhausted case, "
319 + "try with another externalIP if possible");
320 nextExtIpFlag = true;
323 int extPort = rpcResult.getResult().getIdValue().intValue();
324 // Write to ip-port-map before returning
325 IpPortExternalBuilder ipExt = new IpPortExternalBuilder();
326 IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build();
327 IpPortMap ipm = new IpPortMapBuilder().withKey(new IpPortMapKey(internalIpPort))
328 .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build();
329 LOG.debug("getExternalAddressMapping : writing into ip-port-map with "
330 + "externalIP {} and port {}",
331 ipPortExt.getIpAddress(), ipPortExt.getPortNum());
333 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
334 getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm);
335 } catch (UncheckedExecutionException uee) {
336 LOG.error("getExternalAddressMapping : Failed to write into ip-port-map with exception",
340 // Write to snat-internal-ip-port-info
341 String internalIpAddress = sourceAddress.getIpAddress();
342 int ipPort = sourceAddress.getPortNumber();
343 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
344 final ReentrantLock lock = lockFor(segmentId, internalIpAddress, protocolType);
347 List<Integer> portList = new ArrayList<>(
348 NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, internalIpAddress,
350 portList.add(ipPort);
352 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
353 IntIpProtoType intIpProtocolType =
354 builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
356 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
357 NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType),
359 } catch (Exception ex) {
360 LOG.error("getExternalAddressMapping : Failed to write into snat-internal-ip-port-info "
361 + "with exception", ex);
366 SessionAddress externalIpPort = new SessionAddress(extIp, extPort);
367 LOG.debug("getExternalAddressMapping : successfully returning externalIP {} "
368 + "and port {}", externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
369 return externalIpPort;
370 } catch (InterruptedException | ExecutionException e) {
371 LOG.error("getExternalAddressMapping : Exception caught", e);
375 LOG.error("getExternalAddressMapping : Unable to handle external IP address and port mapping with segmentId {},"
376 + "internalIp {} and internalPort {}", segmentId, sourceAddress.getIpAddress(),
377 sourceAddress.getPortNumber());
382 * Release the existing mapping of internal ip/port to external ip/port pair
383 * if no mapping exist for given internal ip/port, it returns false.
385 * @param segmentId - Router ID
386 * @param address - Session Address
387 * @param protocol - TCP/UDP
388 * @return true if mapping exist and the mapping is removed successfully
390 // TODO Clean up the exception handling
391 @SuppressWarnings("checkstyle:IllegalCatch")
392 public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
393 LOG.debug("releaseAddressMapping : called with segmentId {}, internalIP {}, port {}",
394 segmentId, address.getIpAddress(), address.getPortNumber());
395 // delete entry from IpPort Map and IP Map if exists
396 String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
397 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
398 if (existingIpPort != null) {
399 // delete the entry from IpPortMap DS
401 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
402 } catch (Exception e) {
403 LOG.error("releaseAddressMapping : failed, Removal of ipportmap {} for "
404 + "router {} failed", internalIpPort, segmentId, e);
408 LOG.error("releaseAddressMapping : failed, segmentId {} and internalIpPort {} "
409 + "not found in IpPortMap DS", segmentId, internalIpPort);
412 String existingIp = checkIpMap(segmentId, address.getIpAddress());
413 if (existingIp != null) {
414 // delete the entry from IpMap DS
416 removeFromIpMapDS(segmentId, address.getIpAddress());
417 } catch (Exception e) {
418 LOG.error("releaseAddressMapping : Removal of ipmap {} for router {} failed",
419 address.getIpAddress(), segmentId, e);
422 //delete the entry from snatIntIpportinfo
424 removeFromSnatIpPortDS(segmentId, address.getIpAddress());
425 } catch (Exception e) {
426 LOG.error("releaseAddressMapping : failed, Removal of snatipportmap {} for "
427 + "router {} failed", address.getIpAddress(), segmentId, e);
431 LOG.error("releaseAddressMapping : failed, segmentId {} and internalIpPort {} "
432 + "not found in IpMap DS", segmentId, internalIpPort);
435 // Finally release port from idmanager
436 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
438 LOG.debug("releaseAddressMapping : Exited successfully for segmentId {} and internalIpPort {}",
439 segmentId, internalIpPort);
443 // TODO Clean up the exception handling
444 @SuppressWarnings("checkstyle:IllegalCatch")
445 protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
446 String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
447 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
448 if (existingIpPort != null) {
449 // delete the entry from IpPortMap DS
451 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
452 // Finally release port from idmanager
453 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
454 } catch (Exception e) {
455 LOG.error("releaseIpExtPortMapping : failed, Removal of ipportmap {} for "
456 + "router {} failed", internalIpPort, segmentId, e);
459 LOG.error("releaseIpExtPortMapping : failed, segmentId {} and "
460 + "internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
463 //delete the entry of port for InternalIp from snatIntIpportMappingDS
464 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
465 final ReentrantLock lock = lockFor(segmentId, address.getIpAddress(), protocolType);
468 removeSnatIntIpPortDS(segmentId, address, protocolType);
469 } catch (Exception e) {
470 LOG.error("releaseSnatIpPortMapping : failed, Removal of snatipportmap {} for router {} failed",
471 address.getIpAddress(), segmentId, e);
478 * Removes the internal ip to external ip mapping if present.
480 * @param segmentId - Router ID
481 * @return true if successfully removed
483 // TODO Clean up the exception handling
484 @SuppressWarnings("checkstyle:IllegalCatch")
485 public boolean removeMapping(long segmentId) {
487 removeIpMappingForRouterID(segmentId);
488 removeIpPortMappingForRouterID(segmentId);
489 removeIntIpPortMappingForRouterID(segmentId);
490 } catch (Exception e) {
491 LOG.error("removeMapping : Removal of IPMapping for router {} failed", segmentId, e);
495 //TODO : This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
499 protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
500 return InstanceIdentifier.builder(IntextIpMap.class)
501 .child(IpMapping.class, new IpMappingKey(segid))
502 .child(IpMap.class, new IpMapKey(internal)).build();
505 protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
506 return InstanceIdentifier.builder(ExternalIpsCounter.class)
507 .child(ExternalCounters.class, new ExternalCountersKey(segmentId))
508 .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
512 public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
513 InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
514 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
515 LogicalDatastoreType.OPERATIONAL, id).toJavaUtil().map(IpMapping::getIpMap).orElse(
516 Collections.emptyList());
519 protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
520 return InstanceIdentifier.builder(
521 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
524 protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal,
525 NAPTEntryEvent.Protocol protocol) {
526 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
527 return InstanceIdentifier.builder(IntextIpPortMap.class)
528 .child(IpPortMapping.class, new IpPortMappingKey(segid))
529 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
530 .child(IpPortMap.class, new IpPortMapKey(internal)).build();
534 private SessionAddress checkIpPortMap(long segmentId, String internalIpPort,
535 NAPTEntryEvent.Protocol protocol) {
536 LOG.debug("checkIpPortMap : called with segmentId {} and internalIpPort {}",
537 segmentId, internalIpPort);
538 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
539 // check if ip-port-map node is there
540 InstanceIdentifierBuilder<IpPortMap> idBuilder =
541 InstanceIdentifier.builder(IntextIpPortMap.class)
542 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
543 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
544 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
545 InstanceIdentifier<IpPortMap> id = idBuilder.build();
546 Optional<IpPortMap> ipPortMapType =
547 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
548 if (ipPortMapType.isPresent()) {
549 LOG.debug("checkIpPortMap : {}", ipPortMapType.get());
550 SessionAddress externalIpPort = new SessionAddress(ipPortMapType.get().getIpPortExternal().getIpAddress(),
551 ipPortMapType.get().getIpPortExternal().getPortNum());
552 LOG.debug("checkIpPortMap : returning successfully externalIP {} and port {}",
553 externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
554 return externalIpPort;
556 // return null if not found
557 LOG.warn("checkIpPortMap : no-entry in checkIpPortMap, returning NULL [should be OK] for "
558 + "segmentId {} and internalIPPort {}", segmentId, internalIpPort);
563 protected String checkIpMap(long segmentId, String internalIp) {
564 LOG.debug("checkIpMap : called with segmentId {} and internalIp {}", segmentId, internalIp);
566 // check if ip-map node is there
567 InstanceIdentifierBuilder<IpMapping> idBuilder =
568 InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
569 InstanceIdentifier<IpMapping> id = idBuilder.build();
570 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
571 if (ipMapping.isPresent()) {
572 for (IpMap ipMap : requireNonNullElse(ipMapping.get().getIpMap(), Collections.<IpMap>emptyList())) {
573 if (Objects.equals(ipMap.getInternalIp(), internalIp)) {
574 LOG.debug("checkIpMap : IpMap : {}", ipMap);
575 externalIp = ipMap.getExternalIp();
576 LOG.debug("checkIpMap : successfully returning externalIp {}", externalIp);
578 } else if (ipMap.getInternalIp().contains("/")) { // subnet case
579 SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
580 SubnetInfo subnetInfo = subnetUtils.getInfo();
581 if (subnetInfo.isInRange(internalIp)) {
582 LOG.debug("checkIpMap : internalIp {} found to be IpMap of internalIpSubnet {}",
583 internalIp, ipMap.getInternalIp());
584 externalIp = ipMap.getExternalIp();
585 LOG.debug("checkIpMap : checkIpMap successfully returning externalIp {}", externalIp);
591 // return null if not found
592 LOG.error("checkIpMap : failed, returning NULL for segmentId {} and internalIp {}",
593 segmentId, internalIp);
597 // TODO Clean up the exception handling
598 @SuppressWarnings("checkstyle:IllegalCatch")
599 protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address, ProtocolTypes protocolType) {
600 LOG.trace("removeSnatIntIpPortDS : method called for IntIpport {} of router {} ",
602 List<Integer> portList =
603 NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, address.getIpAddress(), protocolType);
604 if (portList.isEmpty() || !portList.contains(address.getPortNumber())) {
605 LOG.error("removeSnatIntIpPortDS : Internal IP {} for port {} entry not found in SnatIntIpPort DS",
606 address.getIpAddress(), address.getPortNumber());
609 LOG.trace("removeSnatIntIpPortDS : PortList {} retrieved for InternalIp {} of router {}",
610 portList, address.getIpAddress(), segmentId);
611 Integer port = address.getPortNumber();
612 portList.remove(port);
614 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
615 IntIpProtoType intIpProtocolType =
616 builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
618 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
619 NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType),
621 } catch (Exception ex) {
622 LOG.error("removeSnatIntIpPortDS : Failed to write into snat-internal-ip-port-info with exception", ex);
624 LOG.debug("removeSnatIntIpPortDS : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore",
625 address.getIpAddress(), address.getPortNumber(), segmentId);
628 protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
629 InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
630 .child(IntipPortMap.class, new IntipPortMapKey(segmentId))
631 .child(IpPort.class, new IpPortKey(internalIp)).build();
632 // remove from SnatIpPortDS
633 LOG.debug("removeFromSnatIpPortDS : Removing SnatIpPort from datastore : {}", intIp);
634 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
637 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
638 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
639 removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
642 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
643 InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
644 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
645 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
646 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
647 InstanceIdentifier<IpPortMap> id = idBuilder.build();
648 // remove from ipportmap DS
649 LOG.debug("removeFromIpPortMapDS : Removing ipportmap from datastore : {}", id);
650 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
653 protected void removeFromIpMapDS(long segmentId, String internalIp) {
654 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
655 .child(IpMapping.class, new IpMappingKey(segmentId))
656 .child(IpMap.class, new IpMapKey(internalIp));
657 InstanceIdentifier<IpMap> id = idBuilder.build();
658 // Get externalIp and decrement the counter
659 String externalIp = null;
660 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
661 if (ipMap.isPresent()) {
662 externalIp = ipMap.get().getExternalIp();
663 LOG.debug("removeFromIpMapDS : externalIP is {}", externalIp);
665 LOG.warn("removeFromIpMapDS : ipMap not present for the internal IP {}", internalIp);
668 if (externalIp != null) {
669 updateCounter(segmentId, externalIp, false);
670 // remove from ipmap DS
671 LOG.debug("removeFromIpMapDS : Removing ipmap from datastore");
672 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
674 LOG.warn("removeFromIpMapDS : externalIp not present for the internal IP {}", internalIp);
678 protected void removeIntExtIpMapDS(long segmentId, String internalIp) {
679 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
680 .child(IpMapping.class, new IpMappingKey(segmentId))
681 .child(IpMap.class, new IpMapKey(internalIp));
682 InstanceIdentifier<IpMap> id = idBuilder.build();
684 LOG.debug("removeIntExtIpMapDS : Removing ipmap from datastore");
685 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
689 protected String getExternalIpAllocatedForSubnet(long segmentId, String internalIp) {
690 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
691 .child(IpMapping.class, new IpMappingKey(segmentId))
692 .child(IpMap.class, new IpMapKey(internalIp));
693 InstanceIdentifier<IpMap> id = idBuilder.build();
695 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
696 if (ipMap.isPresent()) {
697 return ipMap.get().getExternalIp();
702 private void removeIpMappingForRouterID(long segmentId) {
703 InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
704 .child(IpMapping.class, new IpMappingKey(segmentId));
705 InstanceIdentifier<IpMapping> id = idBuilder.build();
706 // Get all externalIps and decrement their counters before deleting the ipmap
707 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
708 if (ipMapping.isPresent()) {
709 for (IpMap ipMap : requireNonNullElse(ipMapping.get().getIpMap(), Collections.<IpMap>emptyList())) {
710 String externalIp = ipMap.getExternalIp();
711 LOG.debug("removeIpMappingForRouterID : externalIP is {}", externalIp);
712 if (externalIp != null) {
713 updateCounter(segmentId, externalIp, false);
716 // remove from ipmap DS
717 LOG.debug("removeIpMappingForRouterID : Removing Ipmap for router {} from datastore", segmentId);
718 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
722 void removeIpPortMappingForRouterID(long segmentId) {
723 InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
724 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
725 Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
727 if (ipPortMapping.isPresent()) {
728 // remove from IntExtIpPortmap DS
729 LOG.debug("removeIpPortMappingForRouterID : Removing IntExtIpPort map for router {} from datastore",
731 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder);
735 void removeIntIpPortMappingForRouterID(long segmentId) {
736 InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
737 .child(IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
738 Optional<IntipPortMap> intIpPortMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
739 if (intIpPortMap.isPresent()) {
740 // remove from SnatIntIpPortmap DS
741 LOG.debug("removeIntIpPortMappingForRouterID : Removing SnatIntIpPort from datastore : {}", intIp);
742 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
746 void removePortFromPool(String internalIpPort, String externalIp) {
747 LOG.debug("removePortFromPool : method called");
748 ReleaseIdInput idInput = new ReleaseIdInputBuilder()
749 .setPoolName(externalIp)
750 .setIdKey(internalIpPort).build();
752 RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(idInput).get();
753 if (!rpcResult.isSuccessful()) {
754 LOG.error("removePortFromPool : idmanager failed to remove port from pool {}", rpcResult.getErrors());
756 LOG.debug("removePortFromPool : Removed port from pool for InternalIpPort {} with externalIp {}",
757 internalIpPort, externalIp);
758 } catch (InterruptedException | ExecutionException e) {
759 LOG.error("removePortFromPool : idmanager failed when removing entry in pool with key {} with Exception",
764 protected void initialiseExternalCounter(Routers routers, long routerId) {
765 LOG.debug("initialiseExternalCounter : Initialise External IPs counter");
767 //update the new counter value for this externalIp
768 for (ExternalIps externalIp : requireNonNullElse(routers.getExternalIps(),
769 Collections.<ExternalIps>emptyList())) {
770 String[] ipSplit = externalIp.getIpAddress().split("/");
771 String extIp = ipSplit[0];
772 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
773 if (ipSplit.length == 2) {
774 extPrefix = ipSplit[1];
776 extIp = extIp + "/" + extPrefix;
777 initialiseNewExternalIpCounter(routerId, extIp);
781 protected void initialiseNewExternalIpCounter(long routerId, String externalIp) {
782 ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder()
783 .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter((short) 0).build();
784 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
785 getExternalIpsIdentifier(routerId, externalIp), externalIpCounterData);
788 protected void removeExternalCounter(long routerId) {
789 // Remove from external-counters model
790 InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
791 .child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
792 LOG.debug("removeExternalCounter : Removing ExternalCounterd from datastore");
793 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
796 protected void removeExternalIpCounter(long routerId, String externalIp) {
797 // Remove from external-counters model
798 InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
799 .child(ExternalCounters.class, new ExternalCountersKey(routerId))
800 .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
801 LOG.debug("removeExternalIpCounter : Removing ExternalIpsCounter from datastore");
802 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
805 private static ReentrantLock lockFor(final long segmentId, String ipAddress, final ProtocolTypes protocolType) {
806 // FIXME: use an Identifier class instead?
807 String lockName = new StringBuilder()
809 .append(NatConstants.COLON_SEPARATOR)
811 .append(NatConstants.COLON_SEPARATOR)
812 .append(protocolType.getName()).toString();
814 return JvmGlobalLocks.getLockForString(lockName);