Skip to content

Commit 2a7070c

Browse files
committed
[#1415] Support for PD in free lease container
1 parent cba758e commit 2a7070c

File tree

5 files changed

+603
-165
lines changed

5 files changed

+603
-165
lines changed

src/lib/dhcpsrv/address_range.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
66

77
#include <config.h>
8+
#include <asiolink/addr_utilities.h>
89
#include <asiolink/io_address.h>
910
#include <dhcpsrv/address_range.h>
1011
#include <exceptions/exceptions.h>
@@ -27,5 +28,42 @@ AddressRange::AddressRange(const IOAddress& start, const IOAddress& end)
2728
}
2829
}
2930

31+
PrefixRange::PrefixRange(const asiolink::IOAddress& prefix, const uint8_t length, const uint8_t delegated)
32+
: start_(prefix), end_(IOAddress::IPV6_ZERO_ADDRESS()), delegated_length_(delegated) {
33+
if (!start_.isV6()) {
34+
isc_throw(BadValue, "IPv6 prefix required for prefix delegation range but "
35+
<< start_ << " was specified");
36+
}
37+
if (delegated_length_ < length) {
38+
isc_throw(BadValue, "delegated length " << static_cast<int>(delegated_length_)
39+
<< " must not be lower than prefix length " << static_cast<int>(length));
40+
}
41+
if ((length > 128) || (delegated_length_ > 128)) {
42+
isc_throw(BadValue, "delegated length " << static_cast<int>(delegated_length_)
43+
<< " and prefix length " << static_cast<int>(length)
44+
<< " must not be greater than 128");
45+
}
46+
auto prefixes_num = prefixesInRange(length, delegated_length_);
47+
uint64_t addrs_in_prefix = static_cast<uint64_t>(1) << (128 - delegated_length_);
48+
end_ = offsetAddress(prefix, (prefixes_num - 1) * addrs_in_prefix);
49+
}
50+
51+
PrefixRange::PrefixRange(const asiolink::IOAddress& start, const asiolink::IOAddress& end,
52+
const uint8_t delegated)
53+
: start_(start), end_(end), delegated_length_(delegated) {
54+
if (!start_.isV6() || !end_.isV6()) {
55+
isc_throw(BadValue, "IPv6 prefix required for prefix delegation range but "
56+
<< start_ << ":" << end_ << " was specified");
57+
}
58+
// The start must be lower or equal the end.
59+
if (end_ < start_) {
60+
isc_throw(BadValue, "invalid address range boundaries " << start_ << ":" << end_);
61+
}
62+
if (delegated_length_ > 128) {
63+
isc_throw(BadValue, "delegated length " << static_cast<int>(delegated_length_)
64+
<< " must not be greater than 128");
65+
}
66+
}
67+
3068
} // end of namespace isc::dhcp
3169
} // end of namespace isc

src/lib/dhcpsrv/free_lease_queue.cc

Lines changed: 133 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
66

77
#include <config.h>
8+
#include <asiolink/addr_utilities.h>
89
#include <dhcpsrv/free_lease_queue.h>
9-
#include <exceptions/exceptions.h>
1010

1111
#include <boost/make_shared.hpp>
1212

1313
#include <iostream>
14-
#include <iterator>
1514
#include <tuple>
1615
#include <utility>
1716

@@ -29,48 +28,9 @@ FreeLeaseQueue::addRange(const Range& range) {
2928
// If the container with ranges is empty, there are is no need for
3029
// doing any checks. Let's just add the new range.
3130
if (!containers_.empty()) {
32-
// Get the next range in the container relative to the start of the new
33-
// range. The upper_bound returns the range which starts after the start
34-
// of the new range.
35-
auto next_range = containers_.lower_bound(range.start_);
36-
// Get the range the range that is before that one. It is also possible that
37-
// there is no previous range in which case we default to end().
38-
auto previous_range = containers_.end();
39-
// If the next range is at the beginning of the container there is no
40-
// previous range.
41-
if (next_range != containers_.begin()) {
42-
// This should work fine even if the next range is set to end(). We
43-
// will get the range that is one position before end() and that
44-
// should be the range that goes before the new one.
45-
auto it = next_range;
46-
--it;
47-
previous_range = it;
48-
}
49-
50-
// Now that we have next and previous ranges set we should check that the
51-
// new range we're adding does not overlap with them.
52-
53-
// If the previous range exists, let's check that the start of the new
54-
// range is neither within that range nor lower. Assuming that the ranges
55-
// are constructed such that the end must be greater or equal the start
56-
// it is sufficient to check that the start of the new range is not lower
57-
// or equal the end of the previous range.
58-
if ((previous_range != containers_.end()) &&
59-
(range.start_ <= previous_range->range_end_)) {
60-
isc_throw(BadValue, "new address range " << range.start_ << ":" << range.end_
61-
<< " overlaps with the existing range");
62-
}
63-
64-
// If the next range exists, let's check that the end of the new range
65-
// is neither within that range nor higher.
66-
if ((next_range != containers_.end()) &&
67-
(next_range->range_start_ <= range.end_)) {
68-
isc_throw(BadValue, "new address range " << range.start_ << ":" << range.end_
69-
<< " overlaps with the existing range");
70-
}
71-
}
72-
73-
containers_.insert(ContainerDescriptor{range.start_, range.end_,
31+
checkRangeOverlaps(range.start_, range.end_);
32+
}
33+
containers_.insert(ContainerDescriptor{range.start_, range.end_, 128,
7434
boost::make_shared<Container>()});
7535
}
7636

@@ -79,9 +39,20 @@ FreeLeaseQueue::addRange(const IOAddress& start, const IOAddress& end) {
7939
addRange(FreeLeaseQueue::Range(start, end));
8040
}
8141

82-
bool
83-
FreeLeaseQueue::removeRange(const Range& range) {
84-
return (containers_.get<1>().erase(range.start_) > 0);
42+
void
43+
FreeLeaseQueue::addRange(const PrefixRange& range) {
44+
if (!containers_.empty()) {
45+
auto last_addr = offsetAddress(range.end_, range.delegated_length_ - 1);
46+
checkRangeOverlaps(range.start_, last_addr);
47+
}
48+
containers_.insert(ContainerDescriptor{range.start_, range.end_, range.delegated_length_,
49+
boost::make_shared<Container>()});
50+
}
51+
52+
void
53+
FreeLeaseQueue::addRange(const asiolink::IOAddress& prefix, const uint8_t prefix_length,
54+
const uint8_t delegated_length) {
55+
addRange(FreeLeaseQueue::PrefixRange(prefix, prefix_length, delegated_length));
8556
}
8657

8758
bool
@@ -112,33 +83,63 @@ FreeLeaseQueue::append(const IOAddress& address) {
11283
return (true);
11384
}
11485

86+
bool
87+
FreeLeaseQueue::append(const IOAddress& prefix, const uint8_t delegated_length) {
88+
// If there are no ranges defined, there is nothing to do.
89+
if (containers_.empty()) {
90+
return (false);
91+
}
92+
// Find the beginning of the range which has the start address
93+
// greater than the address we're appending.
94+
auto lb = containers_.upper_bound(prefix);
95+
// If the range we found is the first one in the container
96+
// there is no range matching our prefix because all existing
97+
// ranges include higher addresses.
98+
if (lb == containers_.begin()) {
99+
return (false);
100+
}
101+
--lb;
102+
// Go one range back and see if our prefix is within its boundaries.
103+
if ((lb->range_end_ < prefix) || (prefix < lb->range_start_) ||
104+
(delegated_length != lb->delegated_length_)) {
105+
return (false);
106+
}
107+
// Use the range we found and append the prefix to it.
108+
FreeLeaseQueue::PrefixRange range(lb->range_start_, lb->range_end_, lb->delegated_length_);
109+
append(range, prefix);
110+
111+
// Everything is fine.
112+
return (true);
113+
}
114+
115115
void
116116
FreeLeaseQueue::append(const FreeLeaseQueue::Range& range, const IOAddress& address) {
117117
// Make sure the address is within the range boundaries.
118-
if ((address < range.start_) || (range.end_ < address)) {
119-
isc_throw(BadValue, "address " << address << " is not within the range of "
120-
<< range.start_ << ":" << range.end_);
121-
}
118+
checkRangeBoundaries(range, address);
122119
auto cont = getContainer(range);
123120
cont->insert(address);
124121
}
125122

126123
void
127-
FreeLeaseQueue::append(const uint64_t range_index, const IOAddress& address) {
124+
FreeLeaseQueue::append(const uint64_t range_index, const IOAddress& ip) {
128125
auto desc = getContainerDescriptor(range_index);
129-
if ((address < desc.range_start_) || (desc.range_end_ < address)) {
130-
isc_throw(BadValue, "address " << address << " is not within the range of "
131-
<< desc.range_start_ << ":" << desc.range_end_);
126+
if ((ip < desc.range_start_) || (desc.range_end_ < ip)) {
127+
isc_throw(BadValue, ip << " is not within the range of " << desc.range_start_
128+
<< ":" << desc.range_end_);
132129
}
133-
desc.container_->insert(address);
130+
desc.container_->insert(ip);
131+
}
132+
133+
void
134+
FreeLeaseQueue::append(const FreeLeaseQueue::PrefixRange& range, const asiolink::IOAddress& prefix) {
135+
checkRangeBoundaries(range, prefix, true);
136+
auto cont = getContainer(range);
137+
cont->insert(prefix);
134138
}
135139

136140
bool
137141
FreeLeaseQueue::use(const FreeLeaseQueue::Range& range, const IOAddress& address) {
138-
if ((address < range.start_) || (range.end_ < address)) {
139-
isc_throw(BadValue, "address " << address << " is outside of the range of "
140-
<< range.start_ << ":" << range.end_);
141-
}
142+
checkRangeBoundaries(range, address);
142143
auto cont = getContainer(range);
143144
auto found = cont->find(address);
144145
if (found != cont->end()) {
@@ -148,28 +149,74 @@ FreeLeaseQueue::use(const FreeLeaseQueue::Range& range, const IOAddress& address
148149
return (false);
149150
}
150151

151-
IOAddress
152-
FreeLeaseQueue::next(const FreeLeaseQueue::Range& range) {
153-
return (popNextInternal(range, true));
152+
bool
153+
FreeLeaseQueue::use(const FreeLeaseQueue::PrefixRange& range, const IOAddress& prefix) {
154+
checkRangeBoundaries(range, prefix, true);
155+
auto cont = getContainer(range);
156+
auto found = cont->find(prefix);
157+
if (found != cont->end()) {
158+
static_cast<void>(cont->erase(found));
159+
return (true);
160+
}
161+
return (false);
154162
}
155163

156-
IOAddress
157-
FreeLeaseQueue::pop(const FreeLeaseQueue::Range& range) {
158-
return (popNextInternal(range, false));
164+
template<typename RangeType>
165+
void
166+
FreeLeaseQueue::checkRangeBoundaries(const RangeType& range, const IOAddress& ip,
167+
const bool prefix) const {
168+
if ((ip < range.start_) || (range.end_ < ip)) {
169+
isc_throw(BadValue, (prefix ? "prefix " : "address ") << ip << " is not within the range of "
170+
<< range.start_ << ":" << range.end_);
171+
}
159172
}
160173

161-
uint64_t
162-
FreeLeaseQueue::getRangeIndex(const FreeLeaseQueue::Range& range) const {
163-
auto cont = containers_.get<1>().find(range.start_);
164-
if (cont == containers_.get<1>().end()) {
165-
isc_throw(BadValue, "conatiner for the specified address range " << range.start_
166-
<< ":" << range.end_ << " does not exist");
174+
void
175+
FreeLeaseQueue::checkRangeOverlaps(const IOAddress& start, const IOAddress& end) const {
176+
// Get the next range in the container relative to the start of the new
177+
// range. The upper_bound returns the range which starts after the start
178+
// of the new range.
179+
auto next_range = containers_.lower_bound(start);
180+
// Get the range the range that is before that one. It is also possible that
181+
// there is no previous range in which case we default to end().
182+
auto previous_range = containers_.end();
183+
// If the next range is at the beginning of the container there is no
184+
// previous range.
185+
if (next_range != containers_.begin()) {
186+
// This should work fine even if the next range is set to end(). We
187+
// will get the range that is one position before end() and that
188+
// should be the range that goes before the new one.
189+
auto it = next_range;
190+
--it;
191+
previous_range = it;
192+
}
193+
194+
// Now that we have next and previous ranges set we should check that the
195+
// new range we're adding does not overlap with them.
196+
197+
// If the previous range exists, let's check that the start of the new
198+
// range is neither within that range nor lower. Assuming that the ranges
199+
// are constructed such that the end must be greater or equal the start
200+
// it is sufficient to check that the start of the new range is not lower
201+
// or equal the end of the previous range.
202+
if ((previous_range != containers_.end()) &&
203+
(start <= previous_range->range_end_)) {
204+
isc_throw(BadValue, "new address range " << start << ":" << end
205+
<< " overlaps with the existing range");
206+
}
207+
208+
// If the next range exists, let's check that the end of the new range
209+
// is neither within that range nor higher.
210+
if ((next_range != containers_.end()) &&
211+
(next_range->range_start_ <= end)) {
212+
isc_throw(BadValue, "new address range " << start << ":" << end
213+
<< " overlaps with the existing range");
167214
}
168-
return (std::distance(containers_.get<2>().begin(), containers_.project<2>(cont)));
169215
}
170216

217+
171218
FreeLeaseQueue::ContainerPtr
172-
FreeLeaseQueue::getContainer(const FreeLeaseQueue::Range& range) {
219+
FreeLeaseQueue::getContainer(const FreeLeaseQueue::Range& range) const {
173220
auto cont = containers_.find(range.start_);
174221
if (cont == containers_.end()) {
175222
isc_throw(BadValue, "conatiner for the specified address range " << range.start_
@@ -178,8 +225,19 @@ FreeLeaseQueue::getContainer(const FreeLeaseQueue::Range& range) {
178225
return (cont->container_);
179226
}
180227

228+
FreeLeaseQueue::ContainerPtr
229+
FreeLeaseQueue::getContainer(const FreeLeaseQueue::PrefixRange& range) const {
230+
auto cont = containers_.find(range.start_);
231+
if (cont == containers_.end()) {
232+
isc_throw(BadValue, "conatiner for the specified prefix " << range.start_
233+
<< " and delegated length of " << static_cast<int>(range.delegated_length_)
234+
<< " does not exist");
235+
}
236+
return (cont->container_);
237+
}
238+
181239
FreeLeaseQueue::ContainerDescriptor
182-
FreeLeaseQueue::getContainerDescriptor(const uint64_t range_index) {
240+
FreeLeaseQueue::getContainerDescriptor(const uint64_t range_index) const {
183241
if (containers_.get<2>().size() <= range_index) {
184242
isc_throw(BadValue, "conatiner for the specified range index " << range_index
185243
<< " does not exist");
@@ -188,21 +246,5 @@ FreeLeaseQueue::getContainerDescriptor(const uint64_t range_index) {
188246
return (cont);
189247
}
190248

191-
IOAddress
192-
FreeLeaseQueue::popNextInternal(const Range& range, const bool push) {
193-
auto cont = getContainer(range);
194-
if (cont->empty()) {
195-
return (IOAddress::IPV4_ZERO_ADDRESS());
196-
}
197-
auto& idx = cont->get<1>();
198-
auto next = idx.front();
199-
idx.pop_front();
200-
if (push) {
201-
idx.push_back(next);
202-
}
203-
return (next);
204-
205-
}
206-
207249
} // end of namespace isc::dhcp
208250
} // end of namespace isc

0 commit comments

Comments
 (0)