diff options
author | Tomek Mrugalski <tomasz@isc.org> | 2015-01-20 21:15:25 +0100 |
---|---|---|
committer | Tomek Mrugalski <tomasz@isc.org> | 2015-01-20 21:15:25 +0100 |
commit | 06246ea31973025b7d7ce44a11c30d8cbf809ab4 (patch) | |
tree | 48a4cb49f711ae145b1d0b3f285cc875e34dc703 /src/lib/dhcpsrv/cfg_hosts.cc | |
parent | [3563] HostContainer6 definitions added. (diff) | |
download | kea-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.cc | 118 |
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)); } } |