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.inject.Inject;
25 import javax.inject.Singleton;
26 import org.apache.commons.net.util.SubnetUtils;
27 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
28 import org.eclipse.jdt.annotation.NonNull;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.utils.JvmGlobalLocks;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.SnatintIpPortMap;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCountersKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternalBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMap;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
83 import org.opendaylight.yangtools.yang.common.RpcResult;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
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());
379 // TODO Clean up the exception handling
380 @SuppressWarnings("checkstyle:IllegalCatch")
381 protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) {
382 String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber();
383 SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol);
384 if (existingIpPort != null) {
385 // delete the entry from IpPortMap DS
387 removeFromIpPortMapDS(segmentId, internalIpPort, protocol);
388 // Finally release port from idmanager
389 removePortFromPool(internalIpPort, existingIpPort.getIpAddress());
390 } catch (Exception e) {
391 LOG.error("releaseIpExtPortMapping : failed, Removal of ipportmap {} for "
392 + "router {} failed", internalIpPort, segmentId, e);
395 LOG.error("releaseIpExtPortMapping : failed, segmentId {} and "
396 + "internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort);
399 //delete the entry of port for InternalIp from snatIntIpportMappingDS
400 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
401 final ReentrantLock lock = lockFor(segmentId, address.getIpAddress(), protocolType);
404 removeSnatIntIpPortDS(segmentId, address, protocolType);
405 } catch (Exception e) {
406 LOG.error("releaseSnatIpPortMapping : failed, Removal of snatipportmap {} for router {} failed",
407 address.getIpAddress(), segmentId, e);
414 * Removes the internal ip to external ip mapping if present.
416 * @param segmentId - Router ID
417 * @return true if successfully removed
419 // TODO Clean up the exception handling
420 @SuppressWarnings("checkstyle:IllegalCatch")
421 public boolean removeMapping(long segmentId) {
423 removeIpMappingForRouterID(segmentId);
424 removeIpPortMappingForRouterID(segmentId);
425 removeIntIpPortMappingForRouterID(segmentId);
426 } catch (Exception e) {
427 LOG.error("removeMapping : Removal of IPMapping for router {} failed", segmentId, e);
431 //TODO : This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios
435 protected InstanceIdentifier<IpMap> getIpMapIdentifier(long segid, String internal) {
436 return InstanceIdentifier.builder(IntextIpMap.class)
437 .child(IpMapping.class, new IpMappingKey(segid))
438 .child(IpMap.class, new IpMapKey(internal)).build();
441 protected InstanceIdentifier<ExternalIpCounter> getExternalIpsIdentifier(long segmentId, String external) {
442 return InstanceIdentifier.builder(ExternalIpsCounter.class)
443 .child(ExternalCounters.class, new ExternalCountersKey(segmentId))
444 .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build();
448 public static List<IpMap> getIpMapList(DataBroker broker, Long routerId) {
449 InstanceIdentifier<IpMapping> id = getIpMapList(routerId);
450 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
451 LogicalDatastoreType.OPERATIONAL, id).toJavaUtil().map(IpMapping::getIpMap).orElse(
452 Collections.emptyList());
455 protected static InstanceIdentifier<IpMapping> getIpMapList(long routerId) {
456 return InstanceIdentifier.builder(
457 IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build();
460 protected InstanceIdentifier<IpPortMap> getIpPortMapIdentifier(long segid, String internal,
461 NAPTEntryEvent.Protocol protocol) {
462 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
463 return InstanceIdentifier.builder(IntextIpPortMap.class)
464 .child(IpPortMapping.class, new IpPortMappingKey(segid))
465 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
466 .child(IpPortMap.class, new IpPortMapKey(internal)).build();
470 private SessionAddress checkIpPortMap(long segmentId, String internalIpPort,
471 NAPTEntryEvent.Protocol protocol) {
472 LOG.debug("checkIpPortMap : called with segmentId {} and internalIpPort {}",
473 segmentId, internalIpPort);
474 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
475 // check if ip-port-map node is there
476 InstanceIdentifierBuilder<IpPortMap> idBuilder =
477 InstanceIdentifier.builder(IntextIpPortMap.class)
478 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
479 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
480 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
481 InstanceIdentifier<IpPortMap> id = idBuilder.build();
482 Optional<IpPortMap> ipPortMapType =
483 MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
484 if (ipPortMapType.isPresent()) {
485 LOG.debug("checkIpPortMap : {}", ipPortMapType.get());
486 SessionAddress externalIpPort = new SessionAddress(ipPortMapType.get().getIpPortExternal().getIpAddress(),
487 ipPortMapType.get().getIpPortExternal().getPortNum());
488 LOG.debug("checkIpPortMap : returning successfully externalIP {} and port {}",
489 externalIpPort.getIpAddress(), externalIpPort.getPortNumber());
490 return externalIpPort;
492 // return null if not found
493 LOG.warn("checkIpPortMap : no-entry in checkIpPortMap, returning NULL [should be OK] for "
494 + "segmentId {} and internalIPPort {}", segmentId, internalIpPort);
499 protected String checkIpMap(long segmentId, String internalIp) {
500 LOG.debug("checkIpMap : called with segmentId {} and internalIp {}", segmentId, internalIp);
502 // check if ip-map node is there
503 InstanceIdentifierBuilder<IpMapping> idBuilder =
504 InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId));
505 InstanceIdentifier<IpMapping> id = idBuilder.build();
506 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
507 if (ipMapping.isPresent()) {
508 for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
509 if (Objects.equals(ipMap.getInternalIp(), internalIp)) {
510 LOG.debug("checkIpMap : IpMap : {}", ipMap);
511 externalIp = ipMap.getExternalIp();
512 LOG.debug("checkIpMap : successfully returning externalIp {}", externalIp);
514 } else if (ipMap.getInternalIp().contains("/")) { // subnet case
515 SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp());
516 SubnetInfo subnetInfo = subnetUtils.getInfo();
517 if (subnetInfo.isInRange(internalIp)) {
518 LOG.debug("checkIpMap : internalIp {} found to be IpMap of internalIpSubnet {}",
519 internalIp, ipMap.getInternalIp());
520 externalIp = ipMap.getExternalIp();
521 LOG.debug("checkIpMap : checkIpMap successfully returning externalIp {}", externalIp);
527 // return null if not found
528 LOG.error("checkIpMap : failed, returning NULL for segmentId {} and internalIp {}",
529 segmentId, internalIp);
533 // TODO Clean up the exception handling
534 @SuppressWarnings("checkstyle:IllegalCatch")
535 protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address, ProtocolTypes protocolType) {
536 LOG.trace("removeSnatIntIpPortDS : method called for IntIpport {} of router {} ",
538 List<Integer> portList =
539 NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, address.getIpAddress(), protocolType);
540 if (portList.isEmpty() || !portList.contains(address.getPortNumber())) {
541 LOG.error("removeSnatIntIpPortDS : Internal IP {} for port {} entry not found in SnatIntIpPort DS",
542 address.getIpAddress(), address.getPortNumber());
545 LOG.trace("removeSnatIntIpPortDS : PortList {} retrieved for InternalIp {} of router {}",
546 portList, address.getIpAddress(), segmentId);
547 Integer port = address.getPortNumber();
548 portList.remove(port);
550 IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder();
551 IntIpProtoType intIpProtocolType =
552 builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build();
554 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
555 NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType),
557 } catch (Exception ex) {
558 LOG.error("removeSnatIntIpPortDS : Failed to write into snat-internal-ip-port-info with exception", ex);
560 LOG.debug("removeSnatIntIpPortDS : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore",
561 address.getIpAddress(), address.getPortNumber(), segmentId);
564 protected void removeFromSnatIpPortDS(long segmentId, String internalIp) {
565 InstanceIdentifier<IpPort> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
566 .child(IntipPortMap.class, new IntipPortMapKey(segmentId))
567 .child(IpPort.class, new IpPortKey(internalIp)).build();
568 // remove from SnatIpPortDS
569 LOG.debug("removeFromSnatIpPortDS : Removing SnatIpPort from datastore : {}", intIp);
570 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
573 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) {
574 ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
575 removeFromIpPortMapDS(segmentId, internalIpPort, protocolType);
578 protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) {
579 InstanceIdentifierBuilder<IpPortMap> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
580 .child(IpPortMapping.class, new IpPortMappingKey(segmentId))
581 .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType))
582 .child(IpPortMap.class, new IpPortMapKey(internalIpPort));
583 InstanceIdentifier<IpPortMap> id = idBuilder.build();
584 // remove from ipportmap DS
585 LOG.debug("removeFromIpPortMapDS : Removing ipportmap from datastore : {}", id);
586 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
589 protected void removeFromIpMapDS(long segmentId, String internalIp) {
590 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
591 .child(IpMapping.class, new IpMappingKey(segmentId))
592 .child(IpMap.class, new IpMapKey(internalIp));
593 InstanceIdentifier<IpMap> id = idBuilder.build();
594 // Get externalIp and decrement the counter
595 String externalIp = null;
596 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
597 if (ipMap.isPresent()) {
598 externalIp = ipMap.get().getExternalIp();
599 LOG.debug("removeFromIpMapDS : externalIP is {}", externalIp);
601 LOG.warn("removeFromIpMapDS : ipMap not present for the internal IP {}", internalIp);
604 if (externalIp != null) {
605 updateCounter(segmentId, externalIp, false);
606 // remove from ipmap DS
607 LOG.debug("removeFromIpMapDS : Removing ipmap from datastore");
608 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
610 LOG.warn("removeFromIpMapDS : externalIp not present for the internal IP {}", internalIp);
614 protected void removeIntExtIpMapDS(long segmentId, String internalIp) {
615 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
616 .child(IpMapping.class, new IpMappingKey(segmentId))
617 .child(IpMap.class, new IpMapKey(internalIp));
618 InstanceIdentifier<IpMap> id = idBuilder.build();
620 LOG.debug("removeIntExtIpMapDS : Removing ipmap from datastore");
621 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
625 protected String getExternalIpAllocatedForSubnet(long segmentId, String internalIp) {
626 InstanceIdentifierBuilder<IpMap> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
627 .child(IpMapping.class, new IpMappingKey(segmentId))
628 .child(IpMap.class, new IpMapKey(internalIp));
629 InstanceIdentifier<IpMap> id = idBuilder.build();
631 Optional<IpMap> ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
632 if (ipMap.isPresent()) {
633 return ipMap.get().getExternalIp();
638 private void removeIpMappingForRouterID(long segmentId) {
639 InstanceIdentifierBuilder<IpMapping> idBuilder = InstanceIdentifier.builder(IntextIpMap.class)
640 .child(IpMapping.class, new IpMappingKey(segmentId));
641 InstanceIdentifier<IpMapping> id = idBuilder.build();
642 // Get all externalIps and decrement their counters before deleting the ipmap
643 Optional<IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
644 if (ipMapping.isPresent()) {
645 for (IpMap ipMap : ipMapping.get().nonnullIpMap()) {
646 String externalIp = ipMap.getExternalIp();
647 LOG.debug("removeIpMappingForRouterID : externalIP is {}", externalIp);
648 if (externalIp != null) {
649 updateCounter(segmentId, externalIp, false);
652 // remove from ipmap DS
653 LOG.debug("removeIpMappingForRouterID : Removing Ipmap for router {} from datastore", segmentId);
654 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
658 void removeIpPortMappingForRouterID(long segmentId) {
659 InstanceIdentifier<IpPortMapping> idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class)
660 .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build();
661 Optional<IpPortMapping> ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
663 if (ipPortMapping.isPresent()) {
664 // remove from IntExtIpPortmap DS
665 LOG.debug("removeIpPortMappingForRouterID : Removing IntExtIpPort map for router {} from datastore",
667 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder);
671 void removeIntIpPortMappingForRouterID(long segmentId) {
672 InstanceIdentifier<IntipPortMap> intIp = InstanceIdentifier.builder(SnatintIpPortMap.class)
673 .child(IntipPortMap.class, new IntipPortMapKey(segmentId)).build();
674 Optional<IntipPortMap> intIpPortMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
675 if (intIpPortMap.isPresent()) {
676 // remove from SnatIntIpPortmap DS
677 LOG.debug("removeIntIpPortMappingForRouterID : Removing SnatIntIpPort from datastore : {}", intIp);
678 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp);
682 void removePortFromPool(String internalIpPort, String externalIp) {
683 LOG.debug("removePortFromPool : method called");
684 ReleaseIdInput idInput = new ReleaseIdInputBuilder()
685 .setPoolName(externalIp)
686 .setIdKey(internalIpPort).build();
688 RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(idInput).get();
689 if (!rpcResult.isSuccessful()) {
690 LOG.error("removePortFromPool : idmanager failed to remove port from pool {}", rpcResult.getErrors());
692 LOG.debug("removePortFromPool : Removed port from pool for InternalIpPort {} with externalIp {}",
693 internalIpPort, externalIp);
694 } catch (InterruptedException | ExecutionException e) {
695 LOG.error("removePortFromPool : idmanager failed when removing entry in pool with key {} with Exception",
700 protected void initialiseExternalCounter(Routers routers, long routerId) {
701 LOG.debug("initialiseExternalCounter : Initialise External IPs counter");
703 //update the new counter value for this externalIp
704 for (ExternalIps externalIp : routers.nonnullExternalIps()) {
705 String[] ipSplit = externalIp.getIpAddress().split("/");
706 String extIp = ipSplit[0];
707 String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
708 if (ipSplit.length == 2) {
709 extPrefix = ipSplit[1];
711 extIp = extIp + "/" + extPrefix;
712 initialiseNewExternalIpCounter(routerId, extIp);
716 protected void initialiseNewExternalIpCounter(long routerId, String externalIp) {
717 ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder()
718 .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter((short) 0).build();
719 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
720 getExternalIpsIdentifier(routerId, externalIp), externalIpCounterData);
723 protected void removeExternalCounter(long routerId) {
724 // Remove from external-counters model
725 InstanceIdentifier<ExternalCounters> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
726 .child(ExternalCounters.class, new ExternalCountersKey(routerId)).build();
727 LOG.debug("removeExternalCounter : Removing ExternalCounterd from datastore");
728 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
731 protected void removeExternalIpCounter(long routerId, String externalIp) {
732 // Remove from external-counters model
733 InstanceIdentifier<ExternalIpCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class)
734 .child(ExternalCounters.class, new ExternalCountersKey(routerId))
735 .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build();
736 LOG.debug("removeExternalIpCounter : Removing ExternalIpsCounter from datastore");
737 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
740 private static ReentrantLock lockFor(final long segmentId, String ipAddress, final ProtocolTypes protocolType) {
741 // FIXME: use an Identifier class instead?
742 String lockName = new StringBuilder()
744 .append(NatConstants.COLON_SEPARATOR)
746 .append(NatConstants.COLON_SEPARATOR)
747 .append(protocolType.getName()).toString();
749 return JvmGlobalLocks.getLockForString(lockName);