All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.netvirt.natservice.internal.NaptManager Maven / Gradle / Ivy

There is a newer version: 0.11.4
Show newest version
/*
 * 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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy