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 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.annotation.Nonnull;
25 import javax.annotation.Nullable;
26 import javax.inject.Inject;
27 import javax.inject.Singleton;
28 import org.apache.commons.net.util.SubnetUtils;
29 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
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;
88 public class NaptManager {
89 private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class);
91 private static final long LOW_PORT = 49152L;
92 private static final long HIGH_PORT = 65535L;
94 private final DataBroker dataBroker;
95 private final IdManagerService idManager;
98 public NaptManager(final DataBroker dataBroker, final IdManagerService idManager) {
99 this.dataBroker = dataBroker;
100 this.idManager = idManager;
103 protected void createNaptPortPool(String poolName) {
104 LOG.debug("createNaptPortPool : requested for : {}", poolName);
105 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
106 .setPoolName(poolName)
111 Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
112 if (result != null && result.get().isSuccessful()) {
113 LOG.debug("createNaptPortPool : Created PortPool :{}", poolName);
115 LOG.error("createNaptPortPool : Unable to create PortPool : {}", poolName);
117 } catch (InterruptedException | ExecutionException e) {
118 LOG.error("createNaptPortPool : Failed to create PortPool for NAPT Service", e);
122 void removeNaptPortPool(String poolName) {
123 DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
124 LOG.debug("removeNaptPortPool : Remove Napt port pool requested for : {}", poolName);
126 Future<RpcResult<DeleteIdPoolOutput>> result = idManager.deleteIdPool(deleteIdPoolInput);
127 if (result != null && result.get().isSuccessful()) {
128 LOG.debug("removeNaptPortPool : Deleted PortPool {}", poolName);
130 LOG.error("removeNaptPortPool : Unable to delete PortPool {}", poolName);
132 } catch (InterruptedException | ExecutionException e) {
133 LOG.error("removeNaptPortPool : Failed to delete PortPool {} for NAPT Service", poolName, e);
137 // 1. napt service functions
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.
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
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;
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();
163 externalIpPool = external.getIpAddress();
165 createNaptPortPool(externalIpPool);
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();
172 String externalIp = external.getIpAddress();
173 if (external.getPrefixLength() != 0) {
174 externalIp = external.getIpAddress() + "/" + external.getPrefixLength();
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);
186 public void updateCounter(long segmentId, String externalIp, boolean isAdd) {
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();
197 LOG.debug("updateCounter : externalIp and counter after increment are {} and {}", externalIp, counter);
202 LOG.debug("updateCounter : externalIp and counter after decrement are {} and {}", externalIp, counter);
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);
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.
221 * @param segmentId - Router ID
222 * @param sourceAddress - internal ip address/port pair
223 * @param protocol - TCP/UDP
224 * @return external ip address/port
226 // TODO Clean up the exception handling
227 @SuppressWarnings("checkstyle:IllegalCatch")
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());
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
240 //SessionAddress externalIpPort = new SessionAddress();
241 String internalIpPort = sourceAddress.getIpAddress() + ":" + sourceAddress.getPortNumber();
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;
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");
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
267 * else Take second externalIp and create that Pool and getPort
270 * Continue same with third externalIp till we exhaust subnet
271 * b) Nothing worked return error
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());
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));
289 allIps.add(externalIp);
292 boolean nextExtIpFlag = false;
293 for (String extIp : allIps) {
294 LOG.info("getExternalAddressMapping : Looping externalIPs with externalIP now as {}", extIp);
296 createNaptPortPool(extIp);
297 LOG.debug("getExternalAddressMapping : Created Pool for next Ext IP {}", extIp);
299 AllocateIdInput getIdInput = new AllocateIdInputBuilder()
300 .setPoolName(extIp).setIdKey(internalIpPort)
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();
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");
316 LOG.debug("getExternalAddressMapping : Could be ports exhausted case, "
317 + "try with another externalIP if possible");
318 nextExtIpFlag = true;
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());
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",
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);
345 List<Integer> portList = new ArrayList<>(
346 NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, internalIpAddress,
348 portList.add(ipPort);
350 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
351 IntIpProtoType intIpProtocolType =
352 builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
354 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
355 NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType),
357 } catch (Exception ex) {
358 LOG.error("getExternalAddressMapping : Failed to write into snat-internal-ip-port-info "
359 + "with exception", ex);
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);
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());
380 * Release the existing mapping of internal ip/port to external ip/port pair
381 * if no mapping exist for given internal ip/port, it returns false.
383 * @param segmentId - Router ID
384 * @param address - Session Address
385 * @param protocol - TCP/UDP
386 * @return true if mapping exist and the mapping is removed successfully
388 // TODO Clean up the exception handling
389 @SuppressWarnings("checkstyle:IllegalCatch")
390 public boolean releaseAddressMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
391 LOG.debug("releaseAddressMapping : called with segmentId {}, internalIP {}, port {}",
392 segmentId, address.getIpAddress(), address.getPortNumber());
393 // delete entry from IpPort Map and IP Map if exists
394 String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
395 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
396 if (existingIpPort != null) {
397 // delete the entry from IpPortMap DS
399 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
400 } catch (Exception e) {
401 LOG.error("releaseAddressMapping : failed, Removal of ipportmap {} for "
402 + "router {} failed", internalIpPort, segmentId, e);
406 LOG.error("releaseAddressMapping : failed, segmentId {} and internalIpPort {} "
407 + "not found in IpPortMap DS", segmentId, internalIpPort);
410 String existingIp = checkIpMap(segmentId, address.getIpAddress());
411 if (existingIp != null) {
412 // delete the entry from IpMap DS
414 removeFromIpMapDS(segmentId, address.getIpAddress());
415 } catch (Exception e) {
416 LOG.error("releaseAddressMapping : Removal of ipmap {} for router {} failed",
417 address.getIpAddress(), segmentId, e);
420 //delete the entry from snatIntIpportinfo
422 removeFromSnatIpPortDS(segmentId, address.getIpAddress());
423 } catch (Exception e) {
424 LOG.error("releaseAddressMapping : failed, Removal of snatipportmap {} for "
425 + "router {} failed", address.getIpAddress(), segmentId, e);
429 LOG.error("releaseAddressMapping : failed, segmentId {} and internalIpPort {} "
430 + "not found in IpMap DS", segmentId, internalIpPort);
433 // Finally release port from idmanager
434 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
436 LOG.debug("releaseAddressMapping : Exited successfully for segmentId {} and internalIpPort {}",
437 segmentId, internalIpPort);
441 // TODO Clean up the exception handling
442 @SuppressWarnings("checkstyle:IllegalCatch")
443 protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
444 String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
445 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
446 if (existingIpPort != null) {
447 // delete the entry from IpPortMap DS
449 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
450 // Finally release port from idmanager
451 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
452 } catch (Exception e) {
453 LOG.error("releaseIpExtPortMapping : failed, Removal of ipportmap {} for "
454 + "router {} failed", internalIpPort, segmentId, e);
457 LOG.error("releaseIpExtPortMapping : failed, segmentId {} and "
458 + "internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
461 //delete the entry of port for InternalIp from snatIntIpportMappingDS
462 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
463 final ReentrantLock lock = lockFor(segmentId, address.getIpAddress(), protocolType);
466 removeSnatIntIpPortDS(segmentId, address, protocolType);
467 } catch (Exception e) {
468 LOG.error("releaseSnatIpPortMapping : failed, Removal of snatipportmap {} for router {} failed",
469 address.getIpAddress(), segmentId, e);
476 * Removes the internal ip to external ip mapping if present.
478 * @param segmentId - Router ID
479 * @return true if successfully removed
481 // TODO Clean up the exception handling
482 @SuppressWarnings("checkstyle:IllegalCatch")
483 public boolean removeMapping(long segmentId) {
485 removeIpMappingForRouterID(segmentId);
486 removeIpPortMappingForRouterID(segmentId);
487 removeIntIpPortMappingForRouterID(segmentId);
488 } catch (Exception e) {
489 LOG.error("removeMapping : Removal of IPMapping for router {} failed", segmentId, e);
493 //TODO : This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
497 protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
498 return InstanceIdentifier.builder(IntextIpMap.class)
499 .child(IpMapping.class, new IpMappingKey(segid))
500 .child(IpMap.class, new IpMapKey(internal)).build();
503 protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
504 return InstanceIdentifier.builder(ExternalIpsCounter.class)
505 .child(ExternalCounters.class, new ExternalCountersKey(segmentId))
506 .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
510 public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
511 InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
512 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
513 LogicalDatastoreType.OPERATIONAL, id).toJavaUtil().map(IpMapping::getIpMap).orElse(
514 Collections.emptyList());
517 protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
518 return InstanceIdentifier.builder(
519 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
522 protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal,
523 NAPTEntryEvent.Protocol protocol) {
524 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
525 return InstanceIdentifier.builder(IntextIpPortMap.class)
526 .child(IpPortMapping.class, new IpPortMappingKey(segid))
527 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
528 .child(IpPortMap.class, new IpPortMapKey(internal)).build();
532 private SessionAddress checkIpPortMap(long segmentId, String internalIpPort,
533 NAPTEntryEvent.Protocol protocol) {
534 LOG.debug("checkIpPortMap : called with segmentId {} and internalIpPort {}",
535 segmentId, internalIpPort);
536 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
537 // check if ip-port-map node is there
538 InstanceIdentifierBuilder<IpPortMap> idBuilder =
539 InstanceIdentifier.builder(IntextIpPortMap.class)
540 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
541 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
542 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
543 InstanceIdentifier<IpPortMap> id = idBuilder.build();
544 Optional<IpPortMap> ipPortMapType =
545 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
546 if (ipPortMapType.isPresent()) {
547 LOG.debug("checkIpPortMap : {}", ipPortMapType.get());
548 SessionAddress externalIpPort = new SessionAddress(ipPortMapType.get().getIpPortExternal().getIpAddress(),
549 ipPortMapType.get().getIpPortExternal().getPortNum());
550 LOG.debug("checkIpPortMap : returning successfully externalIP {} and port {}",
551 externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
552 return externalIpPort;
554 // return null if not found
555 LOG.warn("checkIpPortMap : no-entry in checkIpPortMap, returning NULL [should be OK] for "
556 + "segmentId {} and internalIPPort {}", segmentId, internalIpPort);
561 protected String checkIpMap(long segmentId, String internalIp) {
562 LOG.debug("checkIpMap : called with segmentId {} and internalIp {}", segmentId, internalIp);
564 // check if ip-map node is there
565 InstanceIdentifierBuilder<IpMapping> idBuilder =
566 InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
567 InstanceIdentifier<IpMapping> id = idBuilder.build();
568 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
569 if (ipMapping.isPresent()) {
570 for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
571 if (Objects.equals(ipMap.getInternalIp(), internalIp)) {
572 LOG.debug("checkIpMap : IpMap : {}", ipMap);
573 externalIp = ipMap.getExternalIp();
574 LOG.debug("checkIpMap : successfully returning externalIp {}", externalIp);
576 } else if (ipMap.getInternalIp().contains("/")) { // subnet case
577 SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
578 SubnetInfo subnetInfo = subnetUtils.getInfo();
579 if (subnetInfo.isInRange(internalIp)) {
580 LOG.debug("checkIpMap : internalIp {} found to be IpMap of internalIpSubnet {}",
581 internalIp, ipMap.getInternalIp());
582 externalIp = ipMap.getExternalIp();
583 LOG.debug("checkIpMap : checkIpMap successfully returning externalIp {}", externalIp);
589 // return null if not found
590 LOG.error("checkIpMap : failed, returning NULL for segmentId {} and internalIp {}",
591 segmentId, internalIp);
595 // TODO Clean up the exception handling
596 @SuppressWarnings("checkstyle:IllegalCatch")
597 protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address, ProtocolTypes protocolType) {
598 LOG.trace("removeSnatIntIpPortDS : method called for IntIpport {} of router {} ",
600 List<Integer> portList =
601 NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, address.getIpAddress(), protocolType);
602 if (portList.isEmpty() || !portList.contains(address.getPortNumber())) {
603 LOG.error("removeSnatIntIpPortDS : Internal IP {} for port {} entry not found in SnatIntIpPort DS",
604 address.getIpAddress(), address.getPortNumber());
607 LOG.trace("removeSnatIntIpPortDS : PortList {} retrieved for InternalIp {} of router {}",
608 portList, address.getIpAddress(), segmentId);
609 Integer port = address.getPortNumber();
610 portList.remove(port);
612 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
613 IntIpProtoType intIpProtocolType =
614 builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
616 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
617 NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType),
619 } catch (Exception ex) {
620 LOG.error("removeSnatIntIpPortDS : Failed to write into snat-internal-ip-port-info with exception", ex);
622 LOG.debug("removeSnatIntIpPortDS : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore",
623 address.getIpAddress(), address.getPortNumber(), segmentId);
626 protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
627 InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
628 .child(IntipPortMap.class, new IntipPortMapKey(segmentId))
629 .child(IpPort.class, new IpPortKey(internalIp)).build();
630 // remove from SnatIpPortDS
631 LOG.debug("removeFromSnatIpPortDS : Removing SnatIpPort from datastore : {}", intIp);
632 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
635 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
636 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
637 removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
640 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
641 InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
642 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
643 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
644 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
645 InstanceIdentifier<IpPortMap> id = idBuilder.build();
646 // remove from ipportmap DS
647 LOG.debug("removeFromIpPortMapDS : Removing ipportmap from datastore : {}", id);
648 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
651 protected void removeFromIpMapDS(long segmentId, String internalIp) {
652 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
653 .child(IpMapping.class, new IpMappingKey(segmentId))
654 .child(IpMap.class, new IpMapKey(internalIp));
655 InstanceIdentifier<IpMap> id = idBuilder.build();
656 // Get externalIp and decrement the counter
657 String externalIp = null;
658 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
659 if (ipMap.isPresent()) {
660 externalIp = ipMap.get().getExternalIp();
661 LOG.debug("removeFromIpMapDS : externalIP is {}", externalIp);
663 LOG.warn("removeFromIpMapDS : ipMap not present for the internal IP {}", internalIp);
666 if (externalIp != null) {
667 updateCounter(segmentId, externalIp, false);
668 // remove from ipmap DS
669 LOG.debug("removeFromIpMapDS : Removing ipmap from datastore");
670 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
672 LOG.warn("removeFromIpMapDS : externalIp not present for the internal IP {}", internalIp);
676 protected void removeIntExtIpMapDS(long segmentId, String internalIp) {
677 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
678 .child(IpMapping.class, new IpMappingKey(segmentId))
679 .child(IpMap.class, new IpMapKey(internalIp));
680 InstanceIdentifier<IpMap> id = idBuilder.build();
682 LOG.debug("removeIntExtIpMapDS : Removing ipmap from datastore");
683 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
687 protected String getExternalIpAllocatedForSubnet(long segmentId, String internalIp) {
688 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
689 .child(IpMapping.class, new IpMappingKey(segmentId))
690 .child(IpMap.class, new IpMapKey(internalIp));
691 InstanceIdentifier<IpMap> id = idBuilder.build();
693 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
694 if (ipMap.isPresent()) {
695 return ipMap.get().getExternalIp();
700 private void removeIpMappingForRouterID(long segmentId) {
701 InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
702 .child(IpMapping.class, new IpMappingKey(segmentId));
703 InstanceIdentifier<IpMapping> id = idBuilder.build();
704 // Get all externalIps and decrement their counters before deleting the ipmap
705 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
706 if (ipMapping.isPresent()) {
707 for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
708 String externalIp = ipMap.getExternalIp();
709 LOG.debug("removeIpMappingForRouterID : externalIP is {}", externalIp);
710 if (externalIp != null) {
711 updateCounter(segmentId, externalIp, false);
714 // remove from ipmap DS
715 LOG.debug("removeIpMappingForRouterID : Removing Ipmap for router {} from datastore", segmentId);
716 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
720 void removeIpPortMappingForRouterID(long segmentId) {
721 InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
722 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
723 Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
725 if (ipPortMapping.isPresent()) {
726 // remove from IntExtIpPortmap DS
727 LOG.debug("removeIpPortMappingForRouterID : Removing IntExtIpPort map for router {} from datastore",
729 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder);
733 void removeIntIpPortMappingForRouterID(long segmentId) {
734 InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
735 .child(IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
736 Optional<IntipPortMap> intIpPortMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
737 if (intIpPortMap.isPresent()) {
738 // remove from SnatIntIpPortmap DS
739 LOG.debug("removeIntIpPortMappingForRouterID : Removing SnatIntIpPort from datastore : {}", intIp);
740 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
744 void removePortFromPool(String internalIpPort, String externalIp) {
745 LOG.debug("removePortFromPool : method called");
746 ReleaseIdInput idInput = new ReleaseIdInputBuilder()
747 .setPoolName(externalIp)
748 .setIdKey(internalIpPort).build();
750 RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(idInput).get();
751 if (!rpcResult.isSuccessful()) {
752 LOG.error("removePortFromPool : idmanager failed to remove port from pool {}", rpcResult.getErrors());
754 LOG.debug("removePortFromPool : Removed port from pool for InternalIpPort {} with externalIp {}",
755 internalIpPort, externalIp);
756 } catch (InterruptedException | ExecutionException e) {
757 LOG.error("removePortFromPool : idmanager failed when removing entry in pool with key {} with Exception",
762 protected void initialiseExternalCounter(Routers routers, long routerId) {
763 LOG.debug("initialiseExternalCounter : Initialise External IPs counter");
765 //update the new counter value for this externalIp
766 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
767 String[] ipSplit = externalIp.getIpAddress().split("/");
768 String extIp = ipSplit[0];
769 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
770 if (ipSplit.length == 2) {
771 extPrefix = ipSplit[1];
773 extIp = extIp + "/" + extPrefix;
774 initialiseNewExternalIpCounter(routerId, extIp);
778 protected void initialiseNewExternalIpCounter(long routerId, String externalIp) {
779 ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder()
780 .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter((short) 0).build();
781 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
782 getExternalIpsIdentifier(routerId, externalIp), externalIpCounterData);
785 protected void removeExternalCounter(long routerId) {
786 // Remove from external-counters model
787 InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
788 .child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
789 LOG.debug("removeExternalCounter : Removing ExternalCounterd from datastore");
790 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
793 protected void removeExternalIpCounter(long routerId, String externalIp) {
794 // Remove from external-counters model
795 InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
796 .child(ExternalCounters.class, new ExternalCountersKey(routerId))
797 .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
798 LOG.debug("removeExternalIpCounter : Removing ExternalIpsCounter from datastore");
799 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
802 private static ReentrantLock lockFor(final long segmentId, String ipAddress, final ProtocolTypes protocolType) {
803 // FIXME: use an Identifier class instead?
804 String lockName = new StringBuilder()
806 .append(NatConstants.COLON_SEPARATOR)
808 .append(NatConstants.COLON_SEPARATOR)
809 .append(protocolType.getName()).toString();
811 return JvmGlobalLocks.getLockForString(lockName);