Commit e2a3e5e7 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac3563' (Reservations in DHCPv6)

Conflicts:
	src/lib/dhcpsrv/alloc_engine.cc
parents 519e5673 d5c43ea6
......@@ -1294,24 +1294,21 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
hostname = fqdn->getDomainName();
}
// Attempt to get MAC address using configured mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6.
HWAddrPtr hwaddr = getMAC(query);
// Use allocation engine to pick a lease for this client. Allocation engine
// will try to honour the hint, but it is just a hint - some other address
// may be used instead. If fake_allocation is set to false, the lease will
// be inserted into the LeaseMgr as well.
Lease6Collection old_leases;
Lease6Collection leases = alloc_engine_->allocateLeases6(subnet, duid,
ia->getIAID(),
hint, Lease::TYPE_NA,
do_fwd, do_rev,
hostname,
fake_allocation,
callout_handle,
old_leases,
hwaddr);
AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(),
hint, Lease::TYPE_NA, do_fwd, do_rev,
hostname, fake_allocation);
ctx.callout_handle_ = callout_handle;
// Attempt to get MAC address using configured mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6.
ctx.hwaddr_ = getMAC(query);
Lease6Collection leases = alloc_engine_->allocateLeases6(ctx);
/// @todo: Handle more than one lease
Lease6Ptr lease;
if (!leases.empty()) {
......@@ -1347,8 +1344,8 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
// code is considered a success.
Lease6Ptr old_lease;
if (!old_leases.empty()) {
old_lease = *old_leases.begin();
if (!ctx.old_leases_.empty()) {
old_lease = *ctx.old_leases_.begin();
}
// Allocation engine may have returned an existing lease. If so, we
// have to check that the FQDN settings we provided are the same
......@@ -1414,10 +1411,6 @@ Dhcpv6Srv::assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
hint = hint_opt->getAddress();
}
// Attempt to get MAC address using any of available mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6
HWAddrPtr hwaddr = getMAC(query);
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_REQUEST)
.arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID())
.arg(hint_opt ? hint.toText() : "(no hint)");
......@@ -1437,14 +1430,15 @@ Dhcpv6Srv::assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid,
// may be used instead. If fake_allocation is set to false, the lease will
// be inserted into the LeaseMgr as well.
Lease6Collection old_leases;
Lease6Collection leases = alloc_engine_->allocateLeases6(subnet, duid,
ia->getIAID(),
hint, Lease::TYPE_PD,
false, false,
string(),
fake_allocation,
callout_handle,
old_leases, hwaddr);
AllocEngine::ClientContext6 ctx(subnet, duid, ia->getIAID(), hint, Lease::TYPE_PD,
false, false, string(), fake_allocation);
ctx.callout_handle_ = callout_handle;
// Attempt to get MAC address using any of available mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6
ctx.hwaddr_ = getMAC(query);
Lease6Collection leases = alloc_engine_->allocateLeases6(ctx);
if (!leases.empty()) {
......
This diff is collapsed.
This diff is collapsed.
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -49,6 +49,20 @@ CfgHosts::getAll4(const IOAddress& address) {
return (collection);
}
ConstHostCollection
CfgHosts::getAll6(const IOAddress& address) const {
ConstHostCollection collection;
getAllInternal6<ConstHostCollection>(address, collection);
return (collection);
}
HostCollection
CfgHosts::getAll6(const IOAddress& address) {
HostCollection collection;
getAllInternal6<HostCollection>(address, collection);
return (collection);
}
template<typename Storage>
void
CfgHosts::getAllInternal(const std::vector<uint8_t>& identifier,
......@@ -98,6 +112,24 @@ CfgHosts::getAllInternal4(const IOAddress& address, Storage& storage) const {
}
}
template<typename Storage>
void
CfgHosts::getAllInternal6(const IOAddress& address, Storage& storage) const {
// Must not specify address other than IPv6.
if (!address.isV6()) {
isc_throw(BadHostAddress, "must specify an IPv6 address when searching"
" for a host, specified address was " << address);
}
// Search for the Host using the reserved IPv6 address as a key.
const HostContainerIndex1& idx = hosts_.get<1>();
HostContainerIndex1Range r = idx.equal_range(address);
// Append each Host object to the storage.
for (HostContainerIndex1::iterator host = r.first; host != r.second;
++host) {
storage.push_back(*host);
}
}
ConstHostPtr
CfgHosts::get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
......@@ -151,6 +183,66 @@ CfgHosts::get6(const IOAddress&, const uint8_t) {
isc_throw(isc::NotImplemented, "get6(prefix, len) is not implemented");
}
ConstHostPtr
CfgHosts::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostCollection storage;
getAllInternal6(subnet_id, address, storage);
switch (storage.size()) {
case 0:
return (ConstHostPtr());
case 1:
return (*storage.begin());
default:
isc_throw(DuplicateHost, "more than one reservation found"
" for the host belonging to the subnet with id '"
<< subnet_id << "' and using the address '"
<< address.toText() << "'");
}
}
template<typename Storage>
void
CfgHosts::getAllInternal6(const SubnetID& subnet_id,
const asiolink::IOAddress& address,
Storage& storage) const {
// Must not specify address other than IPv6.
if (!address.isV6()) {
isc_throw(BadHostAddress, "must specify an IPv6 address when searching"
" for a host, specified address was " << address);
}
// Let's get all reservations that match subnet_id, address.
const HostContainer6Index1& idx = hosts6_.get<1>();
HostContainer6Index1Range r = idx.equal_range(boost::make_tuple(subnet_id, address));
// For each IPv6 reservation, add the host to the results list. Fortunately,
// in all sane cases, there will be only one such host. (Each host can have
// multiple addresses reserved, but for each (address, subnet_id) there should
// be at most one host reserving it).
for(HostContainer6Index1::iterator resrv = r.first; resrv != r.second; ++resrv) {
storage.push_back(resrv->host_);
}
}
HostPtr
CfgHosts::get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) {
HostCollection storage;
getAllInternal6<HostCollection>(subnet_id, address, storage);
switch (storage.size()) {
case 0:
return (HostPtr());
case 1:
return (*storage.begin());
default:
isc_throw(DuplicateHost, "more than one reservation found"
" for the host belonging to the subnet with id '"
<< subnet_id << "' and using the address '"
<< address.toText() << "'");
}
}
HostPtr
CfgHosts::getHostInternal(const SubnetID& subnet_id, const bool subnet6,
const HWAddrPtr& hwaddr, const DuidPtr& duid) const {
......@@ -207,6 +299,15 @@ CfgHosts::add(const HostPtr& host) {
isc_throw(BadValue, "must not use both IPv4 and IPv6 subnet ids of"
" 0 when adding new host reservation");
}
add4(host);
add6(host);
}
void
CfgHosts::add4(const HostPtr& host) {
/// @todo This may need further sanity checks.
HWAddrPtr hwaddr = host->getHWAddress();
DuidPtr duid = host->getDuid();
......@@ -236,6 +337,7 @@ CfgHosts::add(const HostPtr& host) {
<< "' to the IPv4 subnet id '" << host->getIPv4SubnetID()
<< "' as this host has already been added");
// Check for duplicates for the specified IPv6 subnet.
} else if (host->getIPv6SubnetID() &&
get6(host->getIPv6SubnetID(), duid, hwaddr)) {
......@@ -252,5 +354,40 @@ CfgHosts::add(const HostPtr& host) {
hosts_.insert(host);
}
void
CfgHosts::add6(const HostPtr& host) {
/// @todo This may need further sanity checks.
HWAddrPtr hwaddr = host->getHWAddress();
DuidPtr duid = host->getDuid();
// Get all reservations for this host.
IPv6ResrvRange reservations = host->getIPv6Reservations();
// Check if there are any IPv6 reservations.
if (std::distance(reservations.first, reservations.second) == 0) {
// If there aren't, we don't need to add this to hosts6_, which is used
// for getting hosts by their IPv6 address reservations.
return;
}
// Now for each reservation, insert corresponding (address, host) tuple.
for (IPv6ResrvIterator it = reservations.first; it != reservations.second;
++it) {
// If there's an entry for this (subnet-id, address), reject it.
if (get6(host->getIPv6SubnetID(), it->second.getPrefix())) {
isc_throw(DuplicateHost, "failed to add address reservation for "
<< "host using the HW address '"
<< (hwaddr ? hwaddr->toText(false) : "(null)")
<< " and DUID '" << (duid ? duid->toText() : "(null)")
<< "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
<< "' for address/prefix " << it->second.getPrefix()
<< ": There's already reservation for this address/prefix");
}
hosts6_.insert(HostResrv6Tuple(it->second, host));
}
}
} // end of namespace isc::dhcp
} // end of namespace isc
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -95,6 +95,28 @@ public:
virtual HostCollection
getAll4(const asiolink::IOAddress& address);
/// @brief Returns a collection of hosts using the specified IPv6 address.
///
/// This method may return multiple @c Host objects if they are connected
/// to different subnets.
///
/// @param address IPv6 address for which the @c Host object is searched.
///
/// @return Collection of const @c Host objects.
virtual ConstHostCollection
getAll6(const asiolink::IOAddress& address) const;
/// @brief Returns a collection of hosts using the specified IPv6 address.
///
/// This method may return multiple @c Host objects if they are connected
/// to different subnets.
///
/// @param address IPv6 address for which the @c Host object is searched.
///
/// @return Collection of const @c Host objects.
virtual HostCollection
getAll6(const asiolink::IOAddress& address);
/// @brief Returns a host connected to the IPv4 subnet and matching
/// specified identifiers.
///
......@@ -183,6 +205,25 @@ public:
virtual HostPtr
get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len);
/// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address.
///
/// @return Const @c Host object using a specified IPv6 address.
virtual ConstHostPtr
get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
/// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address.
///
/// @return Const @c Host object using a specified IPv6 address.
virtual HostPtr
get6(const SubnetID& subnet_id, const asiolink::IOAddress& address);
/// @brief Adds a new host to the collection.
///
......@@ -241,6 +282,40 @@ private:
void getAllInternal4(const asiolink::IOAddress& address,
Storage& storage) const;
/// @brief Returns @c Host objects for the specified IPv6 address.
///
/// This private method is called by the @c CfgHosts::getAll6 methods
/// to retrieve the @c Host for which the specified IPv6 address is
/// reserved. The retrieved objects are appended to the @c storage
/// container.
///
/// @param address IPv6 address.
/// @param [out] storage Container to which the retrieved objects are
/// appended.
/// @tparam One of the @c ConstHostCollection or @c HostCollection.
template<typename Storage>
void getAllInternal6(const asiolink::IOAddress& address,
Storage& storage) const;
/// @brief Returns @c Host objects for the specified (Subnet-id,IPv6 address) tuple.
///
/// This private method is called by the @c CfgHosts::getAll6 methods
/// to retrieve the @c Host for which the specified IPv6 address is
/// reserved and is in specified subnet-id. The retrieved objects are
/// appended to the @c storage container.
///
/// @param subnet_id Subnet Identifier.
/// @param address IPv6 address.
/// @param [out] storage Container to which the retrieved objects are
/// appended.
/// @tparam One of the @c ConstHostCollection or @c HostCollection.
template<typename Storage>
void
getAllInternal6(const SubnetID& subnet_id,
const asiolink::IOAddress& address,
Storage& storage) const;
/// @brief Returns @c Host object connected to a subnet.
///
/// This private method returns a pointer to the @c Host object identified
......@@ -260,9 +335,41 @@ private:
const HWAddrPtr& hwaddr,
const DuidPtr& duid) const;
/// @brief Adds a new host to the v4 collection.
///
/// This is an internal method called by public @ref add.
///
/// @param host Pointer to the new @c Host object being added.
///
/// @throw DuplicateHost If a host for a particular HW address or DUID
/// has already been added to the IPv4 subnet.
virtual void add4(const HostPtr& host);
/// @brief Adds a new host to the v6 collection.
///
/// This is an internal method called by public @ref add.
///
/// @param host Pointer to the new @c Host object being added.
///
/// @throw DuplicateHost If a host for a particular HW address or DUID
/// or for the particular address or prefix has already been added to
/// the IPv6 subnet.
virtual void add6(const HostPtr& host);
/// @brief Multi-index container holding @c Host objects.
///
/// It can be used for finding hosts by the following criteria:
/// - IPv4 address
/// - DUID
/// - HW/MAC address
HostContainer hosts_;
/// @brief Multi-index container holding @c Host objects with v6 reservations.
///
/// It can be used for finding hosts by the following criteria:
/// - IPv6 address
/// - IPv6 prefix
HostContainer6 hosts6_;
};
/// @name Pointers to the @c CfgHosts objects.
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -194,6 +194,12 @@ Host::getIPv6Reservations(const IPv6Resrv::Type& type) const {
return (ipv6_reservations_.equal_range(type));
}
IPv6ResrvRange
Host::getIPv6Reservations() const {
return (IPv6ResrvRange(ipv6_reservations_.begin(),
ipv6_reservations_.end()));
}
bool
Host::hasIPv6Reservation() const {
return (!ipv6_reservations_.empty());
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -352,6 +352,12 @@ public:
/// the specified type.
IPv6ResrvRange getIPv6Reservations(const IPv6Resrv::Type& type) const;
/// @brief Returns all IPv6 reservations.
///
/// @return A range of iterators pointing to the reservations of
/// the specified type.
IPv6ResrvRange getIPv6Reservations() const;
/// @brief Checks if there is at least one IPv6 reservation for this host.
///
/// @return true if there is a reservation for the host, false otherwise.
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -16,10 +16,13 @@
#define HOST_CONTAINER_H
#include <dhcpsrv/host.h>
#include <dhcpsrv/subnet_id.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
namespace isc {
namespace dhcp {
......@@ -96,7 +99,107 @@ typedef HostContainer::nth_index<1>::type HostContainerIndex1;
typedef std::pair<HostContainerIndex1::iterator,
HostContainerIndex1::iterator> HostContainerIndex1Range;
}
}
/// @brief Defines one entry for the Host Container for v6 hosts
///
/// It's essentially a pair of (IPv6 reservation, Host pointer).
/// This structure is used as an intermediate structure in HostContainer6.
/// For a single host that has reservations for X addresses or prefixes, there
/// will be X HostResrv6Tuple structures.
struct HostResrv6Tuple {
/// @brief Default constructor.
///
/// @param resrv IPv6 address/prefix reservation
/// @param host pointer to the host object
HostResrv6Tuple(const IPv6Resrv& resrv, const HostPtr& host)
:resrv_(resrv), host_(host), subnet_id_(host ? host->getIPv6SubnetID() : 0) {
}
/// @brief Address or prefix reservation.
const IPv6Resrv resrv_;
/// @brief Pointer to the host object.
HostPtr host_;
/// @brief Value of the IPv6 Subnet-id
const SubnetID subnet_id_;
/// @brief Key extractor (used in the second composite key)
const asiolink::IOAddress& getKey() const {
return (resrv_.getPrefix());
}
};
/// @brief Multi-index container holding IPv6 reservations.
///
/// This container holds HostResrv6Tuples, i.e. pairs of (IPv6Resrv, HostPtr)
/// pieces of information. This is needed for efficiently finding a host
/// for a given IPv6 address or prefix.
typedef boost::multi_index_container<
// This containers stores (IPv6Resrv, HostPtr) tuples
HostResrv6Tuple,
// Start specification of indexes here.
boost::multi_index::indexed_by<
// First index is used to search by an address.
boost::multi_index::ordered_non_unique<
// Address is extracted by calling IPv6Resrv::getPrefix()
// and it will return an IOAddress object.
boost::multi_index::const_mem_fun<
HostResrv6Tuple, const asiolink::IOAddress&, &HostResrv6Tuple::getKey>
>,
// Second index is used to search by (subnet_id, address) pair.
// This is
boost::multi_index::ordered_unique<
/// This is a composite key. It uses two keys: subnet-id and
/// IPv6 address reservation.
boost::multi_index::composite_key<
// Composite key uses members of the HostResrv6Tuple class.
HostResrv6Tuple,
// First key extractor. Gets subnet-id as a member of the
// HostResrv6Tuple structure.
boost::multi_index::member<HostResrv6Tuple, const SubnetID,
&HostResrv6Tuple::subnet_id_>,
// Second key extractor. Address is extracted by calling
// IPv6Resrv::getPrefix() and it will return an IOAddress object.
boost::multi_index::const_mem_fun<
HostResrv6Tuple, const asiolink::IOAddress&,
&HostResrv6Tuple::getKey
>
>
>
>
> HostContainer6;
/// @brief First index type in the @c HostContainer6.
///
/// This index allows for searching for @c Host objects using an
/// address.
typedef HostContainer6::nth_index<0>::type HostContainer6Index0;
/// @brief Results range returned using the @c HostContainer6Index0.
typedef std::pair<HostContainer6Index0::iterator,
HostContainer6Index0::iterator> HostContainer6Index0Range;
/// @brief Second index type in the @c HostContainer6.
///
/// This index allows for searching for @c Host objects using a
/// reserved (SubnetID, IPv6 address) tuple.
typedef HostContainer6::nth_index<1>::type HostContainer6Index1;
/// @brief Results range returned using the @c HostContainer6Index1.
typedef std::pair<HostContainer6Index1::iterator,
HostContainer6Index1::iterator> HostContainer6Index1Range;
}; // end of isc::dhcp namespace
}; // end of isc namespace
#endif // HOST_CONTAINER_H
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -118,6 +118,17 @@ HostMgr::get6(const IOAddress& prefix, const uint8_t prefix_len) const {
return (host);
}
ConstHostPtr
HostMgr::get6(const SubnetID& subnet_id,
const asiolink::IOAddress& addr) const {
ConstHostPtr host = getCfgHosts()->get6(subnet_id, addr);
if (!host && alternate_source) {
host = alternate_source->get6(subnet_id, addr);
}
return (host);
}
void
HostMgr::add(const HostPtr&) {
isc_throw(isc::NotImplemented, "HostMgr::add is not implemented");
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2015 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
......@@ -181,6 +181,15 @@ public:
virtual ConstHostPtr
get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
/// @brief Returns a host from specific subnet and reserved address.
///
/// @param subnet_id subnet identfier.
/// @param addr specified address.
///
/// @return Const @c host object that has a reservation for specified address.
virtual ConstHostPtr
get6(const SubnetID& subnet_id, const asiolink::IOAddress& addr) const;
/// @brief Adds a new host to the alternate data source.
///
/// This method will throw an exception if no alternate data source is
......
......@@ -66,6 +66,27 @@ public: