/* * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ /* * Created eyugsar 2016/12/1 */ package org.opendaylight.netvirt.natservice.internal; import com.google.common.base.Optional; import com.google.common.util.concurrent.UncheckedExecutionException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.locks.ReentrantLock; import javax.inject.Inject; import javax.inject.Singleton; import org.apache.commons.net.util.SubnetUtils; import org.apache.commons.net.util.SubnetUtils.SubnetInfo; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker; import org.opendaylight.genius.mdsalutil.MDSALUtil; import org.opendaylight.genius.utils.JvmGlobalLocks; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.SnatintIpPortMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCountersKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounterKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.IpMappingKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolTypeKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMapKey; 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; 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; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMap; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.IntipPortMapKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPort; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.IpPortKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoType; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.snatint.ip.port.map.intip.port.map.ip.port.IntIpProtoTypeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class NaptManager { private static final Logger LOG = LoggerFactory.getLogger(NaptManager.class); private static final long LOW_PORT = 49152L; private static final long HIGH_PORT = 65535L; private final DataBroker dataBroker; private final IdManagerService idManager; @Inject public NaptManager(final DataBroker dataBroker, final IdManagerService idManager) { this.dataBroker = dataBroker; this.idManager = idManager; } protected void createNaptPortPool(String poolName) { LOG.debug("createNaptPortPool : requested for : {}", poolName); CreateIdPoolInput createPool = new CreateIdPoolInputBuilder() .setPoolName(poolName) .setLow(LOW_PORT) .setHigh(HIGH_PORT) .build(); try { Future> result = idManager.createIdPool(createPool); if (result != null && result.get().isSuccessful()) { LOG.debug("createNaptPortPool : Created PortPool :{}", poolName); } else { LOG.error("createNaptPortPool : Unable to create PortPool : {}", poolName); } } catch (InterruptedException | ExecutionException e) { LOG.error("createNaptPortPool : Failed to create PortPool for NAPT Service", e); } } void removeNaptPortPool(String poolName) { DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(poolName).build(); LOG.debug("removeNaptPortPool : Remove Napt port pool requested for : {}", poolName); try { Future> result = idManager.deleteIdPool(deleteIdPoolInput); if (result != null && result.get().isSuccessful()) { LOG.debug("removeNaptPortPool : Deleted PortPool {}", poolName); } else { LOG.error("removeNaptPortPool : Unable to delete PortPool {}", poolName); } } catch (InterruptedException | ExecutionException e) { LOG.error("removeNaptPortPool : Failed to delete PortPool {} for NAPT Service", poolName, e); } } // 1. napt service functions /** * This method is used to inform this service of what external IP address to be used * as mapping when requested one for the internal IP address given in the input. * * @param segmentId – segmentation in which the mapping to be used. Eg; routerid * @param internal subnet prefix or ip address * @param external subnet prefix or ip address */ public void registerMapping(long segmentId, IPAddress internal, IPAddress external) { LOG.debug("registerMapping : called with segmentid {}, internalIp {}, prefix {}, externalIp {} " + "and prefix {} ", segmentId, internal.getIpAddress(), internal.getPrefixLength(), external.getIpAddress(), external.getPrefixLength()); // Create Pool per ExternalIp and not for all IPs in the subnet. // Create new Pools during getExternalAddressMapping if exhausted. String externalIpPool; // subnet case if (external.getPrefixLength() != 0 && external.getPrefixLength() != NatConstants.DEFAULT_PREFIX) { String externalSubnet = external.getIpAddress() + "/" + external.getPrefixLength(); LOG.debug("registerMapping : externalSubnet is : {}", externalSubnet); SubnetUtils subnetUtils = new SubnetUtils(externalSubnet); SubnetInfo subnetInfo = subnetUtils.getInfo(); externalIpPool = subnetInfo.getLowAddress(); } else { // ip case externalIpPool = external.getIpAddress(); } createNaptPortPool(externalIpPool); // Store the ip to ip map in Operational DS String internalIp = internal.getIpAddress(); if (internal.getPrefixLength() != 0) { internalIp = internal.getIpAddress() + "/" + internal.getPrefixLength(); } String externalIp = external.getIpAddress(); if (external.getPrefixLength() != 0) { externalIp = external.getIpAddress() + "/" + external.getPrefixLength(); } updateCounter(segmentId, externalIp, true); //update the actual ip-map IpMap ipm = new IpMapBuilder().withKey(new IpMapKey(internalIp)).setInternalIp(internalIp) .setExternalIp(externalIp).build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, getIpMapIdentifier(segmentId, internalIp), ipm); LOG.debug("registerMapping : registerMapping exit after updating DS with internalIP {}, externalIP {}", internalIp, externalIp); } public void updateCounter(long segmentId, String externalIp, boolean isAdd) { short counter = 0; InstanceIdentifier id = InstanceIdentifier.builder(ExternalIpsCounter.class) .child(ExternalCounters.class, new ExternalCountersKey(segmentId)) .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build(); Optional externalIpCounter = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); if (externalIpCounter.isPresent()) { counter = externalIpCounter.get().getCounter(); if (isAdd) { counter++; LOG.debug("updateCounter : externalIp and counter after increment are {} and {}", externalIp, counter); } else { if (counter > 0) { counter--; } LOG.debug("updateCounter : externalIp and counter after decrement are {} and {}", externalIp, counter); } } else if (isAdd) { counter = 1; } //update the new counter value for this externalIp ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder() .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter(counter).build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(segmentId, externalIp), externalIpCounterData); } /** * method to get external ip/port mapping when provided with internal ip/port pair * If already a mapping exist for the given input, then the existing mapping is returned * instead of overwriting with new ip/port pair. * * @param segmentId - Router ID * @param sourceAddress - internal ip address/port pair * @param protocol - TCP/UDP * @return external ip address/port */ // TODO Clean up the exception handling @SuppressWarnings("checkstyle:IllegalCatch") @Nullable public SessionAddress getExternalAddressMapping(long segmentId, SessionAddress sourceAddress, NAPTEntryEvent.Protocol protocol) { LOG.debug("getExternalAddressMapping : called with segmentId {}, internalIp {} and port {}", segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber()); /* 1. Get Internal IP, Port in IP:Port format 2. Inside DB with routerId get the list of entries and check if it matches with existing IP:Port 3. If True return SessionAddress of ExternalIp and Port 4. Else check ip Map and Form the ExternalIp and Port and update DB and then return ExternalIp and Port */ //SessionAddress externalIpPort = new SessionAddress(); String internalIpPort = sourceAddress.getIpAddress() + ":" + sourceAddress.getPortNumber(); // First check existing Port Map. SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol); if (existingIpPort != null) { // populate externalIpPort from IpPortMap and return LOG.debug("getExternalAddressMapping : successfully returning existingIpPort as {} and {}", existingIpPort.getIpAddress(), existingIpPort.getPortNumber()); return existingIpPort; } // Now check in ip-map String externalIp = checkIpMap(segmentId, sourceAddress.getIpAddress()); if (externalIp == null) { LOG.error("getExternalAddressMapping : Unexpected error, internal to external " + "ip map does not exist"); return null; } /* Logic assuming internalIp is always ip and not subnet * case 1: externalIp is ip * a) goto externalIp pool and getPort and return * b) else return error * case 2: externalIp is subnet * a) Take first externalIp and goto that Pool and getPort * if port -> return * else Take second externalIp and create that Pool and getPort * if port ->return * else * Continue same with third externalIp till we exhaust subnet * b) Nothing worked return error */ SubnetUtils externalIpSubnet; List allIps = new ArrayList<>(); String subnetPrefix = "/" + String.valueOf(NatConstants.DEFAULT_PREFIX); boolean extSubnetFlag = false; if (!externalIp.contains(subnetPrefix)) { extSubnetFlag = true; externalIpSubnet = new SubnetUtils(externalIp); allIps = Arrays.asList(externalIpSubnet.getInfo().getAllAddresses()); LOG.debug("getExternalAddressMapping : total count of externalIps available {}", externalIpSubnet.getInfo().getAddressCount()); } else { LOG.debug("getExternalAddressMapping : getExternalAddress single ip case"); if (externalIp.contains(subnetPrefix)) { //remove /32 what we got from checkIpMap externalIp = externalIp.substring(0, externalIp.indexOf(subnetPrefix)); } allIps.add(externalIp); } boolean nextExtIpFlag = false; for (String extIp : allIps) { LOG.info("getExternalAddressMapping : Looping externalIPs with externalIP now as {}", extIp); if (nextExtIpFlag) { createNaptPortPool(extIp); LOG.debug("getExternalAddressMapping : Created Pool for next Ext IP {}", extIp); } AllocateIdInput getIdInput = new AllocateIdInputBuilder() .setPoolName(extIp).setIdKey(internalIpPort) .build(); try { Future> result = idManager.allocateId(getIdInput); RpcResult rpcResult; if (result != null && result.get().isSuccessful()) { LOG.debug("getExternalAddressMapping : Got id from idManager"); rpcResult = result.get(); } else { LOG.error("getExternalAddressMapping : getExternalAddressMapping, idManager could not " + "allocate id retry if subnet"); if (!extSubnetFlag) { LOG.error("getExternalAddressMapping : getExternalAddressMapping returning null " + "for single IP case, may be ports exhausted"); return null; } LOG.debug("getExternalAddressMapping : Could be ports exhausted case, " + "try with another externalIP if possible"); nextExtIpFlag = true; continue; } int extPort = rpcResult.getResult().getIdValue().intValue(); // Write to ip-port-map before returning IpPortExternalBuilder ipExt = new IpPortExternalBuilder(); IpPortExternal ipPortExt = ipExt.setIpAddress(extIp).setPortNum(extPort).build(); IpPortMap ipm = new IpPortMapBuilder().withKey(new IpPortMapKey(internalIpPort)) .setIpPortInternal(internalIpPort).setIpPortExternal(ipPortExt).build(); LOG.debug("getExternalAddressMapping : writing into ip-port-map with " + "externalIP {} and port {}", ipPortExt.getIpAddress(), ipPortExt.getPortNum()); try { MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, getIpPortMapIdentifier(segmentId, internalIpPort, protocol), ipm); } catch (UncheckedExecutionException uee) { LOG.error("getExternalAddressMapping : Failed to write into ip-port-map with exception", uee); } // Write to snat-internal-ip-port-info String internalIpAddress = sourceAddress.getIpAddress(); int ipPort = sourceAddress.getPortNumber(); ProtocolTypes protocolType = NatUtil.getProtocolType(protocol); final ReentrantLock lock = lockFor(segmentId, internalIpAddress, protocolType); lock.lock(); try { List portList = new ArrayList<>( NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, internalIpAddress, protocolType)); portList.add(ipPort); IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder(); IntIpProtoType intIpProtocolType = builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build(); try { MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, internalIpAddress, protocolType), intIpProtocolType); } catch (Exception ex) { LOG.error("getExternalAddressMapping : Failed to write into snat-internal-ip-port-info " + "with exception", ex); } } finally { lock.unlock(); } SessionAddress externalIpPort = new SessionAddress(extIp, extPort); LOG.debug("getExternalAddressMapping : successfully returning externalIP {} " + "and port {}", externalIpPort.getIpAddress(), externalIpPort.getPortNumber()); return externalIpPort; } catch (InterruptedException | ExecutionException e) { LOG.error("getExternalAddressMapping : Exception caught", e); return null; } } // end of for loop LOG.error("getExternalAddressMapping : Unable to handle external IP address and port mapping with segmentId {}," + "internalIp {} and internalPort {}", segmentId, sourceAddress.getIpAddress(), sourceAddress.getPortNumber()); return null; } // TODO Clean up the exception handling @SuppressWarnings("checkstyle:IllegalCatch") protected void releaseIpExtPortMapping(long segmentId, SessionAddress address, NAPTEntryEvent.Protocol protocol) { String internalIpPort = address.getIpAddress() + ":" + address.getPortNumber(); SessionAddress existingIpPort = checkIpPortMap(segmentId, internalIpPort, protocol); if (existingIpPort != null) { // delete the entry from IpPortMap DS try { removeFromIpPortMapDS(segmentId, internalIpPort, protocol); // Finally release port from idmanager removePortFromPool(internalIpPort, existingIpPort.getIpAddress()); } catch (Exception e) { LOG.error("releaseIpExtPortMapping : failed, Removal of ipportmap {} for " + "router {} failed", internalIpPort, segmentId, e); } } else { LOG.error("releaseIpExtPortMapping : failed, segmentId {} and " + "internalIpPort {} not found in IpPortMap DS", segmentId, internalIpPort); } //delete the entry of port for InternalIp from snatIntIpportMappingDS ProtocolTypes protocolType = NatUtil.getProtocolType(protocol); final ReentrantLock lock = lockFor(segmentId, address.getIpAddress(), protocolType); lock.lock(); try { removeSnatIntIpPortDS(segmentId, address, protocolType); } catch (Exception e) { LOG.error("releaseSnatIpPortMapping : failed, Removal of snatipportmap {} for router {} failed", address.getIpAddress(), segmentId, e); } finally { lock.unlock(); } } /** * Removes the internal ip to external ip mapping if present. * * @param segmentId - Router ID * @return true if successfully removed */ // TODO Clean up the exception handling @SuppressWarnings("checkstyle:IllegalCatch") public boolean removeMapping(long segmentId) { try { removeIpMappingForRouterID(segmentId); removeIpPortMappingForRouterID(segmentId); removeIntIpPortMappingForRouterID(segmentId); } catch (Exception e) { LOG.error("removeMapping : Removal of IPMapping for router {} failed", segmentId, e); return false; } //TODO : This is when router is deleted then cleanup the entries in tables, ports etc - Delete scenarios return false; } protected InstanceIdentifier getIpMapIdentifier(long segid, String internal) { return InstanceIdentifier.builder(IntextIpMap.class) .child(IpMapping.class, new IpMappingKey(segid)) .child(IpMap.class, new IpMapKey(internal)).build(); } protected InstanceIdentifier getExternalIpsIdentifier(long segmentId, String external) { return InstanceIdentifier.builder(ExternalIpsCounter.class) .child(ExternalCounters.class, new ExternalCountersKey(segmentId)) .child(ExternalIpCounter.class, new ExternalIpCounterKey(external)).build(); } @NonNull public static List getIpMapList(DataBroker broker, Long routerId) { InstanceIdentifier id = getIpMapList(routerId); return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, LogicalDatastoreType.OPERATIONAL, id).toJavaUtil().map(IpMapping::getIpMap).orElse( Collections.emptyList()); } protected static InstanceIdentifier getIpMapList(long routerId) { return InstanceIdentifier.builder( IntextIpMap.class).child(IpMapping.class, new IpMappingKey(routerId)).build(); } protected InstanceIdentifier getIpPortMapIdentifier(long segid, String internal, NAPTEntryEvent.Protocol protocol) { ProtocolTypes protocolType = NatUtil.getProtocolType(protocol); return InstanceIdentifier.builder(IntextIpPortMap.class) .child(IpPortMapping.class, new IpPortMappingKey(segid)) .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)) .child(IpPortMap.class, new IpPortMapKey(internal)).build(); } @Nullable private SessionAddress checkIpPortMap(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) { LOG.debug("checkIpPortMap : called with segmentId {} and internalIpPort {}", segmentId, internalIpPort); ProtocolTypes protocolType = NatUtil.getProtocolType(protocol); // check if ip-port-map node is there InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class) .child(IpPortMapping.class, new IpPortMappingKey(segmentId)) .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)) .child(IpPortMap.class, new IpPortMapKey(internalIpPort)); InstanceIdentifier id = idBuilder.build(); Optional ipPortMapType = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id); if (ipPortMapType.isPresent()) { LOG.debug("checkIpPortMap : {}", ipPortMapType.get()); SessionAddress externalIpPort = new SessionAddress(ipPortMapType.get().getIpPortExternal().getIpAddress(), ipPortMapType.get().getIpPortExternal().getPortNum()); LOG.debug("checkIpPortMap : returning successfully externalIP {} and port {}", externalIpPort.getIpAddress(), externalIpPort.getPortNumber()); return externalIpPort; } // return null if not found LOG.warn("checkIpPortMap : no-entry in checkIpPortMap, returning NULL [should be OK] for " + "segmentId {} and internalIPPort {}", segmentId, internalIpPort); return null; } @Nullable protected String checkIpMap(long segmentId, String internalIp) { LOG.debug("checkIpMap : called with segmentId {} and internalIp {}", segmentId, internalIp); String externalIp; // check if ip-map node is there InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpMap.class).child(IpMapping.class, new IpMappingKey(segmentId)); InstanceIdentifier id = idBuilder.build(); Optional ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); if (ipMapping.isPresent()) { for (IpMap ipMap : ipMapping.get().nonnullIpMap()) { if (Objects.equals(ipMap.getInternalIp(), internalIp)) { LOG.debug("checkIpMap : IpMap : {}", ipMap); externalIp = ipMap.getExternalIp(); LOG.debug("checkIpMap : successfully returning externalIp {}", externalIp); return externalIp; } else if (ipMap.getInternalIp().contains("/")) { // subnet case SubnetUtils subnetUtils = new SubnetUtils(ipMap.getInternalIp()); SubnetInfo subnetInfo = subnetUtils.getInfo(); if (subnetInfo.isInRange(internalIp)) { LOG.debug("checkIpMap : internalIp {} found to be IpMap of internalIpSubnet {}", internalIp, ipMap.getInternalIp()); externalIp = ipMap.getExternalIp(); LOG.debug("checkIpMap : checkIpMap successfully returning externalIp {}", externalIp); return externalIp; } } } } // return null if not found LOG.error("checkIpMap : failed, returning NULL for segmentId {} and internalIp {}", segmentId, internalIp); return null; } // TODO Clean up the exception handling @SuppressWarnings("checkstyle:IllegalCatch") protected void removeSnatIntIpPortDS(long segmentId, SessionAddress address, ProtocolTypes protocolType) { LOG.trace("removeSnatIntIpPortDS : method called for IntIpport {} of router {} ", address, segmentId); List portList = NatUtil.getInternalIpPortListInfo(dataBroker, segmentId, address.getIpAddress(), protocolType); if (portList.isEmpty() || !portList.contains(address.getPortNumber())) { LOG.error("removeSnatIntIpPortDS : Internal IP {} for port {} entry not found in SnatIntIpPort DS", address.getIpAddress(), address.getPortNumber()); return; } LOG.trace("removeSnatIntIpPortDS : PortList {} retrieved for InternalIp {} of router {}", portList, address.getIpAddress(), segmentId); Integer port = address.getPortNumber(); portList.remove(port); IntIpProtoTypeBuilder builder = new IntIpProtoTypeBuilder(); IntIpProtoType intIpProtocolType = builder.withKey(new IntIpProtoTypeKey(protocolType)).setPorts(portList).build(); try { MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, NatUtil.buildSnatIntIpPortIdentifier(segmentId, address.getIpAddress(), protocolType), intIpProtocolType); } catch (Exception ex) { LOG.error("removeSnatIntIpPortDS : Failed to write into snat-internal-ip-port-info with exception", ex); } LOG.debug("removeSnatIntIpPortDS : Removing SnatIp {} Port {} of router {} from SNATIntIpport datastore", address.getIpAddress(), address.getPortNumber(), segmentId); } protected void removeFromSnatIpPortDS(long segmentId, String internalIp) { InstanceIdentifier intIp = InstanceIdentifier.builder(SnatintIpPortMap.class) .child(IntipPortMap.class, new IntipPortMapKey(segmentId)) .child(IpPort.class, new IpPortKey(internalIp)).build(); // remove from SnatIpPortDS LOG.debug("removeFromSnatIpPortDS : Removing SnatIpPort from datastore : {}", intIp); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp); } protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, NAPTEntryEvent.Protocol protocol) { ProtocolTypes protocolType = NatUtil.getProtocolType(protocol); removeFromIpPortMapDS(segmentId, internalIpPort, protocolType); } protected void removeFromIpPortMapDS(long segmentId, String internalIpPort, ProtocolTypes protocolType) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class) .child(IpPortMapping.class, new IpPortMappingKey(segmentId)) .child(IntextIpProtocolType.class, new IntextIpProtocolTypeKey(protocolType)) .child(IpPortMap.class, new IpPortMapKey(internalIpPort)); InstanceIdentifier id = idBuilder.build(); // remove from ipportmap DS LOG.debug("removeFromIpPortMapDS : Removing ipportmap from datastore : {}", id); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id); } protected void removeFromIpMapDS(long segmentId, String internalIp) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpMap.class) .child(IpMapping.class, new IpMappingKey(segmentId)) .child(IpMap.class, new IpMapKey(internalIp)); InstanceIdentifier id = idBuilder.build(); // Get externalIp and decrement the counter String externalIp = null; Optional ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); if (ipMap.isPresent()) { externalIp = ipMap.get().getExternalIp(); LOG.debug("removeFromIpMapDS : externalIP is {}", externalIp); } else { LOG.warn("removeFromIpMapDS : ipMap not present for the internal IP {}", internalIp); } if (externalIp != null) { updateCounter(segmentId, externalIp, false); // remove from ipmap DS LOG.debug("removeFromIpMapDS : Removing ipmap from datastore"); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id); } else { LOG.warn("removeFromIpMapDS : externalIp not present for the internal IP {}", internalIp); } } protected void removeIntExtIpMapDS(long segmentId, String internalIp) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpMap.class) .child(IpMapping.class, new IpMappingKey(segmentId)) .child(IpMap.class, new IpMapKey(internalIp)); InstanceIdentifier id = idBuilder.build(); LOG.debug("removeIntExtIpMapDS : Removing ipmap from datastore"); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id); } @Nullable protected String getExternalIpAllocatedForSubnet(long segmentId, String internalIp) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpMap.class) .child(IpMapping.class, new IpMappingKey(segmentId)) .child(IpMap.class, new IpMapKey(internalIp)); InstanceIdentifier id = idBuilder.build(); Optional ipMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); if (ipMap.isPresent()) { return ipMap.get().getExternalIp(); } return null; } private void removeIpMappingForRouterID(long segmentId) { InstanceIdentifierBuilder idBuilder = InstanceIdentifier.builder(IntextIpMap.class) .child(IpMapping.class, new IpMappingKey(segmentId)); InstanceIdentifier id = idBuilder.build(); // Get all externalIps and decrement their counters before deleting the ipmap Optional ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); if (ipMapping.isPresent()) { for (IpMap ipMap : ipMapping.get().nonnullIpMap()) { String externalIp = ipMap.getExternalIp(); LOG.debug("removeIpMappingForRouterID : externalIP is {}", externalIp); if (externalIp != null) { updateCounter(segmentId, externalIp, false); } } // remove from ipmap DS LOG.debug("removeIpMappingForRouterID : Removing Ipmap for router {} from datastore", segmentId); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id); } } void removeIpPortMappingForRouterID(long segmentId) { InstanceIdentifier idBuilder = InstanceIdentifier.builder(IntextIpPortMap.class) .child(IpPortMapping.class, new IpPortMappingKey(segmentId)).build(); Optional ipPortMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder); if (ipPortMapping.isPresent()) { // remove from IntExtIpPortmap DS LOG.debug("removeIpPortMappingForRouterID : Removing IntExtIpPort map for router {} from datastore", segmentId); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, idBuilder); } } void removeIntIpPortMappingForRouterID(long segmentId) { InstanceIdentifier intIp = InstanceIdentifier.builder(SnatintIpPortMap.class) .child(IntipPortMap.class, new IntipPortMapKey(segmentId)).build(); Optional intIpPortMap = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp); if (intIpPortMap.isPresent()) { // remove from SnatIntIpPortmap DS LOG.debug("removeIntIpPortMappingForRouterID : Removing SnatIntIpPort from datastore : {}", intIp); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, intIp); } } void removePortFromPool(String internalIpPort, String externalIp) { LOG.debug("removePortFromPool : method called"); ReleaseIdInput idInput = new ReleaseIdInputBuilder() .setPoolName(externalIp) .setIdKey(internalIpPort).build(); try { RpcResult rpcResult = idManager.releaseId(idInput).get(); if (!rpcResult.isSuccessful()) { LOG.error("removePortFromPool : idmanager failed to remove port from pool {}", rpcResult.getErrors()); } LOG.debug("removePortFromPool : Removed port from pool for InternalIpPort {} with externalIp {}", internalIpPort, externalIp); } catch (InterruptedException | ExecutionException e) { LOG.error("removePortFromPool : idmanager failed when removing entry in pool with key {} with Exception", internalIpPort, e); } } protected void initialiseExternalCounter(Routers routers, long routerId) { LOG.debug("initialiseExternalCounter : Initialise External IPs counter"); //update the new counter value for this externalIp for (ExternalIps externalIp : routers.nonnullExternalIps()) { String[] ipSplit = externalIp.getIpAddress().split("/"); String extIp = ipSplit[0]; String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX); if (ipSplit.length == 2) { extPrefix = ipSplit[1]; } extIp = extIp + "/" + extPrefix; initialiseNewExternalIpCounter(routerId, extIp); } } protected void initialiseNewExternalIpCounter(long routerId, String externalIp) { ExternalIpCounter externalIpCounterData = new ExternalIpCounterBuilder() .withKey(new ExternalIpCounterKey(externalIp)).setExternalIp(externalIp).setCounter((short) 0).build(); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, getExternalIpsIdentifier(routerId, externalIp), externalIpCounterData); } protected void removeExternalCounter(long routerId) { // Remove from external-counters model InstanceIdentifier id = InstanceIdentifier.builder(ExternalIpsCounter.class) .child(ExternalCounters.class, new ExternalCountersKey(routerId)).build(); LOG.debug("removeExternalCounter : Removing ExternalCounterd from datastore"); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id); } protected void removeExternalIpCounter(long routerId, String externalIp) { // Remove from external-counters model InstanceIdentifier id = InstanceIdentifier.builder(ExternalIpsCounter.class) .child(ExternalCounters.class, new ExternalCountersKey(routerId)) .child(ExternalIpCounter.class, new ExternalIpCounterKey(externalIp)).build(); LOG.debug("removeExternalIpCounter : Removing ExternalIpsCounter from datastore"); MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id); } private static ReentrantLock lockFor(final long segmentId, String ipAddress, final ProtocolTypes protocolType) { // FIXME: use an Identifier class instead? String lockName = new StringBuilder() .append(segmentId) .append(NatConstants.COLON_SEPARATOR) .append(ipAddress) .append(NatConstants.COLON_SEPARATOR) .append(protocolType.getName()).toString(); return JvmGlobalLocks.getLockForString(lockName); } }