/* * Copyright 2009-2014 Jagornet Technologies, LLC. All Rights Reserved. * * This software is the proprietary information of Jagornet Technologies, LLC. * Use is subject to license terms. * */ /* * This file V6PrefixBindingPool.java is part of Jagornet DHCP. * * Jagornet DHCP is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jagornet DHCP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jagornet DHCP. If not, see <http://www.gnu.org/licenses/>. * */ package com.jagornet.dhcp.server.request.binding; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jagornet.dhcp.db.IaAddress; import com.jagornet.dhcp.option.v6.DhcpV6ConfigOptions; import com.jagornet.dhcp.server.config.DhcpServerConfigException; import com.jagornet.dhcp.server.config.DhcpV6OptionConfigObject; import com.jagornet.dhcp.util.Subnet; import com.jagornet.dhcp.util.Util; import com.jagornet.dhcp.xml.FiltersType; import com.jagornet.dhcp.xml.LinkFilter; import com.jagornet.dhcp.xml.PoliciesType; import com.jagornet.dhcp.xml.V6PrefixPool; /** * The Class V6PrefixBindingPool. */ public class V6PrefixBindingPool implements BindingPool, DhcpV6OptionConfigObject { private static Logger log = LoggerFactory.getLogger(V6PrefixBindingPool.class); protected Subnet subnet; protected int allocPrefixLen; protected FreeList freeList; protected long preferredLifetime; protected long validLifetime; protected V6PrefixPool pool; protected DhcpV6ConfigOptions dhcpConfigOptions; protected LinkFilter linkFilter; protected Timer reaper; /** * Instantiates a new binding pool. * * @param pool the pool * * @throws DhcpServerConfigException if the PrefixPool definition is invalid */ public V6PrefixBindingPool(V6PrefixPool pool) throws DhcpServerConfigException { try { this.pool = pool; allocPrefixLen = pool.getPrefixLength(); String[] cidr = pool.getRange().split("/"); if ((cidr == null) || (cidr.length != 2)) { throw new DhcpServerConfigException( "Prefix pool must be specified in prefix/len notation"); } subnet = new Subnet(cidr[0], cidr[1]); if (allocPrefixLen < subnet.getPrefixLength()) { throw new DhcpServerConfigException( "Allocation prefix length must be greater or equal to pool prefix length"); } int numPrefixes = (int) Math.pow(2,(allocPrefixLen - subnet.getPrefixLength())); freeList = new FreeList(BigInteger.ZERO, BigInteger.valueOf(numPrefixes).subtract(BigInteger.ONE)); reaper = new Timer(pool.getRange()+"_Reaper"); dhcpConfigOptions = new DhcpV6ConfigOptions(pool.getPrefixConfigOptions()); } catch (NumberFormatException ex) { log.error("Invalid PrefixPool definition", ex); throw new DhcpServerConfigException("Invalid PrefixPool definition", ex); } catch (UnknownHostException ex) { log.error("Invalid PrefixPool definition", ex); throw new DhcpServerConfigException("Invalid PrefixPool definition", ex); } } public int getAllocPrefixLen() { return allocPrefixLen; } private BigInteger calculatePrefix() { return BigInteger.valueOf(2).pow(128-allocPrefixLen); } /** * Gets the next available prefix. * * @return the next available prefix */ public InetAddress getNextAvailableAddress() { if (freeList != null) { BigInteger start = new BigInteger(subnet.getSubnetAddress().getAddress()); BigInteger next = freeList.getNextFree(); if (next != null) { //TODO: if there are no more free addresses, then find one // that has been released or has been expired try { BigInteger prefix = next.multiply(calculatePrefix()); return InetAddress.getByAddress(start.add(prefix).toByteArray()); } catch (Exception ex) { log.error("Unable to build IPv6 prefix from next free: " + ex); } } } return null; } /** * Sets the used. * * @param addr the new used */ public void setUsed(InetAddress addr) { if (contains(addr)) { BigInteger prefix = new BigInteger(addr.getAddress()); BigInteger start = new BigInteger(subnet.getSubnetAddress().getAddress()); freeList.setUsed(prefix.subtract(start).divide(calculatePrefix())); } } /** * Sets the free. * * @param addr the new free */ public void setFree(InetAddress addr) { if (contains(addr)) { BigInteger prefix = new BigInteger(addr.getAddress()); BigInteger start = new BigInteger(subnet.getSubnetAddress().getAddress()); freeList.setFree(prefix.subtract(start).divide(calculatePrefix())); } } /** * Start expire timer task. * * @param iaAddr the ia addr * @param secsUntilExpiration the secs until expiration */ public void startExpireTimerTask(IaAddress iaAddr, long secsUntilExpiration) { // convert delay from seconds (lifetime) --> milliseconds (delay) // reaper.schedule(new ExpireTimerTask(iaAddr), secsUntilExpiration*1000); } /** * Contains. * * @param addr the addr * * @return true, if successful */ public boolean contains(InetAddress addr) { if ((Util.compareInetAddrs(addr, subnet.getSubnetAddress()) >= 0) && (Util.compareInetAddrs(addr, subnet.getEndAddress()) <= 0)) { return true; } return false; } public InetAddress getStartAddress() { return subnet.getSubnetAddress(); } public InetAddress getEndAddress() { return subnet.getEndAddress(); } /** * Gets the preferred lifetime. * * @return the preferred lifetime */ public long getPreferredLifetime() { return preferredLifetime; } /** * Gets the preferred lifetime ms. * * @return the preferred lifetime ms */ public long getPreferredLifetimeMs() { return preferredLifetime*1000; } /** * Sets the preferred lifetime. * * @param preferredLifetime the new preferred lifetime */ public void setPreferredLifetime(long preferredLifetime) { this.preferredLifetime = preferredLifetime; } /** * Gets the valid lifetime. * * @return the valid lifetime */ public long getValidLifetime() { return validLifetime; } /** * Gets the valid lifetime ms. * * @return the valid lifetime ms */ public long getValidLifetimeMs() { return validLifetime*1000; } /** * Sets the valid lifetime. * * @param validLifetime the new valid lifetime */ public void setValidLifetime(long validLifetime) { this.validLifetime = validLifetime; } /** * Gets the pool. * * @return the pool */ public V6PrefixPool getV6PrefixPool() { return pool; } /** * Sets the pool. * * @param pool the new pool */ public void setV6PrefixPool(V6PrefixPool pool) { this.pool = pool; } /** * Gets the link filter. * * @return the link filter */ public LinkFilter getLinkFilter() { return linkFilter; } /** * Sets the link filter. * * @param linkFilter the new link filter */ public void setLinkFilter(LinkFilter linkFilter) { this.linkFilter = linkFilter; } public DhcpV6ConfigOptions getDhcpConfigOptions() { return dhcpConfigOptions; } public void setDhcpConfigOptions(DhcpV6ConfigOptions dhcpConfigOptions) { this.dhcpConfigOptions = dhcpConfigOptions; } public String toString() { return subnet.getSubnetAddress().getHostAddress() + "/" + subnet.getPrefixLength(); } @Override public FiltersType getFilters() { if (pool != null) return pool.getFilters(); return null; } @Override public PoliciesType getPolicies() { if (pool != null) return pool.getPolicies(); return null; } public BigInteger getSize() { // TODO: account for delegated prefix size return new BigInteger(subnet.getEndAddress().getAddress()). subtract(new BigInteger(subnet.getSubnetAddress().getAddress())); } }