Commit 0c3a609f authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[2324] Initial, rough version of allocation engine implemented.

parent ce585a07
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <asiolink/io_address.h>
#include <alloc_engine.h>
using namespace isc::asiolink;
namespace isc {
namespace dhcp {
AllocEngine::IterativeAllocator::IterativeAllocator()
:Allocator() {
}
isc::asiolink::IOAddress
AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const IOAddress& hint) {
// Let's get the last allocated address. It is usually be set correctly,
// but there are times when it won't be (like after removing a pool or
// perhaps restaring the server).
IOAddress last = subnet->getLastAllocated();
const Pool6Collection& pools = subnet->getPools();
if (pools.size() == 0) {
isc_throw(AllocFailed, "No pools defined in selected subnet");
}
Pool6Ptr pool = Pool6Ptr(); // null
// first we need to find a pool the last address belongs to.
Pool6Collection::const_iterator it;
for (it = pools.begin(); it != pools.end(); ++it) {
if ((*it)->inRange(last)) {
break;
}
}
// last one was bogus for one of several reasons:
// - we just booted up and that's the first address we're allocating
// - a subnet was removed or other reconfiguration just completed
// - perhaps allocation algorithm was changed
if (it == pools.end()) {
// ok to access first element directly. We checked that pools is non-empty
IOAddress next = pools[0]->getFirstAddress();
subnet->setLastAllocated(next);
return (next);
}
// Ok, we have a pool that the last address belonged to, let's use it.
IOAddress next = increaseAddress(last); // basically addr++
if ((*it)->inRange(next)) {
// the next one it in pool as well, so we haven't hit pool boundary yet
subnet->setLastAllocated(next);
return (next);
}
// We hit pool boundary, let's try to jump to the next pool and try again
++it;
if (it == pools.end()) {
// Really out of luck today. That was the last pool. Let's rewind
// to the beginning.
next = pools[0]->getFirstAddress();
subnet->setLastAllocated(next);
return (next);
}
// there is a next pool, let's try first adddress from it
next = (*it)->getFirstAddress();
subnet->setLastAllocated(next);
return (next);
}
AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
:attempts_(attempts) {
switch (engine_type) {
case ALLOC_ITERATIVE:
allocator_ = new IterativeAllocator();
break;
#if 0
case ALLOC_HASHED:
allocator_ = new HashedAllocator();
break;
case ALLOC_RANDOM:
allocator_ = new RandomAllocator();
break;
#endif
default:
isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
}
}
Lease6Ptr
AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& hint) {
// That check is not necessary. We create allocator in AllocEngine
// constructor
if (!allocator_) {
isc_throw(InvalidOperation, "No allocator selected");
}
unsigned int i = attempts_;
do {
IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
/// @todo: check if the address is reserved once we have host support
/// implemented
Lease6Ptr existing = LeaseMgr::instance().getLease6(candidate);
// there's no existing lease for selected candidate, so it is
// free. Let's allocate it.
if (!existing) {
Lease6Ptr lease = createLease(subnet, duid, iaid, candidate);
if (lease) {
return (lease);
}
// Although the address was free just microseconds ago, it may have
// been taken just now. If the lease insertion fails, we continue
// allocation attempts.
}
// continue trying allocation until we run out of attempts
// (or attempts are set to 0, which means infinite)
--i;
} while ( i || !attempts_);
isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
<< " tries");
}
Lease6Ptr AllocEngine::createLease(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const IOAddress& addr) {
Lease6Ptr lease = new Lease6(Lease6::LEASE_IA_NA, addr, iaid,
duid, subnet->getPreferred(),
subnet->getValid(),
subnet->getT1(),
subnet->getT2(),
subnet->getID());
bool status = LeaseMgr::instance().addLease(lease);
if (status) {
return (lease);
} else {
// One of many failures with LeaseMgr (e.g. lost connection to the
// database, database failed etc.). One notable case for that
// is that we are working in multi-process mode and we lost a race
// (some other process got that address first)
return (Lease6Ptr());
}
}
AllocEngine::~AllocEngine() {
if (allocator_) {
delete allocator_;
allocator_ = NULL;
}
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef ALLOC_ENGINE_H
#define ALLOC_ENGINE_H
#include <boost/noncopyable.hpp>
#include <dhcp/duid.h>
#include <dhcp/subnet.h>
#include <asiolink/io_address.h>
#include <dhcp/lease_mgr.h>
#include <iostream>
namespace isc {
namespace dhcp {
/// An exception that is thrown when allocation module fails (e.g. due to
/// lack of available addresses)
class AllocFailed : public isc::Exception {
public:
/// @brief constructor
///
/// @param file name of the file, where exception occurred
/// @param line line of the file, where exception occurred
/// @param what text description of the issue that caused exception
AllocFailed(const char* file, size_t line, const char* what)
: isc::Exception(file, line, what) {}
};
/// @brief DHCPv4 and DHCPv6 allocation engine
///
/// This class represents DHCP allocation engine. It is responsible
/// for picking subnets, choosing and allocating a lease, extending,
/// renewing, releasing and possibly expiring leases.
class AllocEngine : public boost::noncopyable {
protected:
class Allocator {
public:
virtual isc::asiolink::IOAddress
pickAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint) = 0;
protected:
Allocator() {
}
};
class IterativeAllocator : public Allocator {
public:
IterativeAllocator();
virtual isc::asiolink::IOAddress
pickAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
private:
isc::asiolink::IOAddress increaseAddress(isc::asiolink::IOAddress& addr);
};
#if 0
class HashedAllocator {
public:
IterativeAllocator(unsigned int attempts);
virtual isc::asiolink::IOAddress allocateAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const DUIOAddress& hint);
}
class RandomAllocator() {
public:
IterativeAllocator(unsigned int attempts);
virtual isc::asiolink::IOAddress
allocateAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const DUIOAddress& hint);
}
#endif
public:
/// @brief specifies allocation type
typedef enum {
ALLOC_ITERATIVE, // iterative - one address after another
ALLOC_HASHED, // hashed - client's DUID/client-id is hashed
ALLOC_RANDOM // random - an address is randomly selected
} AllocType;
/// @brief Default constructor.
///
/// Instantiates necessary services, required to run DHCPv6 server.
/// In particular, creates IfaceMgr that will be responsible for
/// network interaction. Will instantiate lease manager, and load
/// old or create new DUID.
///
/// @param engine_type selects allocation algorithm
AllocEngine(AllocType engine_type, unsigned int attempts);
Lease6Ptr
allocateAddress6(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const isc::asiolink::IOAddress& hint);
/// @brief Destructor. Used during DHCPv6 service shutdown.
virtual ~AllocEngine();
private:
isc::asiolink::IOAddress
allocateAddress(const Subnet6Ptr& subnet,
const DuidPtr& duid,
const isc::asiolink::IOAddress& hint);
Lease6Ptr createLease(const Subnet6Ptr& subnet,
const DuidPtr& duid,
uint32_t iaid,
const isc::asiolink::IOAddress& addr);
Allocator* allocator_;
unsigned int attempts_;
};
}; // namespace isc::dhcp
}; // namespace isc
#endif // DHCP6_SRV_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment