|
@@ -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));
|
|
|
}
|
|
|
}
|