summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/cfg_hosts.cc
diff options
context:
space:
mode:
authorTomek Mrugalski <tomasz@isc.org>2015-01-20 21:15:25 +0100
committerTomek Mrugalski <tomasz@isc.org>2015-01-20 21:15:25 +0100
commit06246ea31973025b7d7ce44a11c30d8cbf809ab4 (patch)
tree48a4cb49f711ae145b1d0b3f285cc875e34dc703 /src/lib/dhcpsrv/cfg_hosts.cc
parent[3563] HostContainer6 definitions added. (diff)
downloadkea-06246ea31973025b7d7ce44a11c30d8cbf809ab4.tar.xz
kea-06246ea31973025b7d7ce44a11c30d8cbf809ab4.zip
[3563] CfgHosts::get6(subnet_id, addr) implemented, with unit-tests.
Diffstat (limited to 'src/lib/dhcpsrv/cfg_hosts.cc')
-rw-r--r--src/lib/dhcpsrv/cfg_hosts.cc118
1 files changed, 82 insertions, 36 deletions
diff --git a/src/lib/dhcpsrv/cfg_hosts.cc b/src/lib/dhcpsrv/cfg_hosts.cc
index 5d7a7010bd..2b8659324e 100644
--- a/src/lib/dhcpsrv/cfg_hosts.cc
+++ b/src/lib/dhcpsrv/cfg_hosts.cc
@@ -184,17 +184,64 @@ CfgHosts::get6(const IOAddress&, const uint8_t) {
}
ConstHostPtr
-CfgHosts::get6(const SubnetID& subnet_id, const IOAddress& address) const {
- ConstHostCollection hosts = getAll6(address);
- for (ConstHostCollection::const_iterator host = hosts.begin();
- host != hosts.end(); ++host) {
- if ((*host)->getIPv4SubnetID() == subnet_id) {
- return (*host);
- }
+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() << "'");
}
- return (ConstHostPtr());
}
+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,
@@ -253,13 +300,9 @@ CfgHosts::add(const HostPtr& host) {
" 0 when adding new host reservation");
}
- if (host->getIPv4SubnetID() != 0) {
- add4(host);
- }
+ add4(host);
- if (host->getIPv6SubnetID() != 0) {
- add6(host);
- }
+ add6(host);
}
void
@@ -294,7 +337,17 @@ CfgHosts::add4(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)) {
+ isc_throw(DuplicateHost, "failed to add new host using the HW"
+ " address '" << (hwaddr ? hwaddr->toText(false) : "(null)")
+ << " and DUID '" << (duid ? duid->toText() : "(null)")
+ << "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
+ << "' as this host has already been added");
}
+
/// @todo This may need further sanity checks.
// This is a new instance - add it.
@@ -308,37 +361,30 @@ CfgHosts::add6(const HostPtr& host) {
HWAddrPtr hwaddr = host->getHWAddress();
DuidPtr duid = host->getDuid();
- // Check for duplicates for the specified IPv6 subnet.
- if (host->getIPv6SubnetID() &&
- get6(host->getIPv6SubnetID(), duid, hwaddr)) {
- isc_throw(DuplicateHost, "failed to add new host using the HW"
- " address '" << (hwaddr ? hwaddr->toText(false) : "(null)")
- << " and DUID '" << (duid ? duid->toText() : "(null)")
- << "' to the IPv6 subnet id '" << host->getIPv6SubnetID()
- << "' as this host has already been added");
- }
-
- // Now insert it into hosts_, which will be used for finding hosts
- // based on their HW or DUID addresses. It cannot be used for
- // finding IPv6 hosts by their IPv6 addresses, as there may be multiple
- // addresses for a given host. However, insert only if this
- // host doesn't have v4 subnet-id. If it does, it was just added
- // by the previous call to add4().
- if (! host->getIPv4SubnetID()) {
- hosts_.insert(host);
- }
-
// 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) {
-
- /// @todo: We don't handle address-less reservations yet
+ // 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));
}
}