mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-22 01:49:48 +00:00
Compare commits
24 Commits
088471ad59
...
23ff3a5adf
Author | SHA1 | Date | |
---|---|---|---|
|
23ff3a5adf | ||
|
33d8a82aac | ||
|
a15632a6b6 | ||
|
f5ef1ab3ac | ||
|
6754a4b86a | ||
|
1b6681bb39 | ||
|
b0b3b78d4a | ||
|
378de7eeaa | ||
|
ce880380be | ||
|
3bfffe7205 | ||
|
3776e08a16 | ||
|
45799e22bf | ||
|
069c6ec34e | ||
|
beec9ae4e6 | ||
|
02ede08a7f | ||
|
233e393735 | ||
|
eea3d8af2e | ||
|
cbdf2b5728 | ||
|
284c7f5855 | ||
|
f98c30e4a8 | ||
|
b55feb15a8 | ||
|
7f34f80f9e | ||
|
812ce8789f | ||
|
26255f80ee |
@ -5,8 +5,6 @@ about: Create a new issue using this checklist for each release.
|
||||
|
||||
# Kea Release Checklist
|
||||
|
||||
This is thoroughly documented in [the Kea Release Process guide](https://wiki.isc.org/bin/view/QA/KeaReleaseProcess).
|
||||
|
||||
#### Legend
|
||||
|
||||
- `A.B.C`: the version being released
|
||||
@ -212,7 +210,7 @@ Now it's time to publish the code.
|
||||
|
||||
## Support
|
||||
|
||||
1. [ ] Update tickets if any support customers are waiting for the release.
|
||||
1. [ ] Update tickets if any support customers are waiting for the release. [:link:](https://wiki.isc.org/bin/view/Main/KeaReleaseSupportUpdateTix)
|
||||
|
||||
## QA
|
||||
|
||||
|
7
changelog_unreleased/226-adaptive-lease-time-threshold
Normal file
7
changelog_unreleased/226-adaptive-lease-time-threshold
Normal file
@ -0,0 +1,7 @@
|
||||
[func] fdupont
|
||||
Added the new "adaptive-lease-time-threshold" parameter
|
||||
for the FLQ (Free Lease Queue) allocator which reduces
|
||||
the lifetime of leases when pools of a subnet have an
|
||||
occupancy rate above a configured threshold (new feature
|
||||
from ISC DHCP).
|
||||
(Gitlab #226)
|
@ -989,6 +989,9 @@
|
||||
// lease is returned as it was "cached".
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled).
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// Specify whether the server should look up global reservations.
|
||||
"reservations-global": false,
|
||||
|
||||
@ -1277,6 +1280,9 @@
|
||||
// Subnet-level cache maximum.
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled).
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// List of static IPv4 reservations assigned to clients belonging
|
||||
// to this subnet. For a detailed example, see reservations.json.
|
||||
"reservations": [
|
||||
@ -1419,6 +1425,9 @@
|
||||
// Global cache maximum.
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled).
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// String of zero or more characters with which to replace each
|
||||
// invalid character in the hostname or Client FQDN. The default
|
||||
// value is an empty string, which will cause invalid characters
|
||||
|
@ -939,6 +939,9 @@
|
||||
// lease is returned as it was "cached".
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled).
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// Specify whether the server should look up global reservations.
|
||||
"reservations-global": false,
|
||||
|
||||
@ -1270,6 +1273,9 @@
|
||||
// Subnet-level cache maximum.
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled).
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// List of static IPv6 reservations assigned to clients belonging
|
||||
// to this subnet. For a detailed example, see reservations.json.
|
||||
"reservations": [
|
||||
@ -1408,6 +1414,9 @@
|
||||
// Global cache maximum.
|
||||
"cache-max-age": 1000,
|
||||
|
||||
// Adaptive lease time threshold (1.0 is disabled)
|
||||
"adaptive-lease-time-threshold": 0.8,
|
||||
|
||||
// String of zero or more characters with which to replace each
|
||||
// invalid character in the Client FQDN. The default
|
||||
// value is an empty string, which will cause invalid characters
|
||||
|
@ -8985,3 +8985,20 @@ avoiding unnecessary impact on the server's startup time.
|
||||
As a result, the servers will not be able to offer some of the available
|
||||
leases to the clients. Only a server reclaiming a particular lease will
|
||||
be able to offer it.
|
||||
|
||||
In Kea 3.1.1 a new parameter ``adaptive-lease-time-threshold`` was added.
|
||||
It can be specified at global, shared network and subnet levels and
|
||||
takes a floating point value between ``0.0`` (excluded) and ``1.0``.
|
||||
It is disabled by default or when set to ``1.0``. It is only supported
|
||||
by the FLQ allocator. When the occupancy rate of pools in a subnet is
|
||||
above the specified value the server decreases the lease valid lifetime
|
||||
to the applicable ``min-valid-lifetime`` for new clients. Clients
|
||||
renewing an already existing lease get at least the remaining lifetime
|
||||
from the current lease. Since the leases expire faster, the server may
|
||||
either recover more quickly or avoid pool exhaustion entirely.
|
||||
|
||||
The occupancy rate is defined as being the number of already assigned
|
||||
addresses (including the address being assigned) divided by the total
|
||||
number of addresses in pools where the address can be allocated from
|
||||
(i.e. if the query is not member of a ``client-classes`` guard of a pool
|
||||
this pool is not taken into account).
|
||||
|
@ -8730,3 +8730,21 @@ avoiding unnecessary impact on the server's startup time.
|
||||
As a result, the servers will not be able to offer some of the available
|
||||
leases to the clients. Only a server reclaiming a particular lease will
|
||||
be able to offer it.
|
||||
|
||||
In Kea 3.1.1 a new parameter ``adaptive-lease-time-threshold`` was added.
|
||||
It can be specified at global, shared network and subnet levels and
|
||||
takes a floating point value between ``0.0`` (excluded) and ``1.0``.
|
||||
It is disabled by default or when set to ``1.0``. It is only supported
|
||||
by the FLQ allocator. When the occupancy rate of pools in a subnet is
|
||||
above the specified value the server decreases the lease valid lifetime
|
||||
to the applicable ``min-valid-lifetime`` for new clients. Clients
|
||||
renewing an already existing lease get at least the remaining lifetime
|
||||
from the current lease. Since the leases expire faster, the server may
|
||||
either recover more quickly or avoid pool exhaustion entirely.
|
||||
|
||||
The occupancy rate is defined as being the number of already assigned
|
||||
delegated prefixes (including the address being assigned) divided by the total
|
||||
number of prefixes in pools where the address can be allocated from
|
||||
(i.e. if the query is not member of a ``client-classes`` guard of a pool,
|
||||
or if the delegated prefix length is not compatible this pool is not taken
|
||||
into account).
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1316,6 +1316,17 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
|
||||
}
|
||||
}
|
||||
|
||||
\"adaptive-lease-time-threshold\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
case isc::dhcp::Parser4Context::SUBNET4:
|
||||
case isc::dhcp::Parser4Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp4Parser::make_ADAPTIVE_LEASE_TIME_THRESHOLD(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp4Parser::make_STRING("adaptive-lease-time-threshold", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
\"loggers\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser4Context::DHCP4:
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -130,6 +130,7 @@ using namespace std;
|
||||
T2_PERCENT "t2-percent"
|
||||
CACHE_THRESHOLD "cache-threshold"
|
||||
CACHE_MAX_AGE "cache-max-age"
|
||||
ADAPTIVE_LEASE_TIME_THRESHOLD "adaptive-lease-time-threshold"
|
||||
DECLINE_PROBATION_PERIOD "decline-probation-period"
|
||||
SERVER_TAG "server-tag"
|
||||
STATISTIC_DEFAULT_SAMPLE_COUNT "statistic-default-sample-count"
|
||||
@ -563,6 +564,7 @@ global_param: valid_lifetime
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| loggers
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
@ -654,6 +656,12 @@ cache_max_age: CACHE_MAX_AGE COLON INTEGER {
|
||||
ctx.stack_.back()->set("cache-max-age", cm);
|
||||
};
|
||||
|
||||
adaptive_lease_time_threshold: ADAPTIVE_LEASE_TIME_THRESHOLD COLON FLOAT {
|
||||
ctx.unique("adaptive-lease-time-threshold", ctx.loc2pos(@1));
|
||||
ElementPtr altt(new DoubleElement($3, ctx.loc2pos(@3)));
|
||||
ctx.stack_.back()->set("adaptive-lease-time-threshold", altt);
|
||||
};
|
||||
|
||||
decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER {
|
||||
ctx.unique("decline-probation-period", ctx.loc2pos(@1));
|
||||
ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3)));
|
||||
@ -1683,6 +1691,7 @@ subnet4_param: valid_lifetime
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| ddns_send_updates
|
||||
| ddns_override_no_update
|
||||
| ddns_override_client_update
|
||||
@ -1887,6 +1896,7 @@ shared_network_param: name
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| ddns_send_updates
|
||||
| ddns_override_no_update
|
||||
| ddns_override_client_update
|
||||
|
@ -662,6 +662,7 @@ processDhcp4Config(isc::data::ConstElementPtr config_set) {
|
||||
(config_pair.first == "t2-percent") ||
|
||||
(config_pair.first == "cache-threshold") ||
|
||||
(config_pair.first == "cache-max-age") ||
|
||||
(config_pair.first == "adaptive-lease-time-threshold") ||
|
||||
(config_pair.first == "hostname-char-set") ||
|
||||
(config_pair.first == "hostname-char-replacement") ||
|
||||
(config_pair.first == "ddns-send-updates") ||
|
||||
|
313
src/bin/dhcp4/tests/flq_unittest.cc
Normal file
313
src/bin/dhcp4/tests/flq_unittest.cc
Normal file
@ -0,0 +1,313 @@
|
||||
// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/dhcp4.h>
|
||||
#include <dhcp/option_int.h>
|
||||
#include <dhcp/testutils/iface_mgr_test_config.h>
|
||||
#include <dhcp4/tests/dhcp4_test_utils.h>
|
||||
#include <dhcp4/tests/dhcp4_client.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp::test;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief JSON configuration
|
||||
std::string FLQ_CONFIG =
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"min-valid-lifetime\": 100,"
|
||||
"\"valid-lifetime\": 200,"
|
||||
"\"max-valid-lifetime\": 300,"
|
||||
"\"adaptive-lease-time-threshold\": .5,"
|
||||
"\"cache-threshold\": 0.,"
|
||||
"\"subnet4\": [ { "
|
||||
" \"subnet\": \"10.0.0.0/24\", "
|
||||
" \"id\": 1,"
|
||||
" \"pools\": [ { \"pool\": \"10.0.0.11-10.0.0.14\" } ],"
|
||||
" \"allocator\": \"flq\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
/// @brief Test fixture class for testing FLQ / adaptive-lease-time-threshold.
|
||||
class FLQTest : public Dhcpv4SrvTest {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// Sets up fake interfaces.
|
||||
FLQTest() : Dhcpv4SrvTest(), iface_mgr_test_config_(true) {
|
||||
}
|
||||
|
||||
/// @brief Creates a DHCPv4 lease for an address and MAC address.
|
||||
///
|
||||
/// @param address Lease address.
|
||||
/// @param hw_address_seed a seed from which the hardware address is generated.
|
||||
/// @return Created lease pointer.
|
||||
Lease4Ptr
|
||||
createLease4(const IOAddress& address, uint64_t hw_address_seed) const {
|
||||
vector<uint8_t> hw_address_vec(sizeof(hw_address_seed));
|
||||
for (unsigned i = 0; i < sizeof(hw_address_seed); ++i) {
|
||||
hw_address_vec[i] = (hw_address_seed >> i) & 0xFF;
|
||||
}
|
||||
HWAddrPtr hw_address(new HWAddr(hw_address_vec, HTYPE_ETHER));
|
||||
Lease4Ptr lease(new Lease4(address, hw_address, ClientIdPtr(),
|
||||
600, time(0), 1));
|
||||
return (lease);
|
||||
}
|
||||
|
||||
/// @brief Check the response.
|
||||
///
|
||||
/// @param resp the response.
|
||||
/// @param expected the expected lifetime.
|
||||
/// @param near use near comparision (when true) or equality (when false).
|
||||
void checkResponse(Pkt4Ptr resp, uint32_t expected, bool near = false) {
|
||||
ASSERT_TRUE(resp);
|
||||
|
||||
// Make sure that the server has responded with DHCPACK.
|
||||
ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
|
||||
|
||||
// Make sure that the client has got the requested address.
|
||||
EXPECT_EQ("10.0.0.14", resp->getYiaddr().toText());
|
||||
|
||||
// Verify the valid liftime.
|
||||
OptionUint32Ptr opt = boost::dynamic_pointer_cast<
|
||||
OptionUint32>(resp->getOption(DHO_DHCP_LEASE_TIME));
|
||||
ASSERT_TRUE(opt);
|
||||
if (near) {
|
||||
EXPECT_NEAR(expected, opt->getValue(), 2);
|
||||
} else {
|
||||
EXPECT_EQ(expected, opt->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Allocate all pool leases leaving the last one free.
|
||||
void fill() {
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
auto lease1 = createLease4(IOAddress("10.0.0.11"), 1);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease1));
|
||||
auto lease2 = createLease4(IOAddress("10.0.0.12"), 2);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease2));
|
||||
auto lease3 = createLease4(IOAddress("10.0.0.13"), 3);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease3));
|
||||
}
|
||||
|
||||
/// @brief Age and commit a lease.
|
||||
///
|
||||
/// @param lease the lease.
|
||||
/// @param delay the amount of time backward.
|
||||
/// @param update when false add the lease, when true update the lease.
|
||||
/// @param reclaim when true change the state.
|
||||
void ageLease(Lease4Ptr lease, uint32_t delay, bool update,
|
||||
bool reclaim = false) {
|
||||
ASSERT_TRUE(lease);
|
||||
lease->cltt_ -= delay;
|
||||
lease->current_cltt_ -= delay;
|
||||
if (reclaim) {
|
||||
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
|
||||
}
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
if (update) {
|
||||
EXPECT_NO_THROW(lease_mgr.updateLease4(lease));
|
||||
} else {
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Interface Manager's fake configuration control.
|
||||
IfaceMgrTestConfig iface_mgr_test_config_;
|
||||
};
|
||||
|
||||
// Test allocation with empty pool.
|
||||
TEST_F(FLQTest, empty) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last address.
|
||||
boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
|
||||
ASSERT_NO_THROW(client.doDORA(hint));
|
||||
|
||||
// Valid lifetime should be the valid-lifetime parameter value (200).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 200);
|
||||
}
|
||||
|
||||
// Test allocation with almost full pool.
|
||||
TEST_F(FLQTest, last) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first addresses.
|
||||
fill();
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
ASSERT_NO_THROW(client.doDORA());
|
||||
|
||||
// Valid lifetime should be the min-valid-lifetime parameter value (100).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 100);
|
||||
}
|
||||
|
||||
// Test allocation with an expired lease.
|
||||
TEST_F(FLQTest, expired) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first addresses.
|
||||
fill();
|
||||
|
||||
// Create and expire last lease.
|
||||
auto lease = createLease4(IOAddress("10.0.0.14"), 4);
|
||||
ageLease(lease, 1000, false);
|
||||
ASSERT_TRUE(lease->expired());
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
ASSERT_NO_THROW(client.doDORA());
|
||||
|
||||
// Valid lifetime should be the min-valid-lifetime parameter value (100).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 100);
|
||||
}
|
||||
|
||||
// Test allocation with a reclaimed lease.
|
||||
TEST_F(FLQTest, reclaimed) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first addresses.
|
||||
fill();
|
||||
|
||||
// Create and reclaim last lease.
|
||||
auto lease = createLease4(IOAddress("10.0.0.14"), 4);
|
||||
ageLease(lease, 1000, false, true);
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
ASSERT_NO_THROW(client.doDORA());
|
||||
|
||||
// Valid lifetime should be the min-valid-lifetime parameter value (100).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 100);
|
||||
}
|
||||
|
||||
// Test renewal with almost empty pool.
|
||||
TEST_F(FLQTest, renew) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Obtain a lease from the server using the 4-way exchange.
|
||||
boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
|
||||
ASSERT_NO_THROW(client.doDORA(hint));
|
||||
|
||||
// Valid lifetime should be the valid-lifetime parameter value (200).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 200);
|
||||
|
||||
// Age the lease.
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
Lease4Ptr lease = lease_mgr.getLease4(*hint);
|
||||
ageLease(lease, 150, true);
|
||||
ASSERT_FALSE(lease->expired());
|
||||
|
||||
// Let's transition the client to Renewing state.
|
||||
client.setState(Dhcp4Client::RENEWING);
|
||||
|
||||
// Set the unicast destination address to indicate that it is a renewal.
|
||||
client.setDestAddress(IOAddress("10.0.0.1"));
|
||||
ASSERT_NO_THROW(client.doRequest());
|
||||
|
||||
// Valid lifetime should be the valid-lifetime parameter value (200).
|
||||
resp = client.getContext().response_;
|
||||
checkResponse(resp, 200);
|
||||
}
|
||||
|
||||
// Test renewal with full pool.
|
||||
TEST_F(FLQTest, renewFull) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Obtain a lease from the server using the 4-way exchange.
|
||||
boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
|
||||
ASSERT_NO_THROW(client.doDORA(hint));
|
||||
|
||||
// Valid lifetime should be the valid-lifetime parameter value (200).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 200);
|
||||
|
||||
// Create leases for the first addresses.
|
||||
fill();
|
||||
|
||||
// Age the lease.
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
Lease4Ptr lease = lease_mgr.getLease4(*hint);
|
||||
ageLease(lease, 150, true);
|
||||
ASSERT_FALSE(lease->expired());
|
||||
|
||||
// Let's transition the client to Renewing state.
|
||||
client.setState(Dhcp4Client::RENEWING);
|
||||
|
||||
// Set the unicast destination address to indicate that it is a renewal.
|
||||
client.setDestAddress(IOAddress("10.0.0.1"));
|
||||
ASSERT_NO_THROW(client.doRequest());
|
||||
|
||||
// Valid lifetime should be the min-valid-lifetime parameter value (100).
|
||||
resp = client.getContext().response_;
|
||||
checkResponse(resp, 100);
|
||||
}
|
||||
|
||||
// Test renewal with full pool but remaining lifetime greater than minimal.
|
||||
TEST_F(FLQTest, renewRemaining) {
|
||||
Dhcp4Client client(srv_, Dhcp4Client::SELECTING);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Obtain a lease from the server using the 4-way exchange.
|
||||
boost::shared_ptr<IOAddress> hint(new IOAddress("10.0.0.14"));
|
||||
ASSERT_NO_THROW(client.doDORA(hint));
|
||||
|
||||
// Valid lifetime should be the valid-lifetime parameter value (200).
|
||||
Pkt4Ptr resp = client.getContext().response_;
|
||||
checkResponse(resp, 200);
|
||||
|
||||
// Create leases for the first addresses.
|
||||
fill();
|
||||
|
||||
// Age the lease but only by 50 seconds.
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
Lease4Ptr lease = lease_mgr.getLease4(*hint);
|
||||
ageLease(lease, 50, true);
|
||||
ASSERT_FALSE(lease->expired());
|
||||
|
||||
// Let's transition the client to Renewing state.
|
||||
client.setState(Dhcp4Client::RENEWING);
|
||||
|
||||
// Set the unicast destination address to indicate that it is a renewal.
|
||||
client.setDestAddress(IOAddress("10.0.0.1"));
|
||||
ASSERT_NO_THROW(client.doRequest());
|
||||
|
||||
// Valid lifetime should be the remaining lifetime so ~150 seconds.
|
||||
resp = client.getContext().response_;
|
||||
checkResponse(resp, 150, true);
|
||||
}
|
||||
|
||||
}
|
@ -126,6 +126,7 @@ kea_dhcp4_tests = executable(
|
||||
'dhcp4to6_ipc_unittest.cc',
|
||||
'direct_client_unittest.cc',
|
||||
'dora_unittest.cc',
|
||||
'flq_unittest.cc',
|
||||
'fqdn_unittest.cc',
|
||||
'get_config_unittest.cc',
|
||||
'hooks_unittest.cc',
|
||||
|
@ -210,6 +210,6 @@ TEST_F(SimpleParser4Test, optionDefDefaults4) {
|
||||
checkBoolValue(def, "array", false);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1169,7 +1169,7 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("ddns-ttl-percent", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
\"ddns-ttl\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
@ -1613,6 +1613,17 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu]
|
||||
}
|
||||
}
|
||||
|
||||
\"adaptive-lease-time-threshold\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
case isc::dhcp::Parser6Context::SUBNET6:
|
||||
case isc::dhcp::Parser6Context::SHARED_NETWORK:
|
||||
return isc::dhcp::Dhcp6Parser::make_ADAPTIVE_LEASE_TIME_THRESHOLD(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("adaptive-lease-time-threshold", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
\"loggers\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::DHCP6:
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -115,6 +115,7 @@ using namespace std;
|
||||
T2_PERCENT "t2-percent"
|
||||
CACHE_THRESHOLD "cache-threshold"
|
||||
CACHE_MAX_AGE "cache-max-age"
|
||||
ADAPTIVE_LEASE_TIME_THRESHOLD "adaptive-lease-time-threshold"
|
||||
DECLINE_PROBATION_PERIOD "decline-probation-period"
|
||||
SERVER_TAG "server-tag"
|
||||
STATISTIC_DEFAULT_SAMPLE_COUNT "statistic-default-sample-count"
|
||||
@ -568,6 +569,7 @@ global_param: data_directory
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| loggers
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
@ -686,6 +688,12 @@ cache_max_age: CACHE_MAX_AGE COLON INTEGER {
|
||||
ctx.stack_.back()->set("cache-max-age", cm);
|
||||
};
|
||||
|
||||
adaptive_lease_time_threshold: ADAPTIVE_LEASE_TIME_THRESHOLD COLON FLOAT {
|
||||
ctx.unique("adaptive-lease-time-threshold", ctx.loc2pos(@1));
|
||||
ElementPtr altt(new DoubleElement($3, ctx.loc2pos(@3)));
|
||||
ctx.stack_.back()->set("adaptive-lease-time-threshold", altt);
|
||||
};
|
||||
|
||||
decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER {
|
||||
ctx.unique("decline-probation-period", ctx.loc2pos(@1));
|
||||
ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3)));
|
||||
@ -1692,6 +1700,7 @@ subnet6_param: preferred_lifetime
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
| ddns_send_updates
|
||||
@ -1884,6 +1893,7 @@ shared_network_param: name
|
||||
| t2_percent
|
||||
| cache_threshold
|
||||
| cache_max_age
|
||||
| adaptive_lease_time_threshold
|
||||
| hostname_char_set
|
||||
| hostname_char_replacement
|
||||
| ddns_send_updates
|
||||
|
@ -780,6 +780,7 @@ processDhcp6Config(isc::data::ConstElementPtr config_set) {
|
||||
(config_pair.first == "t2-percent") ||
|
||||
(config_pair.first == "cache-threshold") ||
|
||||
(config_pair.first == "cache-max-age") ||
|
||||
(config_pair.first == "adaptive-lease-time-threshold") ||
|
||||
(config_pair.first == "hostname-char-set") ||
|
||||
(config_pair.first == "hostname-char-replacement") ||
|
||||
(config_pair.first == "ddns-send-updates") ||
|
||||
|
409
src/bin/dhcp6/tests/flq_unittest.cc
Normal file
409
src/bin/dhcp6/tests/flq_unittest.cc
Normal file
@ -0,0 +1,409 @@
|
||||
// Copyright (C) 2025 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/testutils/iface_mgr_test_config.h>
|
||||
#include <dhcp6/tests/dhcp6_test_utils.h>
|
||||
#include <dhcp6/tests/dhcp6_client.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp::test;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief JSON configuration
|
||||
std::string FLQ_CONFIG =
|
||||
"{ \"interfaces-config\": {"
|
||||
" \"interfaces\": [ \"*\" ]"
|
||||
"},"
|
||||
"\"min-preferred-lifetime\": 100,"
|
||||
"\"preferred-lifetime\": 200,"
|
||||
"\"max-preferred-lifetime\": 300,"
|
||||
"\"min-valid-lifetime\": 400,"
|
||||
"\"valid-lifetime\": 600,"
|
||||
"\"max-valid-lifetime\": 700,"
|
||||
"\"rebind-timer\": 250,"
|
||||
"\"renew-timer\": 250,"
|
||||
"\"adaptive-lease-time-threshold\": .5,"
|
||||
"\"cache-threshold\": 0.,"
|
||||
"\"subnet6\": [ { "
|
||||
" \"subnet\": \"3000::/32\", "
|
||||
" \"id\": 1,"
|
||||
" \"interface\": \"eth0\","
|
||||
" \"pd-pools\": [ {"
|
||||
" \"prefix\": \"2001:db8:1::\","
|
||||
" \"prefix-len\": 48,"
|
||||
" \"delegated-len\": 51"
|
||||
" } ],"
|
||||
" \"pd-allocator\": \"flq\""
|
||||
" } ]"
|
||||
"}";
|
||||
|
||||
/// @brief Test fixture class for testing FLQ / adaptive-lease-time-threshold.
|
||||
class FLQTest : public Dhcpv6SrvTest {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// Sets up fake interfaces.
|
||||
FLQTest() : Dhcpv6SrvTest(), iface_mgr_test_config_(true) {
|
||||
}
|
||||
|
||||
/// @brief Creates a DHCPv6 lease for an address and MAC address.
|
||||
///
|
||||
/// @param address Lease address.
|
||||
/// @param duid_seed a seed from which the DUID is generated.
|
||||
/// @return Created lease pointer.
|
||||
Lease6Ptr
|
||||
createLease6(const IOAddress& address, uint64_t duid_seed) const {
|
||||
vector<uint8_t> duid_vec(sizeof(duid_seed));
|
||||
for (unsigned i = 0; i < sizeof(duid_seed); ++i) {
|
||||
duid_vec[i] = (duid_seed >> i) & 0xFF;
|
||||
}
|
||||
DuidPtr duid(new DUID(duid_vec));
|
||||
Lease6Ptr lease(new Lease6(Lease::TYPE_PD, address, duid, 1,
|
||||
800, 1200, 1, HWAddrPtr(), 51));
|
||||
return (lease);
|
||||
}
|
||||
|
||||
/// @brief Check the returned lease.
|
||||
///
|
||||
/// @param lease the lease.
|
||||
/// @param exp_preferred the expected preferred lifetime.
|
||||
/// @param exp_valid the expected valid lifetime
|
||||
/// @param near_preferred use near comparision (when true) or equality
|
||||
/// when false) for the preferred lifetime.
|
||||
/// @param near_valid use near comparision (when true) or equality
|
||||
/// when false) for the valid lifetime.
|
||||
void checkResponse(Lease6Ptr lease, uint32_t exp_preferred,
|
||||
uint32_t exp_valid, bool near_preferred = false,
|
||||
bool near_valid = false) {
|
||||
ASSERT_TRUE(lease);
|
||||
|
||||
// Make sure that the client has got the requested prefix.
|
||||
EXPECT_EQ("2001:db8:1:e000::", lease->addr_.toText());
|
||||
EXPECT_EQ(51, lease->prefixlen_);
|
||||
|
||||
if (near_preferred) {
|
||||
EXPECT_NEAR(exp_preferred, lease->preferred_lft_, 2);
|
||||
} else {
|
||||
EXPECT_EQ(exp_preferred, lease->preferred_lft_);
|
||||
}
|
||||
|
||||
if (near_valid) {
|
||||
EXPECT_NEAR(exp_valid, lease->valid_lft_, 2);
|
||||
} else {
|
||||
EXPECT_EQ(exp_valid, lease->valid_lft_);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Allocate all pool leases leaving the last one free.
|
||||
void fill() {
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
auto lease0 = createLease6(IOAddress("2001:db8:1::"), 1);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease0));
|
||||
auto lease1 = createLease6(IOAddress("2001:db8:1:2000::"), 2);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease1));
|
||||
auto lease2 = createLease6(IOAddress("2001:db8:1:4000::"), 3);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease2));
|
||||
auto lease3 = createLease6(IOAddress("2001:db8:1:6000::"), 4);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease3));
|
||||
auto lease4 = createLease6(IOAddress("2001:db8:1:8000::"), 5);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease4));
|
||||
auto lease5 = createLease6(IOAddress("2001:db8:1:a000::"), 6);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease5));
|
||||
auto lease6 = createLease6(IOAddress("2001:db8:1:c000::"), 7);
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease6));
|
||||
}
|
||||
|
||||
/// @brief Age and commit a lease.
|
||||
///
|
||||
/// @param lease the lease.
|
||||
/// @param delay the amount of time backward.
|
||||
/// @param update when false add the lease, when true update the lease.
|
||||
/// @param reclaim when true change the state.
|
||||
void ageLease(Lease6Ptr lease, uint32_t delay, bool update,
|
||||
bool reclaim = false) {
|
||||
ASSERT_TRUE(lease);
|
||||
lease->cltt_ -= delay;
|
||||
lease->current_cltt_ -= delay;
|
||||
if (reclaim) {
|
||||
lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
|
||||
}
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
if (update) {
|
||||
EXPECT_NO_THROW(lease_mgr.updateLease6(lease));
|
||||
} else {
|
||||
EXPECT_TRUE(lease_mgr.addLease(lease));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Interface Manager's fake configuration control.
|
||||
IfaceMgrTestConfig iface_mgr_test_config_;
|
||||
};
|
||||
|
||||
// Test allocation with empty pool.
|
||||
TEST_F(FLQTest, empty) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last prefix.
|
||||
client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(lease, 200, 600);
|
||||
}
|
||||
|
||||
// Test allocation with almost full pool.
|
||||
TEST_F(FLQTest, last) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
client.requestPrefix();
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config min-preferred-lifetime (100).
|
||||
// Valid lifetime should be the config min-valid-lifetime (400).
|
||||
checkResponse(lease, 100, 400);
|
||||
}
|
||||
|
||||
// Test allocation with an expired lease.
|
||||
TEST_F(FLQTest, expired) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Create and expire last lease.
|
||||
auto lease7 = createLease6(IOAddress("2001:db8:1:e000::"), 8);
|
||||
ageLease(lease7, 10000, false);
|
||||
ASSERT_TRUE(lease7->expired());
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
client.requestPrefix();
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config min-preferred-lifetime (100).
|
||||
// Valid lifetime should be the config min-valid-lifetime (400).
|
||||
checkResponse(lease, 100, 400);
|
||||
}
|
||||
|
||||
// Test allocation with a reclaimed lease.
|
||||
TEST_F(FLQTest, reclaimed) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Create and reclaim last lease.
|
||||
auto lease7 = createLease6(IOAddress("2001:db8:1:e000::"), 8);
|
||||
ageLease(lease7, 10000, false, true);
|
||||
ASSERT_TRUE(lease7->expired());
|
||||
|
||||
// Perform 4-way exchange with the server.
|
||||
client.requestPrefix();
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config min-preferred-lifetime (100).
|
||||
// Valid lifetime should be the config min-valid-lifetime (400).
|
||||
checkResponse(lease, 100, 400);
|
||||
}
|
||||
|
||||
// Test renewal with almost empty pool.
|
||||
TEST_F(FLQTest, renew) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last prefix.
|
||||
client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(lease, 200, 600);
|
||||
|
||||
// Age the lease.
|
||||
ageLease(lease, 1000, true);
|
||||
|
||||
// Send the renew message to the server.
|
||||
ASSERT_NO_THROW(client.doRenew());
|
||||
|
||||
// Server should have renewed the prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr renewed = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(renewed, 200, 600);
|
||||
|
||||
// Check the lease was updated.
|
||||
EXPECT_NEAR(lease->cltt_ + 1000, renewed->cltt_, 2);
|
||||
}
|
||||
|
||||
// Test renewal with full pool.
|
||||
TEST_F(FLQTest, renewFull) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last prefix.
|
||||
client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(lease, 200, 600);
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Age the lease.
|
||||
ageLease(lease, 1000, true);
|
||||
|
||||
// Send the renew message to the server.
|
||||
ASSERT_NO_THROW(client.doRenew());
|
||||
|
||||
// Server should have renewed the prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr renewed = checkLease(client.getLease(0));
|
||||
ASSERT_TRUE(renewed);
|
||||
|
||||
// Preferred lifetime should be the config min-preferred-lifetime (100).
|
||||
// Valid lifetime should be the config min-valid-lifetime (400).
|
||||
checkResponse(renewed, 100, 400);
|
||||
|
||||
// Check the lease was updated.
|
||||
EXPECT_NEAR(lease->cltt_ + 1000, renewed->cltt_, 2);
|
||||
}
|
||||
|
||||
// Test renewal with full pool but remaining lifetimes greater than minimal.
|
||||
TEST_F(FLQTest, renewRemaining) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last prefix.
|
||||
client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(lease, 200, 600);
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Age the lease but only by 50 seconds.
|
||||
ageLease(lease, 50, true);
|
||||
|
||||
// Send the renew message to the server.
|
||||
ASSERT_NO_THROW(client.doRenew());
|
||||
|
||||
// Server should have renewed the prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr renewed = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the remaining lifetime so ~150.
|
||||
// Valid lifetime should be the remaining lifetime so ~550
|
||||
checkResponse(renewed, 150, 550, true, true);
|
||||
|
||||
// Check the lease was updated.
|
||||
EXPECT_NEAR(lease->cltt_ + 50, renewed->cltt_, 2);
|
||||
}
|
||||
|
||||
// Test renewal with full pool but remaining valid lifetime only greater
|
||||
// than minimal.
|
||||
TEST_F(FLQTest, renewRemainingValid) {
|
||||
Dhcp6Client client(srv_);
|
||||
|
||||
// Configure DHCP server.
|
||||
configure(FLQ_CONFIG, *client.getServer());
|
||||
|
||||
// Perform 4-way exchange with the server requesting the last prefix.
|
||||
client.requestPrefix(1, 51, IOAddress("2001:db8:1:e000::"));
|
||||
ASSERT_NO_THROW(client.doSARR());
|
||||
|
||||
// Server should have assigned a prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr lease = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config preferred-lifetime (200).
|
||||
// Valid lifetime should be the config valid-lifetime (600).
|
||||
checkResponse(lease, 200, 600);
|
||||
|
||||
// Create leases for the first prefixes.
|
||||
fill();
|
||||
|
||||
// Age the lease but only by 150 seconds.
|
||||
ageLease(lease, 150, true);
|
||||
|
||||
// Send the renew message to the server.
|
||||
ASSERT_NO_THROW(client.doRenew());
|
||||
|
||||
// Server should have renewed the prefix.
|
||||
ASSERT_EQ(1, client.getLeaseNum());
|
||||
Lease6Ptr renewed = checkLease(client.getLease(0));
|
||||
|
||||
// Preferred lifetime should be the config min-preferred-lifetime (100).
|
||||
// Valid lifetime should be the remaining lifetime so ~450
|
||||
checkResponse(renewed, 100, 450, false, true);
|
||||
|
||||
// Check the lease was updated.
|
||||
EXPECT_NEAR(lease->cltt_ + 150, renewed->cltt_, 2);
|
||||
}
|
||||
|
||||
}
|
@ -127,6 +127,7 @@ kea_dhcp6_tests = executable(
|
||||
'dhcp6_test_utils.cc',
|
||||
'dhcp6_unittests.cc',
|
||||
'dhcp6to4_ipc_unittest.cc',
|
||||
'flq_unittest.cc',
|
||||
'fqdn_unittest.cc',
|
||||
'get_config_unittest.cc',
|
||||
'hooks_unittest.cc',
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
/// false this indicates that the IOService was stopped.
|
||||
///
|
||||
/// @param wait_time_usecs wait time in microseconds.
|
||||
/// @param[out] time_out set to true if the wait time expired
|
||||
/// @param[out] timed_out set to true if the wait time expired
|
||||
/// without any handlers executing.
|
||||
/// timed_out parameter will be set true if the wait time elapsed.
|
||||
///
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
/// false this indicates that the IOService was stopped.
|
||||
///
|
||||
/// @param wait_time_usecs wait time in microseconds.
|
||||
/// @param[out] time_out set to true if the wait time expired
|
||||
/// @param[out] timed_out set to true if the wait time expired
|
||||
/// without any handlers executing.
|
||||
/// timed_out parameter will be set true if the wait time elapsed.
|
||||
///
|
||||
|
@ -272,7 +272,7 @@ private:
|
||||
/// their hashes are equal, if two class lists are not equal their hashes
|
||||
/// are almost surely not equal.
|
||||
///
|
||||
/// @param address A @c ClientClasses to hash.
|
||||
/// @param client_classes A @c ClientClasses to hash.
|
||||
/// @return The hash of the ClientClasses.
|
||||
|
||||
size_t hash_value(const ClientClasses& client_classes);
|
||||
|
@ -1737,6 +1737,22 @@ AllocEngine::removeNonreservedLeases6(ClientContext6& ctx,
|
||||
existing_leases.end(), Lease6Ptr()), existing_leases.end());
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool
|
||||
useMinLifetimes6(AllocEngine::ClientContext6& ctx, const IOAddress& addr,
|
||||
uint8_t prefix_len) {
|
||||
auto const& threshold = ctx.subnet_->getAdaptiveLeaseTimeThreshold();
|
||||
if (!threshold.unspecified() && (threshold < 1.0)) {
|
||||
auto const& occupancy = ctx.subnet_->getAllocator(Lease::TYPE_PD)->
|
||||
getOccupancyRate(addr, prefix_len, ctx.query_->getClasses());
|
||||
if (occupancy >= threshold) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
} // end of anonymous namespace.
|
||||
|
||||
Lease6Ptr
|
||||
AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
|
||||
uint8_t prefix_len,
|
||||
@ -1764,12 +1780,20 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
|
||||
// address, lease type and prefixlen (0) stay the same
|
||||
expired->iaid_ = ctx.currentIA().iaid_;
|
||||
expired->duid_ = ctx.duid_;
|
||||
expired->hwaddr_ = ctx.hwaddr_;
|
||||
|
||||
// Calculate life times.
|
||||
getLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
|
||||
expired->preferred_lft_ = 0;
|
||||
expired->valid_lft_ = 0;
|
||||
if ((expired->type_ == Lease::TYPE_PD) &&
|
||||
useMinLifetimes6(ctx, expired->addr_, prefix_len)) {
|
||||
getMinLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
|
||||
} else {
|
||||
getLifetimes6(ctx, expired->preferred_lft_, expired->valid_lft_);
|
||||
}
|
||||
expired->reuseable_valid_lft_ = 0;
|
||||
|
||||
expired->cltt_ = time(NULL);
|
||||
expired->cltt_ = time(0);
|
||||
expired->subnet_id_ = ctx.subnet_->getID();
|
||||
expired->hostname_ = ctx.hostname_;
|
||||
expired->fqdn_fwd_ = ctx.fwd_dns_update_;
|
||||
@ -1891,6 +1915,20 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
|
||||
return (expired);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void sanitizeLifetimes6(AllocEngine::ClientContext6& ctx,
|
||||
uint32_t& preferred, uint32_t& valid) {
|
||||
// If preferred isn't set or insane, calculate it as valid_lft * 0.625.
|
||||
if (!preferred || preferred > valid) {
|
||||
preferred = ((valid * 5)/8);
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V6_CALCULATED_PREFERRED_LIFETIME)
|
||||
.arg(ctx.query_->getLabel())
|
||||
.arg(preferred);
|
||||
}
|
||||
}
|
||||
} // end of anonymous namespace.
|
||||
|
||||
void
|
||||
AllocEngine::getLifetimes6(ClientContext6& ctx, uint32_t& preferred, uint32_t& valid) {
|
||||
// If the triplets are specified in one of our classes use it.
|
||||
@ -1950,14 +1988,70 @@ AllocEngine::getLifetimes6(ClientContext6& ctx, uint32_t& preferred, uint32_t& v
|
||||
}
|
||||
}
|
||||
|
||||
// If preferred isn't set or insane, calculate it as valid_lft * 0.625.
|
||||
if (!preferred || preferred > valid) {
|
||||
preferred = ((valid * 5)/8);
|
||||
LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
|
||||
ALLOC_ENGINE_V6_CALCULATED_PREFERRED_LIFETIME)
|
||||
.arg(ctx.query_->getLabel())
|
||||
.arg(preferred);
|
||||
sanitizeLifetimes6(ctx, preferred, valid);
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::getMinLifetimes6(ClientContext6& ctx, uint32_t& preferred,
|
||||
uint32_t& valid) {
|
||||
// If the triplets are specified in one of our classes use it.
|
||||
// We use the first one we find for each lifetime.
|
||||
Triplet<uint32_t> candidate_preferred;
|
||||
Triplet<uint32_t> candidate_valid;
|
||||
const ClientClasses classes = ctx.query_->getClasses();
|
||||
if (!classes.empty()) {
|
||||
// Let's get class definitions
|
||||
const ClientClassDictionaryPtr& dict =
|
||||
CfgMgr::instance().getCurrentCfg()->getClientClassDictionary();
|
||||
|
||||
// Iterate over the assigned class definitions.
|
||||
int have_both = 0;
|
||||
for (auto const& name : classes) {
|
||||
ClientClassDefPtr cl = dict->findClass(name);
|
||||
if (candidate_preferred.unspecified() &&
|
||||
(cl && (!cl->getPreferred().unspecified()))) {
|
||||
candidate_preferred = cl->getPreferred();
|
||||
++have_both;
|
||||
}
|
||||
|
||||
if (candidate_valid.unspecified() &&
|
||||
(cl && (!cl->getValid().unspecified()))) {
|
||||
candidate_valid = cl->getValid();
|
||||
++have_both;
|
||||
}
|
||||
if (have_both == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no classes specified preferred lifetime, get it from the subnet.
|
||||
if (!candidate_preferred) {
|
||||
candidate_preferred = ctx.subnet_->getPreferred();
|
||||
}
|
||||
|
||||
// If no classes specified valid lifetime, get it from the subnet.
|
||||
if (!candidate_valid) {
|
||||
candidate_valid = ctx.subnet_->getValid();
|
||||
}
|
||||
|
||||
// Save remaining values.
|
||||
uint32_t remain_preferred(preferred);
|
||||
uint32_t remain_valid(valid);
|
||||
|
||||
// Set the outbound parameters to the minimal values.
|
||||
preferred = candidate_preferred.getMin();
|
||||
valid = candidate_valid.getMin();
|
||||
|
||||
// Return at least the remaining values.
|
||||
if (remain_preferred > preferred) {
|
||||
preferred = remain_preferred;
|
||||
}
|
||||
if (remain_valid > valid) {
|
||||
valid = remain_valid;
|
||||
}
|
||||
|
||||
sanitizeLifetimes6(ctx, preferred, valid);
|
||||
}
|
||||
|
||||
Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
|
||||
@ -1971,7 +2065,12 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
|
||||
|
||||
uint32_t preferred = 0;
|
||||
uint32_t valid = 0;
|
||||
getLifetimes6(ctx, preferred, valid);
|
||||
if ((ctx.currentIA().type_ == Lease::TYPE_PD) &&
|
||||
useMinLifetimes6(ctx, addr, prefix_len)) {
|
||||
getMinLifetimes6(ctx, preferred, valid);
|
||||
} else {
|
||||
getLifetimes6(ctx, preferred, valid);
|
||||
}
|
||||
|
||||
Lease6Ptr lease(new Lease6(ctx.currentIA().type_, addr, ctx.duid_,
|
||||
ctx.currentIA().iaid_, preferred,
|
||||
@ -2098,6 +2197,31 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::getRemaining(const Lease6Ptr& lease, uint32_t& preferred,
|
||||
uint32_t& valid) {
|
||||
valid = 0;
|
||||
preferred = 0;
|
||||
if (!lease || (lease->state_ != Lease::STATE_DEFAULT)) {
|
||||
return;
|
||||
}
|
||||
time_t now = time(0);
|
||||
// Refuse time not going forward.
|
||||
if (lease->cltt_ > now) {
|
||||
return;
|
||||
}
|
||||
uint32_t age = now - lease->cltt_;
|
||||
// Already expired.
|
||||
if (age >= lease->valid_lft_) {
|
||||
return;
|
||||
}
|
||||
valid = lease->valid_lft_ - age;
|
||||
if (age >= lease->preferred_lft_) {
|
||||
return;
|
||||
}
|
||||
preferred = lease->preferred_lft_ - age;
|
||||
}
|
||||
|
||||
Lease6Collection
|
||||
AllocEngine::renewLeases6(ClientContext6& ctx) {
|
||||
try {
|
||||
@ -2282,7 +2406,17 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
|
||||
|
||||
// Calculate life times.
|
||||
uint32_t current_preferred_lft = lease->preferred_lft_;
|
||||
getLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
if ((lease->type_ == Lease::TYPE_PD) &&
|
||||
useMinLifetimes6(ctx, lease->addr_, lease->prefixlen_)) {
|
||||
uint32_t remain_preferred_lft(0);
|
||||
uint32_t remain_valid_lft(0);
|
||||
getRemaining(lease, remain_preferred_lft, remain_valid_lft);
|
||||
lease->preferred_lft_ = remain_preferred_lft;
|
||||
lease->valid_lft_ = remain_valid_lft;
|
||||
getMinLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
} else {
|
||||
getLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
}
|
||||
|
||||
// If either has changed set the changed flag.
|
||||
if ((lease->preferred_lft_ != current_preferred_lft) ||
|
||||
@ -2468,7 +2602,13 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases
|
||||
uint32_t current_preferred_lft = lease->preferred_lft_;
|
||||
if (lease->valid_lft_ == 0) {
|
||||
// The lease was expired by a release: reset zero lifetimes.
|
||||
getLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
lease->preferred_lft_ = 0;
|
||||
if ((lease->type_ == Lease::TYPE_PD) &&
|
||||
useMinLifetimes6(ctx, lease->addr_, lease->prefixlen_)) {
|
||||
getMinLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
} else {
|
||||
getLifetimes6(ctx, lease->preferred_lft_, lease->valid_lft_);
|
||||
}
|
||||
}
|
||||
if (!ctx.fake_allocation_) {
|
||||
bool update_stats = false;
|
||||
@ -4313,6 +4453,65 @@ AllocEngine::getValidLft(const ClientContext4& ctx) {
|
||||
return (candidate_lft.get());
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::getMinValidLft(const ClientContext4& ctx, uint32_t& valid) {
|
||||
// If it's BOOTP, use infinite valid lifetime.
|
||||
if (ctx.query_->inClass("BOOTP")) {
|
||||
valid = Lease::INFINITY_LFT;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the triplet is specified in one of our classes use it.
|
||||
// We use the first one we find.
|
||||
Triplet<uint32_t> candidate_lft;
|
||||
const ClientClasses classes = ctx.query_->getClasses();
|
||||
if (!classes.empty()) {
|
||||
// Let's get class definitions
|
||||
const ClientClassDictionaryPtr& dict =
|
||||
CfgMgr::instance().getCurrentCfg()->getClientClassDictionary();
|
||||
|
||||
// Iterate over the assigned class definitions.
|
||||
for (auto const& name : classes) {
|
||||
ClientClassDefPtr cl = dict->findClass(name);
|
||||
if (cl && (!cl->getValid().unspecified())) {
|
||||
candidate_lft = cl->getValid();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no classes specified it, get it from the subnet.
|
||||
if (!candidate_lft) {
|
||||
candidate_lft = ctx.subnet_->getValid();
|
||||
}
|
||||
|
||||
// Save remaining value.
|
||||
uint32_t remain(valid);
|
||||
|
||||
// Set to the minimal value.
|
||||
valid = candidate_lft.getMin();
|
||||
|
||||
// Return at least the remaining value.
|
||||
if (remain > valid) {
|
||||
valid = remain;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool
|
||||
useMinValidLft(const AllocEngine::ClientContext4& ctx, const IOAddress&addr) {
|
||||
auto const& threshold = ctx.subnet_->getAdaptiveLeaseTimeThreshold();
|
||||
if (!threshold.unspecified() && (threshold < 1.0)) {
|
||||
auto const& occupancy = ctx.subnet_->getAllocator(Lease::TYPE_V4)->
|
||||
getOccupancyRate(addr, ctx.query_->getClasses());
|
||||
if (occupancy >= threshold) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
} // end of anonymous namespace.
|
||||
|
||||
Lease4Ptr
|
||||
AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr,
|
||||
CalloutHandle::CalloutNextStep& callout_status) {
|
||||
@ -4324,9 +4523,16 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr,
|
||||
}
|
||||
|
||||
// Get the context appropriate lifetime.
|
||||
uint32_t valid_lft = (ctx.offer_lft_ ? ctx.offer_lft_ : getValidLft(ctx));
|
||||
uint32_t valid_lft = ctx.offer_lft_;
|
||||
if (!valid_lft) {
|
||||
if (useMinValidLft(ctx, addr)) {
|
||||
getMinValidLft(ctx, valid_lft);
|
||||
} else {
|
||||
valid_lft = getValidLft(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
time_t now = time(NULL);
|
||||
time_t now = time(0);
|
||||
|
||||
ClientIdPtr client_id;
|
||||
if (ctx.subnet_->getMatchClientId()) {
|
||||
@ -4457,6 +4663,30 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AllocEngine::getRemaining(const Lease4Ptr& lease, uint32_t& valid) {
|
||||
valid = 0;
|
||||
if (!lease || (lease->state_ != Lease::STATE_DEFAULT)) {
|
||||
return;
|
||||
}
|
||||
// Always remain infinite lifetime leases.
|
||||
if (lease->valid_lft_ == Lease::INFINITY_LFT) {
|
||||
valid = Lease::INFINITY_LFT;
|
||||
return;
|
||||
}
|
||||
time_t now = time(0);
|
||||
// Refuse time not going forward.
|
||||
if (lease->cltt_ > now) {
|
||||
return;
|
||||
}
|
||||
uint32_t age = now - lease->cltt_;
|
||||
// Already expired.
|
||||
if (age >= lease->valid_lft_) {
|
||||
return;
|
||||
}
|
||||
valid = lease->valid_lft_ - age;
|
||||
}
|
||||
|
||||
Lease4Ptr
|
||||
AllocEngine::renewLease4(const Lease4Ptr& lease,
|
||||
AllocEngine::ClientContext4& ctx) {
|
||||
@ -4998,10 +5228,20 @@ AllocEngine::updateLease4Information(const Lease4Ptr& lease,
|
||||
changed = true;
|
||||
lease->client_id_ = ClientIdPtr();
|
||||
}
|
||||
lease->cltt_ = time(NULL);
|
||||
uint32_t remain_lft(0);
|
||||
getRemaining(lease, remain_lft);
|
||||
lease->cltt_ = time(0);
|
||||
|
||||
// Get the context appropriate valid lifetime.
|
||||
lease->valid_lft_ = (ctx.offer_lft_ ? ctx.offer_lft_ : getValidLft(ctx));
|
||||
lease->valid_lft_ = ctx.offer_lft_;
|
||||
if (!lease->valid_lft_) {
|
||||
if (useMinValidLft(ctx, lease->addr_)) {
|
||||
lease->valid_lft_ = remain_lft;
|
||||
getMinValidLft(ctx, lease->valid_lft_);
|
||||
} else {
|
||||
lease->valid_lft_ = getValidLft(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// Valid lifetime has changed.
|
||||
if (lease->valid_lft_ != lease->current_valid_lft_) {
|
||||
|
@ -816,10 +816,26 @@ public:
|
||||
///
|
||||
/// @param ctx client context that passes all necessary information. See
|
||||
/// @ref ClientContext6 for details.
|
||||
/// @param [out] preferred set to the preferred lifetime that should be used.
|
||||
/// @param [out] valid set to the valid lifetime that should be used.
|
||||
/// @param[out] preferred set to the preferred lifetime that should be used.
|
||||
/// @param[out] valid set to the valid lifetime that should be used.
|
||||
static void getLifetimes6(ClientContext6& ctx, uint32_t& preferred,
|
||||
uint32_t& valid);
|
||||
|
||||
/// @brief Determines the preferred and valid v6 lease lifetimes when
|
||||
/// the pool occupancy is over the adaptive lease time threshold.
|
||||
///
|
||||
/// As for the common case find the candidate triplet and return
|
||||
/// minimal values. Requested lifetimes are ignored but remaining
|
||||
/// lifetimes are returned when greater than minimal.
|
||||
///
|
||||
/// @param ctx client context that passes all necessary information. See
|
||||
/// @ref ClientContext6 for details.
|
||||
/// @param[in,out] preferred set to the preferred lifetime that should
|
||||
/// be used. Caller must set it to 0 or remaining value.
|
||||
/// @param[in,out] valid set to the valid lifetime that should be used.
|
||||
/// Caller must set it to 0 or remaining value.
|
||||
static void getMinLifetimes6(ClientContext6& ctx, uint32_t& preferred,
|
||||
uint32_t& valid);
|
||||
private:
|
||||
|
||||
/// @brief Creates a lease and inserts it in LeaseMgr if necessary
|
||||
@ -834,7 +850,7 @@ private:
|
||||
/// available
|
||||
/// @param prefix_len length of the prefix (for PD only)
|
||||
/// should be 128 for other lease types
|
||||
/// @param [out] callout_status callout returned by the lease6_select
|
||||
/// @param[out] callout_status callout returned by the lease6_select
|
||||
///
|
||||
/// The following fields of the ctx structure are used:
|
||||
/// @ref ClientContext6::subnet_ Subnet the lease is allocated from
|
||||
@ -1537,6 +1553,21 @@ public:
|
||||
/// @return unsigned integer value of the valid lifetime to use.
|
||||
static uint32_t getValidLft(const ClientContext4& ctx);
|
||||
|
||||
/// @brief Returns the valid lifetime based on the v4 context when
|
||||
/// the pool occupancy is over the adaptive lease time threshold.
|
||||
///
|
||||
/// If the client query is a BOOTP query, the value returned will
|
||||
/// be Lease::INFINITY_LFT.
|
||||
///
|
||||
/// Otherwise, as for the common case find the canndidate triplet
|
||||
/// and return the minimal value. Requested lifetime is ignored but
|
||||
/// remaining lifetime is returned when greater than minimal.
|
||||
///
|
||||
/// @param ctx Client context holding various information about the client.
|
||||
/// @param[in,out] valid set to the valid lifetime that should be used.
|
||||
/// Caller must set it to 0 or remaining value.
|
||||
static void getMinValidLft(const ClientContext4& ctx, uint32_t& valid);
|
||||
|
||||
/// @brief Returns the offer lifetime based on the v4 context
|
||||
///
|
||||
/// If the client query is a BOOTP query or something other than
|
||||
@ -1555,6 +1586,20 @@ public:
|
||||
/// @return unsigned integer value of the offer lifetime to use.
|
||||
static uint32_t getOfferLft(const ClientContext4& ctx,
|
||||
bool only_on_discover = true);
|
||||
/// @brief Set remaining valid life time.
|
||||
///
|
||||
/// @param lease A pointer to the lease.
|
||||
/// @param [out] valid The remaining valid life time or 0.
|
||||
static void getRemaining(const Lease4Ptr& lease, uint32_t& valid);
|
||||
|
||||
/// @brief Set remaining valid and preferred life times.
|
||||
///
|
||||
/// @param lease A pointer to the lease.
|
||||
/// @param [out] preferred The remaining preferred life time or 0.
|
||||
/// @param [out] valid The remaining valid life time or 0.
|
||||
static void getRemaining(const Lease6Ptr& lease, uint32_t& preferred,
|
||||
uint32_t& valid);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Offers the lease.
|
||||
|
@ -78,5 +78,18 @@ Allocator::initAfterConfigure() {
|
||||
inited_ = true;
|
||||
}
|
||||
|
||||
double
|
||||
Allocator::getOccupancyRate(const asiolink::IOAddress&,
|
||||
const ClientClasses&) const {
|
||||
return (0.);
|
||||
}
|
||||
|
||||
double
|
||||
Allocator::getOccupancyRate(const asiolink::IOAddress&,
|
||||
const uint8_t,
|
||||
const ClientClasses&) const {
|
||||
return (0.);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +140,36 @@ public:
|
||||
hint_prefix_length));
|
||||
}
|
||||
|
||||
/// @brief Returns the occupancy rate (v4 addresses).
|
||||
///
|
||||
/// The method counts the total number and the number of not free
|
||||
/// addresses in the suitable pools of the subnet, and returns the
|
||||
/// occupancy rate. If the total number of addresses is over UMAX64
|
||||
/// or the address is not from one of these pools, or by default
|
||||
/// the 0. rate is returned.
|
||||
///
|
||||
/// @param addr the address.
|
||||
/// @param client_classes list of classes client belongs to.
|
||||
virtual double
|
||||
getOccupancyRate(const asiolink::IOAddress& addr,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Returns the occupancy rate (v6 prefixes).
|
||||
///
|
||||
/// The method counts the total number and the number of not free
|
||||
/// prefixes in the suitable pools of the subnet, and returns the
|
||||
/// occupancy rate. If the total number of prefixes is over UMAX64
|
||||
/// or the prefix is not from one of these pools, or by default
|
||||
/// the 0. rate is returned.
|
||||
///
|
||||
/// @param pref the prefix.
|
||||
/// @param plen the prefix length.
|
||||
/// @param client_classes list of classes client belongs to.
|
||||
virtual double
|
||||
getOccupancyRate(const asiolink::IOAddress& pref,
|
||||
const uint8_t plen,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Check if the pool matches the selection criteria relative to the
|
||||
/// provided hint prefix length.
|
||||
///
|
||||
|
@ -61,6 +61,7 @@ CfgGlobals::nameToIndex = {
|
||||
{ "ddns-ttl-min", DDNS_TTL_MIN },
|
||||
{ "ddns-ttl-max", DDNS_TTL_MAX },
|
||||
{ "host-reservation-identifiers", HOST_RESERVATION_IDENTIFIERS },
|
||||
{ "adaptive-lease-time-threshold", ADAPTIVE_LEASE_TIME_THRESHOLD },
|
||||
|
||||
// DHCPv4 specific parameters.
|
||||
{ "echo-client-id", ECHO_CLIENT_ID },
|
||||
|
@ -84,6 +84,7 @@ public:
|
||||
DDNS_TTL_MIN,
|
||||
DDNS_TTL_MAX,
|
||||
HOST_RESERVATION_IDENTIFIERS,
|
||||
ADAPTIVE_LEASE_TIME_THRESHOLD,
|
||||
|
||||
// DHCPv4 specific parameters.
|
||||
ECHO_CLIENT_ID,
|
||||
|
@ -840,7 +840,7 @@ private:
|
||||
/// @return Collection of const @c Host objects.
|
||||
ConstHostCollection
|
||||
getAllInternal4(const SubnetID& subnet_id,
|
||||
const asiolink::IOAddress& address) const;
|
||||
const asiolink::IOAddress& address) const;
|
||||
|
||||
/// @brief Returns @c Host objects for the specified (Subnet-id,IPv6 address) tuple.
|
||||
///
|
||||
|
@ -904,7 +904,7 @@ public:
|
||||
/// @return A pointer to the unparsed configuration.
|
||||
isc::data::ElementPtr
|
||||
toElementWithMetadata(const bool include_metadata,
|
||||
CfgOptionDefPtr cfg_option_def = CfgOptionDefPtr()) const;
|
||||
CfgOptionDefPtr cfg_option_def = CfgOptionDefPtr()) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -155,7 +155,7 @@
|
||||
example: 0
|
||||
|
||||
- <b>fqdn_rev</b> - FQDN reverse DNS RR update flag \n
|
||||
type: bool (0 or 1) \n
|
||||
type: bool (0 or 1) \n
|
||||
example: 1
|
||||
|
||||
- <b>hostname</b> - hostname \n
|
||||
|
@ -53,6 +53,17 @@ PoolFreeLeaseQueueAllocationState::deleteFreeLease(const asiolink::IOAddress& ad
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PoolFreeLeaseQueueAllocationState::isFreeLease(const asiolink::IOAddress& address) const {
|
||||
if (free_lease4_queue_) {
|
||||
auto const& idx = free_lease4_queue_->get<1>();
|
||||
return (idx.count(address.toUint32()) > 0);
|
||||
} else {
|
||||
auto const& idx = free_lease6_queue_->get<1>();
|
||||
return (idx.count(address) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
IOAddress
|
||||
PoolFreeLeaseQueueAllocationState::offerFreeLease() {
|
||||
if (free_lease4_queue_) {
|
||||
@ -84,4 +95,3 @@ PoolFreeLeaseQueueAllocationState::getFreeLeaseCount() const {
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
||||
|
@ -55,6 +55,11 @@ public:
|
||||
/// @param address lease address.
|
||||
void deleteFreeLease(const asiolink::IOAddress& address);
|
||||
|
||||
/// @brief Check if a lease is in the queue.
|
||||
///
|
||||
/// @param address lease address.
|
||||
bool isFreeLease(const asiolink::IOAddress& address) const;
|
||||
|
||||
/// @brief Returns next available lease.
|
||||
///
|
||||
/// @return next free lease address or IPv4/IPv6 zero address when
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <util/stopwatch.h>
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
@ -134,6 +135,105 @@ FreeLeaseQueueAllocator::pickPrefixInternal(const ClientClasses& client_classes,
|
||||
return (IOAddress::IPV6_ZERO_ADDRESS());
|
||||
}
|
||||
|
||||
double
|
||||
FreeLeaseQueueAllocator::getOccupancyRate(const IOAddress& addr,
|
||||
const ClientClasses& client_classes) const {
|
||||
// Sanity.
|
||||
if (!addr.isV4()) {
|
||||
return (0.);
|
||||
}
|
||||
auto subnet = subnet_.lock();
|
||||
uint128_t total(0);
|
||||
uint128_t busy(0);
|
||||
bool found(false);
|
||||
|
||||
for (auto const& pool : subnet->getPools(Lease::TYPE_V4)) {
|
||||
if (!pool->clientSupported(client_classes)) {
|
||||
continue;
|
||||
}
|
||||
uint128_t capacity = pool->getCapacity();
|
||||
total += capacity;
|
||||
if (total >= std::numeric_limits<uint64_t>::max()) {
|
||||
return (0.);
|
||||
}
|
||||
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool->getAllocationState());
|
||||
if (!pool_state) {
|
||||
continue;
|
||||
}
|
||||
uint128_t free_cnt = pool_state->getFreeLeaseCount();
|
||||
if (!found && pool->inRange(addr)) {
|
||||
found = true;
|
||||
if ((free_cnt > 0) && pool_state->isFreeLease(addr)) {
|
||||
--free_cnt;
|
||||
}
|
||||
}
|
||||
if (free_cnt > capacity) {
|
||||
free_cnt = capacity;
|
||||
}
|
||||
busy += capacity - free_cnt;
|
||||
}
|
||||
if (!found) {
|
||||
return (0.);
|
||||
}
|
||||
// Should not happen...
|
||||
if (total == 0) {
|
||||
return (0.);
|
||||
}
|
||||
return (static_cast<double>(busy) / static_cast<double>(total));
|
||||
}
|
||||
|
||||
double
|
||||
FreeLeaseQueueAllocator::getOccupancyRate(const IOAddress& pref,
|
||||
const uint8_t plen,
|
||||
const ClientClasses& client_classes) const {
|
||||
// Sanity.
|
||||
if (!pref.isV6()) {
|
||||
return (0.);
|
||||
}
|
||||
auto subnet = subnet_.lock();
|
||||
uint128_t total(0);
|
||||
uint128_t busy(0);
|
||||
bool found(false);
|
||||
|
||||
for (auto const& pool : subnet->getPools(Lease::TYPE_PD)) {
|
||||
if (!pool->clientSupported(client_classes)) {
|
||||
continue;
|
||||
}
|
||||
auto const& pool6 = boost::dynamic_pointer_cast<Pool6>(pool);
|
||||
if (!pool6 || (pool6->getLength() > plen)) {
|
||||
continue;
|
||||
}
|
||||
uint128_t capacity = pool->getCapacity();
|
||||
total += capacity;
|
||||
if (total >= std::numeric_limits<uint64_t>::max()) {
|
||||
return (0.);
|
||||
}
|
||||
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool->getAllocationState());
|
||||
if (!pool_state) {
|
||||
continue;
|
||||
}
|
||||
uint128_t free_cnt = pool_state->getFreeLeaseCount();
|
||||
if (!found && pool->inRange(pref)) {
|
||||
found = true;
|
||||
if ((free_cnt > 0) && pool_state->isFreeLease(pref)) {
|
||||
--free_cnt;
|
||||
}
|
||||
}
|
||||
if (free_cnt > capacity) {
|
||||
free_cnt = capacity;
|
||||
}
|
||||
busy += capacity - free_cnt;
|
||||
}
|
||||
if (!found) {
|
||||
return (0.);
|
||||
}
|
||||
// Should not happen...
|
||||
if (total == 0) {
|
||||
return (0.);
|
||||
}
|
||||
return (static_cast<double>(busy) / static_cast<double>(total));
|
||||
}
|
||||
|
||||
void
|
||||
FreeLeaseQueueAllocator::initAfterConfigureInternal() {
|
||||
auto subnet = subnet_.lock();
|
||||
|
@ -51,6 +51,36 @@ public:
|
||||
return ("flq");
|
||||
}
|
||||
|
||||
/// @brief Returns the occupancy rate (v4 addresses).
|
||||
///
|
||||
/// The method counts the total number and the number of not free
|
||||
/// addresses in the suitable pools of the subnet, and returns the
|
||||
/// occupancy rate. If the total number of addresses is over UMAX64
|
||||
/// or the address is not from one of these pools, or by default
|
||||
/// the 0. rate is returned.
|
||||
///
|
||||
/// @param addr the address.
|
||||
/// @param client_classes list of classes client belongs to.
|
||||
virtual double
|
||||
getOccupancyRate(const asiolink::IOAddress& addr,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
/// @brief Returns the occupancy rate (v6 prefixes).
|
||||
///
|
||||
/// The method counts the total number and the number of not free
|
||||
/// prefixes in the suitable pools of the subnet, and returns the
|
||||
/// occupancy rate. If the total number of prefixes is over UMAX64
|
||||
/// or the prefix is not from one of these pools, or by default
|
||||
/// the 0. rate is returned.
|
||||
///
|
||||
/// @param pref the prefix.
|
||||
/// @param plen the prefix length.
|
||||
/// @param client_classes list of classes client belongs to.
|
||||
virtual double
|
||||
getOccupancyRate(const asiolink::IOAddress& pref,
|
||||
const uint8_t plen,
|
||||
const ClientClasses& client_classes) const;
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Performs allocator initialization after server's reconfiguration.
|
||||
|
@ -276,6 +276,11 @@ Network::toElement() const {
|
||||
map->set("allocator", Element::create(allocator_type_));
|
||||
}
|
||||
|
||||
if (!adaptive_lease_time_threshold_.unspecified()) {
|
||||
map->set("adaptive-lease-time-threshold",
|
||||
Element::create(adaptive_lease_time_threshold_));
|
||||
}
|
||||
|
||||
return (map);
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,8 @@ public:
|
||||
cache_threshold_(), cache_max_age_(), ddns_update_on_renew_(),
|
||||
ddns_conflict_resolution_mode_(), ddns_ttl_percent_(),
|
||||
ddns_ttl_(), ddns_ttl_min_(), ddns_ttl_max_(),
|
||||
allocator_type_(), default_allocator_type_() {
|
||||
allocator_type_(), default_allocator_type_(),
|
||||
adaptive_lease_time_threshold_() {
|
||||
}
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
@ -894,6 +895,25 @@ public:
|
||||
default_allocator_type_ = allocator_type;
|
||||
}
|
||||
|
||||
/// @brief Returns percentage of the adaptive lease time threshold,
|
||||
///
|
||||
/// @param inheritance inheritance mode to be used.
|
||||
util::Optional<double>
|
||||
getAdaptiveLeaseTimeThreshold(const Inheritance& inheritance = Inheritance::ALL) const {
|
||||
return (getProperty<Network>(&Network::getAdaptiveLeaseTimeThreshold,
|
||||
adaptive_lease_time_threshold_,
|
||||
inheritance,
|
||||
CfgGlobals::ADAPTIVE_LEASE_TIME_THRESHOLD));
|
||||
}
|
||||
|
||||
/// @brief Sets new percentage of the adaptive lease time threshold.
|
||||
///
|
||||
/// @param adaptive_lease_time_threshold New percentage to use.
|
||||
void setAdaptiveLeaseTimeThreshold(const util::Optional<double>&
|
||||
adaptive_lease_time_threshold) {
|
||||
adaptive_lease_time_threshold_ = adaptive_lease_time_threshold;
|
||||
}
|
||||
|
||||
/// @brief Unparses network object.
|
||||
///
|
||||
/// @return A pointer to unparsed network configuration.
|
||||
@ -1308,6 +1328,11 @@ protected:
|
||||
/// backend internally.
|
||||
util::Optional<std::string> default_allocator_type_;
|
||||
|
||||
/// @brief Percentage of the adaptive lease time threshold.
|
||||
/// (a lease assignment over the threshold will get minimal or remaining
|
||||
/// life times).
|
||||
util::Optional<double> adaptive_lease_time_threshold_;
|
||||
|
||||
/// @brief Pointer to another network that this network belongs to.
|
||||
///
|
||||
/// The most common case is that this instance is a subnet which belongs
|
||||
|
@ -17,7 +17,6 @@ using namespace isc::util;
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
|
||||
void
|
||||
BaseNetworkParser::parseCommon(const ConstElementPtr& network_data,
|
||||
NetworkPtr& network) {
|
||||
@ -171,6 +170,24 @@ BaseNetworkParser::parsePdAllocatorParams(const data::ConstElementPtr& network_d
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseNetworkParser::parseAdaptiveLeaseTimeParam(const ConstElementPtr& network_data,
|
||||
NetworkPtr& network) {
|
||||
if (network_data->contains("adaptive-lease-time-threshold")) {
|
||||
double adaptive_lease_time_threshold =
|
||||
getDouble(network_data, "adaptive-lease-time-threshold");
|
||||
if ((adaptive_lease_time_threshold <= 0.0) ||
|
||||
(adaptive_lease_time_threshold > 1.0)) {
|
||||
isc_throw(DhcpConfigError,
|
||||
"adaptive-lease-time-threshold: "
|
||||
<< adaptive_lease_time_threshold
|
||||
<< " is invalid, it must be greater than 0.0 "
|
||||
<< "and less than or equal to 1.0");
|
||||
}
|
||||
network->setAdaptiveLeaseTimeThreshold(adaptive_lease_time_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseNetworkParser::parseOfferLft(const data::ConstElementPtr& network_data,
|
||||
Network4Ptr& network) {
|
||||
@ -251,6 +268,5 @@ BaseNetworkParser::getClientClassesElem(ConstElementPtr params,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
@ -117,6 +117,21 @@ protected:
|
||||
void parsePdAllocatorParams(const data::ConstElementPtr& network_data,
|
||||
Network6Ptr& network);
|
||||
|
||||
/// @brief Parses parameter related to adaptive lease time.
|
||||
///
|
||||
/// The parsed parameter is:
|
||||
/// - adaptive-lease-time-threshold.
|
||||
///
|
||||
/// @param network_data Data element holding network configuration
|
||||
/// to be parsed.
|
||||
/// @param [out] network Pointer to a network in which parsed data is
|
||||
/// to be stored.
|
||||
///
|
||||
/// @throw DhcpConfigError if configuration of this parameter is
|
||||
/// invalid.
|
||||
void parseAdaptiveLeaseTimeParam(const data::ConstElementPtr& network_data,
|
||||
NetworkPtr& network);
|
||||
|
||||
/// @brief Parses offer-lifetime parameter (v4 only)
|
||||
///
|
||||
/// @param network_data Data element holding shared network
|
||||
|
@ -972,6 +972,9 @@ Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
|
||||
// Parse lease cache parameters
|
||||
parseCacheParams(params, network);
|
||||
|
||||
// Parse adaptive lease time parameter.
|
||||
parseAdaptiveLeaseTimeParam(params, network);
|
||||
|
||||
// Set the offer_lft value for the subnet.
|
||||
if (params->contains("offer-lifetime")) {
|
||||
uint32_t offer_lft = getInteger(params, "offer-lifetime");
|
||||
@ -1441,6 +1444,9 @@ Subnet6ConfigParser::initSubnet(data::ConstElementPtr params,
|
||||
|
||||
// Parse lease cache parameters
|
||||
parseCacheParams(params, network);
|
||||
|
||||
// Parse adaptive lease time parameter.
|
||||
parseAdaptiveLeaseTimeParam(params, network);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -189,6 +189,9 @@ SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data,
|
||||
// Parse allocator params.
|
||||
parseAllocatorParams(shared_network_data, network);
|
||||
|
||||
// Parse adaptive lease time parameter.
|
||||
parseAdaptiveLeaseTimeParam(shared_network_data, network);
|
||||
|
||||
// Parse offer-lifetime parameter.
|
||||
Network4Ptr network4 = boost::dynamic_pointer_cast<Network4>(shared_network);
|
||||
parseOfferLft(shared_network_data, network4);
|
||||
@ -368,6 +371,9 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data,
|
||||
auto network6 = boost::dynamic_pointer_cast<Network6>(shared_network);
|
||||
parsePdAllocatorParams(shared_network_data, network6);
|
||||
|
||||
// Parse adaptive lease time parameter.
|
||||
parseAdaptiveLeaseTimeParam(shared_network_data, network);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< shared_network_data->getPosition() << ")");
|
||||
|
@ -103,6 +103,7 @@ const SimpleKeywords SimpleParser4::GLOBAL4_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default global values for DHCPv4
|
||||
@ -281,6 +282,7 @@ const SimpleKeywords SimpleParser4::SUBNET4_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for each IPv4 subnet.
|
||||
@ -338,6 +340,7 @@ const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = {
|
||||
"cache-max-age",
|
||||
"allocator",
|
||||
"offer-lifetime",
|
||||
"adaptive-lease-time-threshold",
|
||||
};
|
||||
|
||||
/// @brief This table defines all pool parameters.
|
||||
@ -425,6 +428,7 @@ const SimpleKeywords SimpleParser4::SHARED_NETWORK4_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for interfaces for DHCPv4.
|
||||
|
@ -103,6 +103,7 @@ const SimpleKeywords SimpleParser6::GLOBAL6_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default global values for DHCPv6
|
||||
@ -274,6 +275,7 @@ const SimpleKeywords SimpleParser6::SUBNET6_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for each IPv6 subnet.
|
||||
@ -329,7 +331,8 @@ const ParamsList SimpleParser6::INHERIT_TO_SUBNET6 = {
|
||||
"cache-threshold",
|
||||
"cache-max-age",
|
||||
"allocator",
|
||||
"pd-allocator"
|
||||
"pd-allocator",
|
||||
"adaptive-lease-time-threshold",
|
||||
};
|
||||
|
||||
/// @brief This table defines all pool parameters.
|
||||
@ -439,6 +442,7 @@ const SimpleKeywords SimpleParser6::SHARED_NETWORK6_PARAMETERS = {
|
||||
{ "ddns-ttl", Element::integer },
|
||||
{ "ddns-ttl-min", Element::integer },
|
||||
{ "ddns-ttl-max", Element::integer },
|
||||
{ "adaptive-lease-time-threshold", Element::real },
|
||||
};
|
||||
|
||||
/// @brief This table defines default values for interfaces for DHCPv6.
|
||||
|
@ -5002,6 +5002,209 @@ TEST_F(AllocEngine4Test, getTemplateClassValidLft4) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that AllocEngine::getMinValidLft(ctx4, valid) sets the appropriate
|
||||
// lifetime value based on the context content.
|
||||
TEST_F(AllocEngine4Test, getMinValidLft4) {
|
||||
AllocEngine engine(0);
|
||||
|
||||
// Let's make three classes, two with valid-lifetime and one without,
|
||||
// and add them to the dictionary.
|
||||
ClientClassDictionaryPtr dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
|
||||
ExpressionPtr match_expr;
|
||||
ExpressionParser parser;
|
||||
|
||||
ElementPtr test_cfg = Element::create("'valid_one_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
ClientClassDefPtr class_def(new TemplateClientClassDef("valid_one", match_expr));
|
||||
Triplet<uint32_t> valid_one(50, 100, 150);
|
||||
class_def->setValid(valid_one);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'valid_two_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("valid_two", match_expr));
|
||||
Triplet<uint32_t>valid_two(200, 250, 300);
|
||||
class_def->setValid(valid_two);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'valid_unspec_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("valid_unspec", match_expr));
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
// Commit our class changes.
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Update the subnet's triplet to something more useful.
|
||||
subnet_->setValid(Triplet<uint32_t>(500, 1000, 1500));
|
||||
|
||||
// Describes a test scenario.
|
||||
struct Scenario {
|
||||
std::string desc_; // descriptive text for logging
|
||||
std::vector<std::string> classes_; // class list of assigned classes
|
||||
uint32_t requested_lft_; // use as option 51 is > 0
|
||||
uint32_t remaining_lft_; // remaining lifime or 0
|
||||
uint32_t exp_valid_; // expected lifetime
|
||||
};
|
||||
|
||||
// Scenarios to test.
|
||||
std::vector<Scenario> scenarios = {
|
||||
{
|
||||
"BOOTP",
|
||||
{ "BOOTP" },
|
||||
0,
|
||||
0,
|
||||
Lease::INFINITY_LFT
|
||||
},
|
||||
{
|
||||
"no classes, no option, remain 0",
|
||||
{},
|
||||
0,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no option, remain too small",
|
||||
{},
|
||||
0,
|
||||
100,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no option, remain",
|
||||
{},
|
||||
0,
|
||||
800,
|
||||
800
|
||||
},
|
||||
{
|
||||
"no classes, option, remain 0",
|
||||
{},
|
||||
1000,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"class unspecified, no option, remain 0",
|
||||
{ "valid_unspec" },
|
||||
0,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"from last class, no option, remain 0",
|
||||
{ "valid_unspec", "valid_one" },
|
||||
0,
|
||||
0,
|
||||
valid_one.getMin()
|
||||
},
|
||||
{
|
||||
"from first class, no option, remain 0",
|
||||
{ "valid_two", "valid_one" },
|
||||
0,
|
||||
0,
|
||||
valid_two.getMin()
|
||||
},
|
||||
{
|
||||
"class plus remain too small",
|
||||
{ "valid_one" },
|
||||
0,
|
||||
10,
|
||||
valid_one.getMin(),
|
||||
},
|
||||
{
|
||||
"class plus remain",
|
||||
{ "valid_one" },
|
||||
0,
|
||||
100,
|
||||
100
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate over the scenarios and verify the correct outcome.
|
||||
for (auto const& scenario : scenarios) {
|
||||
SCOPED_TRACE(scenario.desc_); {
|
||||
// Create a context;
|
||||
AllocEngine::ClientContext4 ctx(subnet_, ClientIdPtr(), hwaddr_,
|
||||
IOAddress("0.0.0.0"), false, false,
|
||||
"", false);
|
||||
ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
|
||||
|
||||
// Add client classes (if any)
|
||||
for (auto const& class_name : scenario.classes_) {
|
||||
if (class_name == "BOOTP") {
|
||||
ctx.query_->addClass(class_name);
|
||||
} else {
|
||||
string subclass(TemplateClientClassDef::SPAWN_CLASS_PREFIX);
|
||||
subclass += class_name;
|
||||
subclass += "_value";
|
||||
ctx.query_->addSubClass(class_name, subclass);
|
||||
}
|
||||
}
|
||||
|
||||
// Add client option (if one)
|
||||
if (scenario.requested_lft_) {
|
||||
OptionUint32Ptr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
|
||||
scenario.requested_lft_));
|
||||
ctx.query_->addOption(opt);
|
||||
}
|
||||
|
||||
uint32_t valid = scenario.remaining_lft_;
|
||||
engine.getMinValidLft(ctx, valid);
|
||||
EXPECT_EQ(valid, scenario.exp_valid_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that AllocEngine::getRemaining retuns the remaining lifetime value.
|
||||
TEST_F(AllocEngine4Test, getRemaining) {
|
||||
// No Lease.
|
||||
uint32_t valid(1);
|
||||
Lease4Ptr lease;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
|
||||
// Unexpected state.
|
||||
valid = 1;
|
||||
uint8_t hwaddr_data[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
|
||||
HWAddrPtr hwaddr(new HWAddr(hwaddr_data, sizeof(hwaddr_data), HTYPE_ETHER));
|
||||
uint8_t clientid[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
|
||||
time_t now = time(0);
|
||||
lease.reset(new Lease4(IOAddress("192.0.2.100"), hwaddr, clientid,
|
||||
sizeof(clientid), 100, now, 1));
|
||||
lease->state_ = Lease::STATE_DECLINED;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
|
||||
// Infinite lifetime.
|
||||
lease->state_ = Lease::STATE_DEFAULT;
|
||||
uint32_t infinity_lft = Lease::INFINITY_LFT;
|
||||
lease->valid_lft_ = lease->current_valid_lft_ = infinity_lft;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_EQ(infinity_lft, valid);
|
||||
|
||||
// Time going backward.
|
||||
lease->cltt_ = lease->current_cltt_ = now + 100;
|
||||
lease->valid_lft_ = lease->current_valid_lft_ = 50;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
|
||||
// Already expired.
|
||||
valid = 1;
|
||||
lease->cltt_ = lease->current_cltt_ = now - 100;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
|
||||
// Valid case.
|
||||
now = time(0);
|
||||
lease->cltt_ = lease->current_cltt_ = now - 10;
|
||||
AllocEngine::getRemaining(lease, valid);
|
||||
EXPECT_NEAR(40, valid, 1);
|
||||
}
|
||||
|
||||
// This test checks that deleteRelease handles BOOTP leases.
|
||||
TEST_F(AllocEngine4Test, bootpDelete) {
|
||||
boost::scoped_ptr<AllocEngine> engine;
|
||||
|
@ -6324,6 +6324,358 @@ TEST_F(AllocEngine6Test, getTemplateClassPreferredLifetime) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that AllocEngine::getMinLifetimes6() returns the appropriate
|
||||
// valid lifetime value based on the context content.
|
||||
TEST_F(AllocEngine6Test, getMinValidLifetime) {
|
||||
boost::scoped_ptr<AllocEngine> engine;
|
||||
ASSERT_NO_THROW(engine.reset(new AllocEngine(100)));
|
||||
ASSERT_TRUE(engine);
|
||||
|
||||
// Let's make three classes, two with valid-lifetime and one without,
|
||||
// and add them to the dictionary.
|
||||
ClientClassDictionaryPtr dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
|
||||
ExpressionPtr match_expr;
|
||||
ExpressionParser parser;
|
||||
|
||||
ElementPtr test_cfg = Element::create("'valid_one_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
ClientClassDefPtr class_def(new TemplateClientClassDef("valid_one", match_expr));
|
||||
Triplet<uint32_t> valid_one(50, 100, 150);
|
||||
class_def->setValid(valid_one);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'valid_two_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("valid_two", match_expr));
|
||||
Triplet<uint32_t>valid_two(200, 250, 300);
|
||||
class_def->setValid(valid_two);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'valid_unspec_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("valid_unspec", match_expr));
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
// Commit our class changes.
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Update the subnet's triplet to something more useful.
|
||||
subnet_->setValid(Triplet<uint32_t>(500, 1000, 1500));
|
||||
|
||||
// Describes a test scenario.
|
||||
struct Scenario {
|
||||
std::string desc_; // descriptive text for logging
|
||||
std::vector<std::string> classes_; // class list of assigned classes
|
||||
uint32_t requested_lft_; // use as option 51 is > 0
|
||||
uint32_t remaining_lft_; // remaining valid lifetime
|
||||
uint32_t exp_valid_; // expected lifetime
|
||||
};
|
||||
|
||||
// Scenarios to test.
|
||||
std::vector<Scenario> scenarios = {
|
||||
{
|
||||
"no classes, no hint, remain 0",
|
||||
{},
|
||||
0,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no hint, remain too small",
|
||||
{},
|
||||
0,
|
||||
100,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no hint, remain",
|
||||
{},
|
||||
0,
|
||||
800,
|
||||
800
|
||||
},
|
||||
{
|
||||
"no classes, hint, remain 0",
|
||||
{},
|
||||
800,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"class unspecified, no hint, remain 0",
|
||||
{ "valid_unspec" },
|
||||
0,
|
||||
0,
|
||||
subnet_->getValid().getMin()
|
||||
},
|
||||
{
|
||||
"from last class, no hint, remain 0",
|
||||
{ "valid_unspec", "valid_one" },
|
||||
0,
|
||||
0,
|
||||
valid_one.getMin()
|
||||
},
|
||||
{
|
||||
"from first class, no hint, remain 0",
|
||||
{ "valid_two", "valid_one" },
|
||||
0,
|
||||
0,
|
||||
valid_two.getMin()
|
||||
},
|
||||
{
|
||||
"class plus remain too small",
|
||||
{ "valid_one" },
|
||||
0,
|
||||
10,
|
||||
valid_one.getMin()
|
||||
},
|
||||
{
|
||||
"class plus remain",
|
||||
{ "valid_one" },
|
||||
0,
|
||||
100,
|
||||
100
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate over the scenarios and verify the correct outcome.
|
||||
for (auto const& scenario : scenarios) {
|
||||
SCOPED_TRACE(scenario.desc_); {
|
||||
// Create a context;
|
||||
AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", true,
|
||||
Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234)));
|
||||
// Add client classes (if any)
|
||||
for (auto const& class_name : scenario.classes_) {
|
||||
ctx.query_->addClass(class_name);
|
||||
}
|
||||
|
||||
// Add hint
|
||||
ctx.currentIA().iaid_ = iaid_;
|
||||
|
||||
// prefix, prefixlen, preferred, valid
|
||||
ctx.currentIA().addHint(IOAddress("::"), 128, 0, scenario.requested_lft_);
|
||||
uint32_t valid = scenario.remaining_lft_;
|
||||
uint32_t preferred = 0;
|
||||
|
||||
engine->getMinLifetimes6(ctx, preferred, valid);
|
||||
EXPECT_EQ(valid, scenario.exp_valid_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that AllocEngine::getMinLifetimes6() returns the appropriate
|
||||
// preferred lifetime value based on the context content.
|
||||
TEST_F(AllocEngine6Test, getMinPreferredLifetime) {
|
||||
boost::scoped_ptr<AllocEngine> engine;
|
||||
ASSERT_NO_THROW(engine.reset(new AllocEngine(100)));
|
||||
ASSERT_TRUE(engine);
|
||||
|
||||
// Let's make three classes, two with preferred-lifetime and one without,
|
||||
// and add them to the dictionary.
|
||||
ClientClassDictionaryPtr dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
|
||||
ExpressionPtr match_expr;
|
||||
ExpressionParser parser;
|
||||
|
||||
ElementPtr test_cfg = Element::create("'preferred_one_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
ClientClassDefPtr class_def(new TemplateClientClassDef("preferred_one", match_expr));
|
||||
Triplet<uint32_t> preferred_one(50, 100, 150);
|
||||
class_def->setPreferred(preferred_one);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'preferred_two_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("preferred_two", match_expr));
|
||||
Triplet<uint32_t>preferred_two(200, 250, 300);
|
||||
class_def->setPreferred(preferred_two);
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
test_cfg = Element::create("'preferred_unspec_value'");
|
||||
parser.parse(match_expr, test_cfg, AF_INET6, EvalContext::acceptAll, EvalContext::PARSER_STRING);
|
||||
|
||||
class_def.reset(new TemplateClientClassDef("preferred_unspec", match_expr));
|
||||
dictionary->addClass(class_def);
|
||||
|
||||
// Commit our class changes.
|
||||
CfgMgr::instance().commit();
|
||||
|
||||
// Update the subnet's triplet to something more useful. Note that
|
||||
// valid is 400 for the subnet.
|
||||
subnet_->setPreferred(Triplet<uint32_t>(300, 350, 450));
|
||||
|
||||
// Describes a test scenario.
|
||||
struct Scenario {
|
||||
std::string desc_; // descriptive text for logging
|
||||
std::vector<std::string> classes_; // class list of assigned classes
|
||||
uint32_t requested_lft_; // use as option 51 is > 0
|
||||
uint32_t remaining_lft_; // remaining preferred lifetime
|
||||
uint32_t exp_preferred_; // expected lifetime
|
||||
};
|
||||
|
||||
// Scenarios to test.
|
||||
std::vector<Scenario> scenarios = {
|
||||
{
|
||||
"no classes, no hint, remain 0",
|
||||
{},
|
||||
0,
|
||||
0,
|
||||
subnet_->getPreferred().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no hint, remain too small",
|
||||
{},
|
||||
0,
|
||||
100,
|
||||
subnet_->getPreferred().getMin()
|
||||
},
|
||||
{
|
||||
"no classes, no hint, remain",
|
||||
{},
|
||||
0,
|
||||
350,
|
||||
350
|
||||
},
|
||||
{
|
||||
"no classes, no hint, remain too big",
|
||||
{},
|
||||
0,
|
||||
500,
|
||||
subnet_->getValid().getMin() * 5 / 8
|
||||
},
|
||||
{
|
||||
"no classes, hint, remain 0",
|
||||
{},
|
||||
800,
|
||||
0,
|
||||
subnet_->getPreferred().getMin()
|
||||
},
|
||||
{
|
||||
"class unspecified, no hint, remain 0",
|
||||
{ "preferred_unspec" },
|
||||
0,
|
||||
0,
|
||||
subnet_->getPreferred().getMin()
|
||||
},
|
||||
{
|
||||
"from last class, no hint, remain 0",
|
||||
{ "preferred_unspec", "preferred_one" },
|
||||
0,
|
||||
0,
|
||||
preferred_one.getMin()
|
||||
},
|
||||
{
|
||||
"from first class, no hint, remain 0",
|
||||
{ "preferred_two", "preferred_one" },
|
||||
0,
|
||||
0,
|
||||
preferred_two.getMin()
|
||||
},
|
||||
{
|
||||
"class plus remain too small",
|
||||
{ "preferred_one" },
|
||||
0,
|
||||
10,
|
||||
preferred_one.getMin()
|
||||
},
|
||||
{
|
||||
"class plus remain",
|
||||
{ "preferred_one" },
|
||||
0,
|
||||
100,
|
||||
100
|
||||
}
|
||||
};
|
||||
|
||||
// Iterate over the scenarios and verify the correct outcome.
|
||||
for (auto const& scenario : scenarios) {
|
||||
SCOPED_TRACE(scenario.desc_); {
|
||||
// Create a context;
|
||||
AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", true,
|
||||
Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234)));
|
||||
// Add client classes (if any)
|
||||
for (auto const& class_name : scenario.classes_) {
|
||||
string subclass(TemplateClientClassDef::SPAWN_CLASS_PREFIX);
|
||||
subclass += class_name;
|
||||
subclass += "_value";
|
||||
ctx.query_->addSubClass(class_name, subclass);
|
||||
}
|
||||
|
||||
// Add hint
|
||||
ctx.currentIA().iaid_ = iaid_;
|
||||
|
||||
// prefix, prefixlen, preferred, valid
|
||||
ctx.currentIA().addHint(IOAddress("::"), 128, scenario.requested_lft_, 0);
|
||||
|
||||
uint32_t valid = 0;
|
||||
uint32_t preferred = scenario.remaining_lft_;
|
||||
|
||||
engine->getMinLifetimes6(ctx, preferred, valid);
|
||||
EXPECT_EQ(preferred, scenario.exp_preferred_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that AllocEngine::getRemaining retuns the remaining lifetime values.
|
||||
TEST_F(AllocEngine6Test, getRemaining) {
|
||||
// No Lease.
|
||||
uint32_t valid(1);
|
||||
uint32_t preferred(1);
|
||||
Lease6Ptr lease;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
EXPECT_EQ(0, preferred);
|
||||
|
||||
// Unexpected state.
|
||||
valid = 1;
|
||||
preferred = 1;
|
||||
DuidPtr duid(new DUID(vector<uint8_t>(12, 0xff)));
|
||||
const uint32_t iaid = 3568;
|
||||
time_t now = time(0);
|
||||
lease.reset(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"), duid,
|
||||
iaid, 30, 50, 1));
|
||||
lease->state_ = Lease::STATE_DECLINED;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
EXPECT_EQ(0, preferred);
|
||||
|
||||
// Time going backward.
|
||||
valid = 1;
|
||||
preferred = 1;
|
||||
lease->state_ = Lease::STATE_DEFAULT;
|
||||
lease->cltt_ = lease->current_cltt_ = now + 100;
|
||||
lease->valid_lft_ = lease->current_valid_lft_ = 50;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
EXPECT_EQ(0, preferred);
|
||||
|
||||
// Already expired.
|
||||
valid = 1;
|
||||
preferred = 1;
|
||||
lease->cltt_ = lease->current_cltt_ = now - 100;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_EQ(0, valid);
|
||||
EXPECT_EQ(0, preferred);
|
||||
|
||||
// Valid case.
|
||||
now = time(0);
|
||||
lease->cltt_ = lease->current_cltt_ = now - 10;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_NEAR(40, valid, 1);
|
||||
EXPECT_NEAR(20, preferred, 1);
|
||||
|
||||
// No longer preferred.
|
||||
now = time(0);
|
||||
lease->cltt_ = lease->current_cltt_ = now - 40;
|
||||
AllocEngine::getRemaining(lease, preferred, valid);
|
||||
EXPECT_NEAR(10, valid, 1);
|
||||
EXPECT_EQ(0, preferred);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
@ -210,6 +210,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
|
||||
network1->setHostnameCharReplacement("x");
|
||||
network1->setCacheThreshold(.20);
|
||||
network1->setOfferLft(77);
|
||||
network1->setAdaptiveLeaseTimeThreshold(.90);
|
||||
|
||||
network2->setIface("eth1");
|
||||
network2->setT1(Triplet<uint32_t>(100));
|
||||
@ -255,6 +256,7 @@ TEST(CfgSharedNetworks4Test, unparse) {
|
||||
" \"cache-max-age\": 50\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"adaptive-lease-time-threshold\": .90,\n"
|
||||
" \"calculate-tee-times\": true,\n"
|
||||
" \"ddns-generated-prefix\": \"prefix\",\n"
|
||||
" \"ddns-override-no-update\": true,\n"
|
||||
|
@ -1087,6 +1087,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
|
||||
subnet1->setT1Percent(0.45);
|
||||
subnet1->setT2Percent(0.70);
|
||||
subnet1->setCacheThreshold(0.20);
|
||||
subnet1->setAdaptiveLeaseTimeThreshold(.90);
|
||||
|
||||
subnet2->setIface("lo");
|
||||
subnet2->addRelayAddress(IOAddress("10.0.0.1"));
|
||||
@ -1146,6 +1147,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
|
||||
" \"4o6-interface\": \"\",\n"
|
||||
" \"4o6-interface-id\": \"\",\n"
|
||||
" \"4o6-subnet\": \"\",\n"
|
||||
" \"adaptive-lease-time-threshold\": .90,\n"
|
||||
" \"option-data\": [ ],\n"
|
||||
" \"pools\": [ ],\n"
|
||||
" \"user-context\": { \"comment\": \"foo\" }\n"
|
||||
@ -1821,6 +1823,10 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
|
||||
{"too big", 1.05,
|
||||
"subnet configuration failed: cache-threshold:"
|
||||
" 1.05 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
|
||||
},
|
||||
{"excluded", 1.0,
|
||||
"subnet configuration failed: cache-threshold:"
|
||||
" 1 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
|
||||
}
|
||||
};
|
||||
|
||||
@ -1849,7 +1855,6 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
|
||||
" \"4o6-subnet\": \"\" \n"
|
||||
" }";
|
||||
|
||||
|
||||
data::ElementPtr elems;
|
||||
ASSERT_NO_THROW(elems = data::Element::fromJSON(json))
|
||||
<< "invalid JSON:" << json << "\n test is broken";
|
||||
@ -1887,6 +1892,99 @@ TEST(CfgSubnets4Test, cacheParamValidation) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies the Subnet4 parser's validation logic for
|
||||
// adaptive lease time parameter.
|
||||
TEST(CfgSubnets4Test, adaptiveLeaseTimeParamValidation) {
|
||||
|
||||
// Describes a single test scenario.
|
||||
struct Scenario {
|
||||
std::string label; // label used for logging test failures
|
||||
double threshold; // value of adaptive-lease-time-threshold
|
||||
std::string error_message; // expected error message is parsing should fail
|
||||
};
|
||||
|
||||
// Test Scenarios.
|
||||
std::vector<Scenario> tests = {
|
||||
{"valid", .25, ""},
|
||||
{"valid", 1.0, ""},
|
||||
{"negative", -.25,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" -0.25 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
},
|
||||
{"excluded", 0.,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" 0 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
},
|
||||
{"too big", 1.05,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" 1.05 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
}
|
||||
};
|
||||
|
||||
// First we create a set of elements that provides all
|
||||
// required for a Subnet4.
|
||||
std::string json =
|
||||
" {"
|
||||
" \"id\": 1,\n"
|
||||
" \"subnet\": \"10.1.2.0/24\", \n"
|
||||
" \"interface\": \"\", \n"
|
||||
" \"renew-timer\": 100, \n"
|
||||
" \"rebind-timer\": 200, \n"
|
||||
" \"valid-lifetime\": 300, \n"
|
||||
" \"match-client-id\": false, \n"
|
||||
" \"authoritative\": false, \n"
|
||||
" \"next-server\": \"\", \n"
|
||||
" \"server-hostname\": \"\", \n"
|
||||
" \"boot-file-name\": \"\", \n"
|
||||
" \"client-classes\": [], \n"
|
||||
" \"evaluate-additional-classes\": [], \n"
|
||||
" \"reservations-global\": false, \n"
|
||||
" \"reservations-in-subnet\": true, \n"
|
||||
" \"reservations-out-of-pool\": false, \n"
|
||||
" \"4o6-interface\": \"\", \n"
|
||||
" \"4o6-interface-id\": \"\", \n"
|
||||
" \"4o6-subnet\": \"\" \n"
|
||||
" }";
|
||||
|
||||
data::ElementPtr elems;
|
||||
ASSERT_NO_THROW(elems = data::Element::fromJSON(json))
|
||||
<< "invalid JSON:" << json << "\n test is broken";
|
||||
|
||||
// Iterate over the test scenarios, verifying each prescribed
|
||||
// outcome.
|
||||
for (auto const& test : tests) {
|
||||
{
|
||||
SCOPED_TRACE("test: " + test.label);
|
||||
|
||||
// Set this scenario's configuration parameters
|
||||
elems->set("adaptive-lease-time-threshold",
|
||||
data::Element::create(test.threshold));
|
||||
|
||||
Subnet4Ptr subnet;
|
||||
try {
|
||||
// Attempt to parse the configuration.
|
||||
Subnet4ConfigParser parser;
|
||||
subnet = parser.parse(elems);
|
||||
} catch (const std::exception& ex) {
|
||||
if (!test.error_message.empty()) {
|
||||
// We expected a failure, did we fail the correct way?
|
||||
EXPECT_EQ(test.error_message, ex.what());
|
||||
} else {
|
||||
// Should not have failed.
|
||||
ADD_FAILURE() << "Scenario should not have failed: " << ex.what();
|
||||
}
|
||||
|
||||
// Either way we're done with this scenario.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We parsed correctly, make sure the values are right.
|
||||
EXPECT_TRUE(util::areDoublesEquivalent(test.threshold,
|
||||
subnet->getAdaptiveLeaseTimeThreshold()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the optional interface check works as expected.
|
||||
TEST(CfgSubnets4Test, iface) {
|
||||
// Create a configuration.
|
||||
|
@ -684,6 +684,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
|
||||
subnet1->setT1Percent(0.45);
|
||||
subnet1->setT2Percent(0.70);
|
||||
subnet1->setCacheThreshold(0.20);
|
||||
subnet1->setAdaptiveLeaseTimeThreshold(.90);
|
||||
|
||||
subnet2->setIface("lo");
|
||||
subnet2->addRelayAddress(IOAddress("2001:db8:ff::2"));
|
||||
@ -740,6 +741,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
|
||||
" \"valid-lifetime\": 4,\n"
|
||||
" \"min-valid-lifetime\": 4,\n"
|
||||
" \"max-valid-lifetime\": 4,\n"
|
||||
" \"adaptive-lease-time-threshold\": .90,\n"
|
||||
" \"client-classes\": [ \"foo\", \"bar\" ],\n"
|
||||
" \"pools\": [ ],\n"
|
||||
" \"pd-pools\": [ ],\n"
|
||||
@ -1610,6 +1612,10 @@ TEST(CfgSubnets6Test, cacheParamValidation) {
|
||||
{"too big", 1.05,
|
||||
"subnet configuration failed: cache-threshold:"
|
||||
" 1.05 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
|
||||
},
|
||||
{"excluded", 1.0,
|
||||
"subnet configuration failed: cache-threshold:"
|
||||
" 1 is invalid, it must be greater than or equal to 0.0 and less than 1.0"
|
||||
}
|
||||
};
|
||||
|
||||
@ -1667,6 +1673,91 @@ TEST(CfgSubnets6Test, cacheParamValidation) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies the Subnet6 parser's validation logic for
|
||||
// adaptive lease time parameter.
|
||||
TEST(CfgSubnets6Test, adaptiveLeaseTimeParamValidation) {
|
||||
|
||||
// Describes a single test scenario.
|
||||
struct Scenario {
|
||||
std::string label; // label used for logging test failures
|
||||
double threshold; // value of adaptive-lease-time-threshold
|
||||
std::string error_message; // expected error message is parsing should fail
|
||||
};
|
||||
|
||||
// Test Scenarios.
|
||||
std::vector<Scenario> tests = {
|
||||
{"valid", .25, ""},
|
||||
{"valid", 1.0, ""},
|
||||
{"negative", -.25,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" -0.25 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
},
|
||||
{"excluded", 0.,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" 0 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
},
|
||||
{"too big", 1.05,
|
||||
"subnet configuration failed: adaptive-lease-time-threshold:"
|
||||
" 1.05 is invalid, it must be greater than 0.0 and less than or equal to 1.0"
|
||||
}
|
||||
};
|
||||
|
||||
// First we create a set of elements that provides all
|
||||
// required for a Subnet6.
|
||||
std::string json =
|
||||
" {"
|
||||
" \"id\": 1,\n"
|
||||
" \"subnet\": \"2001:db8:1::/64\", \n"
|
||||
" \"interface\": \"\", \n"
|
||||
" \"renew-timer\": 100, \n"
|
||||
" \"rebind-timer\": 200, \n"
|
||||
" \"valid-lifetime\": 300, \n"
|
||||
" \"client-classes\": [], \n"
|
||||
" \"evaluate-additional-classes\": [], \n"
|
||||
" \"reservations-global\": false, \n"
|
||||
" \"reservations-in-subnet\": true, \n"
|
||||
" \"reservations-out-of-pool\": false \n"
|
||||
" }";
|
||||
|
||||
data::ElementPtr elems;
|
||||
ASSERT_NO_THROW(elems = data::Element::fromJSON(json))
|
||||
<< "invalid JSON:" << json << "\n test is broken";
|
||||
|
||||
// Iterate over the test scenarios, verifying each prescribed
|
||||
// outcome.
|
||||
for (auto const& test : tests) {
|
||||
{
|
||||
SCOPED_TRACE("test: " + test.label);
|
||||
|
||||
// Set this scenario's configuration parameters
|
||||
elems->set("adaptive-lease-time-threshold",
|
||||
data::Element::create(test.threshold));
|
||||
|
||||
Subnet6Ptr subnet;
|
||||
try {
|
||||
// Attempt to parse the configuration.
|
||||
Subnet6ConfigParser parser;
|
||||
subnet = parser.parse(elems);
|
||||
} catch (const std::exception& ex) {
|
||||
if (!test.error_message.empty()) {
|
||||
// We expected a failure, did we fail the correct way?
|
||||
EXPECT_EQ(test.error_message, ex.what());
|
||||
} else {
|
||||
// Should not have failed.
|
||||
ADD_FAILURE() << "Scenario should not have failed: " << ex.what();
|
||||
}
|
||||
|
||||
// Either way we're done with this scenario.
|
||||
continue;
|
||||
}
|
||||
|
||||
// We parsed correctly, make sure the values are right.
|
||||
EXPECT_TRUE(util::areDoublesEquivalent(test.threshold,
|
||||
subnet->getAdaptiveLeaseTimeThreshold()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the optional interface check works as expected.
|
||||
TEST(CfgSubnets6Test, iface) {
|
||||
// Create a configuration.
|
||||
|
@ -78,157 +78,157 @@ public:
|
||||
// Verifies valid permutations of ddns-ttl-percent, ddns-ttl,
|
||||
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
|
||||
template<typename ParserType, typename NetworkPtrType>
|
||||
void validDdnsTtlParmatersSubnet(int family) {
|
||||
struct Scenario {
|
||||
size_t line_no_;
|
||||
std::string json_;
|
||||
double ddns_ttl_percent_;
|
||||
uint32_t ddns_ttl_;
|
||||
uint32_t ddns_ttl_min_;
|
||||
uint32_t ddns_ttl_max_;
|
||||
};
|
||||
void validDdnsTtlParmatersSubnet(int family) {
|
||||
struct Scenario {
|
||||
size_t line_no_;
|
||||
std::string json_;
|
||||
double ddns_ttl_percent_;
|
||||
uint32_t ddns_ttl_;
|
||||
uint32_t ddns_ttl_min_;
|
||||
uint32_t ddns_ttl_max_;
|
||||
};
|
||||
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100
|
||||
})^",
|
||||
0.0, 100, 0, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-percent": 5.0
|
||||
})^",
|
||||
5.0, 0, 0, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 25
|
||||
})^",
|
||||
0.0, 0, 25, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
0.0, 0, 0, 150
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 25,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
0.0, 0, 25, 150
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1, "subnet": "192.0.2.0/24",
|
||||
"ddns-ttl-percent": 5.0,
|
||||
"ddns-ttl-min": 25,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
5.0, 0, 25, 150
|
||||
}};
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100
|
||||
})^",
|
||||
0.0, 100, 0, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-percent": 5.0
|
||||
})^",
|
||||
5.0, 0, 0, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 25
|
||||
})^",
|
||||
0.0, 0, 25, 0
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
0.0, 0, 0, 150
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 25,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
0.0, 0, 25, 150
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1, "subnet": "192.0.2.0/24",
|
||||
"ddns-ttl-percent": 5.0,
|
||||
"ddns-ttl-min": 25,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
5.0, 0, 25, 150
|
||||
}};
|
||||
|
||||
ElementPtr subnet_elem = Element::create(family == AF_INET ?
|
||||
"192.0.2.0/24" : "2001:db8::/64");
|
||||
for (const auto& scenario : scenarios) {
|
||||
std::stringstream oss;
|
||||
oss << "scenario at " << scenario.line_no_;
|
||||
SCOPED_TRACE(oss.str());
|
||||
for (const auto& scenario : scenarios) {
|
||||
std::stringstream oss;
|
||||
oss << "scenario at " << scenario.line_no_;
|
||||
SCOPED_TRACE(oss.str());
|
||||
|
||||
// Parse configuration specified above.
|
||||
ElementPtr config_element;
|
||||
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
|
||||
// Parse configuration specified above.
|
||||
ElementPtr config_element;
|
||||
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
|
||||
config_element->set("subnet", subnet_elem);
|
||||
|
||||
ParserType parser(family);
|
||||
ParserType parser(family);
|
||||
|
||||
NetworkPtrType subnet;
|
||||
NetworkPtrType subnet;
|
||||
|
||||
ASSERT_NO_THROW_LOG(subnet = parser.parse(config_element));
|
||||
ASSERT_TRUE(subnet);
|
||||
ASSERT_NO_THROW_LOG(subnet = parser.parse(config_element));
|
||||
ASSERT_TRUE(subnet);
|
||||
|
||||
EXPECT_EQ(subnet->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
|
||||
EXPECT_EQ(subnet->getDdnsTtlPercent().unspecified(), (scenario.ddns_ttl_percent_ == 0.0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlPercent(), scenario.ddns_ttl_percent_);
|
||||
|
||||
EXPECT_EQ(subnet->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtl(), scenario.ddns_ttl_);
|
||||
EXPECT_EQ(subnet->getDdnsTtl().unspecified(), (scenario.ddns_ttl_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtl(), scenario.ddns_ttl_);
|
||||
|
||||
EXPECT_EQ(subnet->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlMin(), scenario.ddns_ttl_min_);
|
||||
EXPECT_EQ(subnet->getDdnsTtlMin().unspecified(), (scenario.ddns_ttl_min_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlMin(), scenario.ddns_ttl_min_);
|
||||
|
||||
EXPECT_EQ(subnet->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlMax(), scenario.ddns_ttl_max_);
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(subnet->getDdnsTtlMax().unspecified(), (scenario.ddns_ttl_max_ == 0));
|
||||
EXPECT_EQ(subnet->getDdnsTtlMax(), scenario.ddns_ttl_max_);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies invalid permutations of ddns-ttl-percent, ddns-ttl,
|
||||
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
|
||||
// Verifies invalid permutations of ddns-ttl-percent, ddns-ttl,
|
||||
// ddns-ttl-min, and ddns-ttl-max values for SubnetX.
|
||||
template<typename ParserType>
|
||||
void invalidDdnsTtlParmatersSubnet(int family) {
|
||||
struct Scenario {
|
||||
size_t line_no_;
|
||||
std::string json_;
|
||||
std::string exp_message_;
|
||||
};
|
||||
void invalidDdnsTtlParmatersSubnet(int family) {
|
||||
struct Scenario {
|
||||
size_t line_no_;
|
||||
std::string json_;
|
||||
std::string exp_message_;
|
||||
};
|
||||
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-percent": 5.0,
|
||||
"ddns-ttl": 100
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-percent and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100,
|
||||
"ddns-ttl-min": 25
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-min and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-max and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 150,
|
||||
"ddns-ttl-max": 25
|
||||
})^",
|
||||
"subnet configuration failed: ddns-ttl-max: 25 must be greater than ddns-ttl-min: 150"
|
||||
}};
|
||||
std::list<Scenario> scenarios = {
|
||||
{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-percent": 5.0,
|
||||
"ddns-ttl": 100
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-percent and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100,
|
||||
"ddns-ttl-min": 25
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-min and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl": 100,
|
||||
"ddns-ttl-max": 150
|
||||
})^",
|
||||
"subnet configuration failed: cannot specify both ddns-ttl-max and ddns-ttl"
|
||||
},{
|
||||
__LINE__,
|
||||
R"^({
|
||||
"id": 1,
|
||||
"ddns-ttl-min": 150,
|
||||
"ddns-ttl-max": 25
|
||||
})^",
|
||||
"subnet configuration failed: ddns-ttl-max: 25 must be greater than ddns-ttl-min: 150"
|
||||
}};
|
||||
|
||||
ElementPtr subnet_elem = Element::create(family == AF_INET ?
|
||||
"192.0.2.0/24" : "2001:db8::/64");
|
||||
for (const auto& scenario : scenarios) {
|
||||
std::stringstream oss;
|
||||
oss << "scenario at " << scenario.line_no_;
|
||||
SCOPED_TRACE(oss.str());
|
||||
for (const auto& scenario : scenarios) {
|
||||
std::stringstream oss;
|
||||
oss << "scenario at " << scenario.line_no_;
|
||||
SCOPED_TRACE(oss.str());
|
||||
|
||||
// Parse configuration specified above.
|
||||
ElementPtr config_element;
|
||||
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
|
||||
// Parse configuration specified above.
|
||||
ElementPtr config_element;
|
||||
ASSERT_NO_THROW_LOG(config_element = Element::fromJSON(scenario.json_));
|
||||
config_element->set("subnet", subnet_elem);
|
||||
ParserType parser(family);
|
||||
ASSERT_THROW_MSG(parser.parse(config_element), DhcpConfigError, scenario.exp_message_);
|
||||
}
|
||||
}
|
||||
ParserType parser(family);
|
||||
ASSERT_THROW_MSG(parser.parse(config_element), DhcpConfigError, scenario.exp_message_);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Tests valid DDNS parameters in v4 or v6 pools.
|
||||
///
|
||||
@ -241,7 +241,7 @@ public:
|
||||
/// @param pool1 string pool specification for the first pool
|
||||
/// @param pool2 string pool specification for the first pool
|
||||
template<typename PoolListParserType>
|
||||
void validPoolDdnsParameters(const std::string& pool1, const std::string& pool2) {
|
||||
void validPoolDdnsParameters(const std::string& pool1, const std::string& pool2) {
|
||||
std::stringstream ss;
|
||||
|
||||
ss <<
|
||||
@ -456,8 +456,8 @@ public:
|
||||
/// @brief Sets the Hooks path from which hooks can be loaded.
|
||||
/// @param custom_path path to use as the hooks path.
|
||||
void setHooksTestPath(const std::string explicit_path = "") {
|
||||
HooksLibrariesParser::getHooksPath(true,
|
||||
(!explicit_path.empty() ?
|
||||
HooksLibrariesParser::getHooksPath(true,
|
||||
(!explicit_path.empty() ?
|
||||
explicit_path : DHCPSRV_HOOKS_TEST_PATH));
|
||||
}
|
||||
|
||||
@ -4472,12 +4472,12 @@ TEST_F(DhcpParserTest, invalidDdnsTtlParmatersSubnet6) {
|
||||
|
||||
// Verifies valid DDNS parameters in v4 pools.
|
||||
TEST_F(DhcpParserTest, validDdnsParmatersPool4) {
|
||||
validPoolDdnsParameters<Pools4ListParser>("192.0.1.0/24", "192.0.2.0/24");
|
||||
validPoolDdnsParameters<Pools4ListParser>("192.0.1.0/24", "192.0.2.0/24");
|
||||
}
|
||||
|
||||
// Verifies valid DDNS parameters in v6 pools.
|
||||
TEST_F(DhcpParserTest, validDdnsParmatersPool6) {
|
||||
validPoolDdnsParameters<Pools6ListParser>("2001:db8:1::/64", "2001:db8:2::/64");
|
||||
validPoolDdnsParameters<Pools6ListParser>("2001:db8:1::/64", "2001:db8:2::/64");
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
@ -39,12 +39,15 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeaseV4) {
|
||||
|
||||
// Add the first free lease. The pool should now have one free lease
|
||||
// that is always offered.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("192.0.2.1")));
|
||||
state->addFreeLease(IOAddress("192.0.2.1"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(1, state->getFreeLeaseCount());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("192.0.2.1")));
|
||||
// The same lease is always offered.
|
||||
EXPECT_EQ("192.0.2.1", state->offerFreeLease().toText());
|
||||
EXPECT_EQ("192.0.2.1", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("192.0.2.1")));
|
||||
|
||||
// Add another free lease. We should now have two free leases.
|
||||
state->addFreeLease(IOAddress("192.0.2.3"));
|
||||
@ -55,9 +58,12 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeaseV4) {
|
||||
EXPECT_EQ("192.0.2.1", state->offerFreeLease().toText());
|
||||
// Now, the second lease should be offered.
|
||||
EXPECT_EQ("192.0.2.3", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("192.0.2.1")));
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("192.0.2.3")));
|
||||
|
||||
// Try to delete a non-existing lease. It should not affect the
|
||||
// existing leases.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("192.0.2.2")));
|
||||
state->deleteFreeLease(IOAddress("192.0.2.2"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(2, state->getFreeLeaseCount());
|
||||
@ -126,12 +132,15 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeaseNA) {
|
||||
|
||||
// Add the first free lease. The pool should now have one free lease
|
||||
// that is always offered.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("2001:db8:1::1")));
|
||||
state->addFreeLease(IOAddress("2001:db8:1::1"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(1, state->getFreeLeaseCount());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("2001:db8:1::1")));
|
||||
// The same lease is always offered.
|
||||
EXPECT_EQ("2001:db8:1::1", state->offerFreeLease().toText());
|
||||
EXPECT_EQ("2001:db8:1::1", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("2001:db8:1::1")));
|
||||
|
||||
// Add another free lease. We should now have two free leases.
|
||||
state->addFreeLease(IOAddress("2001:db8:1::3"));
|
||||
@ -142,9 +151,12 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeaseNA) {
|
||||
EXPECT_EQ("2001:db8:1::1", state->offerFreeLease().toText());
|
||||
// Now, the second lease should be offered.
|
||||
EXPECT_EQ("2001:db8:1::3", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("2001:db8:1::1")));
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("2001:db8:1::3")));
|
||||
|
||||
// Try to delete a non-existing lease. It should not affect the
|
||||
// existing leases.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("2001:db8:1::2")));
|
||||
state->deleteFreeLease(IOAddress("2001:db8:1::2"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(2, state->getFreeLeaseCount());
|
||||
@ -211,11 +223,15 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeasePD) {
|
||||
|
||||
// Add the first free lease. The pool should now have one free lease
|
||||
// that is always offered.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("3000::5600")));
|
||||
state->addFreeLease(IOAddress("3000::5600"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(1, state->getFreeLeaseCount());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("3000::5600")));
|
||||
// The same lease is always offered.
|
||||
EXPECT_EQ("3000::5600", state->offerFreeLease().toText());
|
||||
EXPECT_EQ("3000::5600", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("3000::5600")));
|
||||
|
||||
// Add another free lease. We should now have two free leases.
|
||||
state->addFreeLease(IOAddress("3000::7800"));
|
||||
@ -226,9 +242,12 @@ TEST(PoolFreeLeaseAllocationState, addDeleteFreeLeasePD) {
|
||||
EXPECT_EQ("3000::5600", state->offerFreeLease().toText());
|
||||
// Now, the second lease should be offered.
|
||||
EXPECT_EQ("3000::7800", state->offerFreeLease().toText());
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("3000::5600")));
|
||||
EXPECT_TRUE(state->isFreeLease(IOAddress("3000::7800")));
|
||||
|
||||
// Try to delete a non-existing lease. It should not affect the
|
||||
// existing leases.
|
||||
EXPECT_FALSE(state->isFreeLease(IOAddress("3000::6400")));
|
||||
state->deleteFreeLease(IOAddress("3000::6400"));
|
||||
EXPECT_FALSE(state->exhausted());
|
||||
EXPECT_EQ(2, state->getFreeLeaseCount());
|
||||
@ -274,5 +293,4 @@ TEST(PoolFreeLeaseAllocationState, addFreeLeasPDSeveralTimes) {
|
||||
EXPECT_TRUE(state->exhausted());
|
||||
}
|
||||
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
@ -65,6 +65,11 @@ TEST_F(FreeLeaseQueueAllocatorTest4, populateFreeAddressLeases) {
|
||||
ASSERT_TRUE(pool_state);
|
||||
EXPECT_FALSE(pool_state->exhausted());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.101"), cc_);
|
||||
EXPECT_EQ(.6, r);
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.1"), cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
|
||||
std::set<IOAddress> addresses;
|
||||
for (auto i = 0; i < 5; ++i) {
|
||||
auto lease = pool_state->offerFreeLease();
|
||||
@ -124,6 +129,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithAllocations) {
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
auto i = 0;
|
||||
for (auto const& address_lease : leases) {
|
||||
if (i % 2) {
|
||||
@ -132,6 +140,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithAllocations) {
|
||||
++i;
|
||||
}
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(.5, r);
|
||||
|
||||
for (auto j = 0; j < 5; ++j) {
|
||||
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
|
||||
@ -142,6 +153,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithAllocations) {
|
||||
|
||||
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating IPv4 addresses and re-allocating these that are
|
||||
@ -170,6 +184,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithReclamations) {
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
auto i = 0;
|
||||
for (auto const& address_lease : leases) {
|
||||
if (i % 2) {
|
||||
@ -179,6 +196,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithReclamations) {
|
||||
}
|
||||
++i;
|
||||
}
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(.5, r);
|
||||
|
||||
for (auto j = 0; j < 5; ++j) {
|
||||
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
|
||||
@ -187,9 +207,11 @@ TEST_F(FreeLeaseQueueAllocatorTest4, singlePoolWithReclamations) {
|
||||
lease->state_ = Lease::STATE_DEFAULT;
|
||||
EXPECT_NO_THROW(lease_mgr.updateLease4(lease));
|
||||
}
|
||||
|
||||
candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating DHCPv4 leases for many pools in a subnet.
|
||||
@ -213,6 +235,10 @@ TEST_F(FreeLeaseQueueAllocatorTest4, manyPools) {
|
||||
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
// 1/100
|
||||
EXPECT_EQ(.01, r);
|
||||
|
||||
std::set<IOAddress> addresses_set;
|
||||
std::vector<IOAddress> addresses_vector;
|
||||
std::vector<PoolPtr> pools_vector;
|
||||
@ -232,6 +258,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, manyPools) {
|
||||
// Make sure that unique addresses have been returned.
|
||||
EXPECT_EQ(total, addresses_set.size());
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
// Verify that the addresses are returned in the random order.
|
||||
// Count how many times we found consecutive addresses. It should
|
||||
// be 0 or close to 0.
|
||||
@ -263,12 +292,16 @@ TEST_F(FreeLeaseQueueAllocatorTest4, manyPools) {
|
||||
// Test that the allocator returns a zero address when there are no pools
|
||||
// in a subnet.
|
||||
TEST_F(FreeLeaseQueueAllocatorTest4, noPools) {
|
||||
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
|
||||
FreeLeaseQueueAllocator alloc(Lease::TYPE_V4, subnet_);
|
||||
|
||||
subnet_->delPools(Lease::TYPE_V4);
|
||||
subnet_->delPools(Lease::TYPE_V4);
|
||||
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
|
||||
// rate is 0. because of the address can't be found, not from 0./0....
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
}
|
||||
|
||||
// Test that the allocator respects client class guards.
|
||||
@ -304,6 +337,9 @@ TEST_F(FreeLeaseQueueAllocatorTest4, clientClasses) {
|
||||
|
||||
// Simulate client's request belonging to the class bar.
|
||||
cc_.insert("bar");
|
||||
double r = alloc.getOccupancyRate(IOAddress("192.0.2.120"), cc_);
|
||||
// 1/20
|
||||
EXPECT_EQ(.05, r);
|
||||
for (auto i = 0; i < 20; ++i) {
|
||||
// Allocate random addresses and make sure they belong to the
|
||||
// pools associated with the class bar.
|
||||
@ -315,11 +351,17 @@ TEST_F(FreeLeaseQueueAllocatorTest4, clientClasses) {
|
||||
}
|
||||
EXPECT_EQ(20, addresses_set.size());
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.120"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
addresses_set.clear();
|
||||
|
||||
// Simulate the case that the client also belongs to the class foo.
|
||||
// All pools should now be available.
|
||||
cc_.insert("foo");
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
// 21/40
|
||||
EXPECT_EQ(.525, r);
|
||||
for (auto i = 0; i < 20; ++i) {
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
addresses_set.insert(candidate);
|
||||
@ -327,12 +369,16 @@ TEST_F(FreeLeaseQueueAllocatorTest4, clientClasses) {
|
||||
EXPECT_TRUE(subnet_->inRange(candidate));
|
||||
}
|
||||
EXPECT_EQ(20, addresses_set.size());
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
// When the client does not belong to any client class the allocator
|
||||
// can't offer any address to the client.
|
||||
cc_.clear();
|
||||
IOAddress candidate = alloc.pickAddress(cc_, clientid_, IOAddress("0.0.0.0"));
|
||||
EXPECT_TRUE(candidate.isV4Zero());
|
||||
r = alloc.getOccupancyRate(IOAddress("192.0.2.100"), cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
}
|
||||
|
||||
/// @brief Test fixture class for the DHCPv6 Free Lease Queue allocator.
|
||||
@ -382,6 +428,10 @@ TEST_F(FreeLeaseQueueAllocatorTest6, populateFreeAddressLeases) {
|
||||
|
||||
EXPECT_NO_THROW(alloc.initAfterConfigure());
|
||||
|
||||
// Address getOccupancyRate is for IPv4 only.
|
||||
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1::10"), cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
|
||||
auto pool_state = boost::dynamic_pointer_cast<PoolFreeLeaseQueueAllocationState>(pool_->getAllocationState());
|
||||
ASSERT_TRUE(pool_state);
|
||||
EXPECT_FALSE(pool_state->exhausted());
|
||||
@ -461,7 +511,7 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePoolWithAllocations) {
|
||||
}
|
||||
|
||||
for (auto j = 0; j < 8; ++j) {
|
||||
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
|
||||
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
|
||||
auto lease = createLease6(Lease::TYPE_NA, candidate, i);
|
||||
@ -509,7 +559,7 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePoolWithReclamations) {
|
||||
}
|
||||
|
||||
for (auto j = 0; j < 8; ++j) {
|
||||
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
|
||||
candidate = alloc.pickAddress(cc_, duid_, IOAddress("::"));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
|
||||
EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_));
|
||||
auto lease = lease_mgr.getLease6(Lease::TYPE_NA, candidate);
|
||||
@ -686,6 +736,9 @@ TEST_F(FreeLeaseQueueAllocatorTest6, populateFreePrefixDelegationLeases) {
|
||||
ASSERT_TRUE(pool_state);
|
||||
EXPECT_FALSE(pool_state->exhausted());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("2001:db8:2::"), 128, cc_);
|
||||
EXPECT_EQ(5. / 256., r);
|
||||
|
||||
std::set<IOAddress> addresses;
|
||||
for (auto i = 0; i < 256; ++i) {
|
||||
auto lease = pool_state->offerFreeLease();
|
||||
@ -721,9 +774,12 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPool) {
|
||||
}
|
||||
// The pool comprises 65536 prefixes. All should be returned.
|
||||
EXPECT_EQ(65536, prefixes.size());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating IPv6 addresses and re-allocating these that are
|
||||
// Test allocating delegated prefixes and re-allocating these that are
|
||||
// deleted (released).
|
||||
TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithAllocations) {
|
||||
// Remove the default pool because it is too large for this test case.
|
||||
@ -757,6 +813,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithAllocations) {
|
||||
|
||||
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
EXPECT_TRUE(candidate.isV6Zero());
|
||||
double r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
auto i = 0;
|
||||
for (auto const& address_lease : leases) {
|
||||
@ -765,6 +823,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithAllocations) {
|
||||
}
|
||||
++i;
|
||||
}
|
||||
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(.5, r);
|
||||
|
||||
for (auto j = 0; j < 128; ++j) {
|
||||
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
@ -776,9 +836,12 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithAllocations) {
|
||||
|
||||
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
EXPECT_TRUE(candidate.isV6Zero());
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating IPv6 addresses and re-allocating these that are
|
||||
// Test allocating delegated prefixes and re-allocating these that are
|
||||
// reclaimed.
|
||||
TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithReclamations) {
|
||||
// Remove the default pool because it is too large for this test case.
|
||||
@ -812,6 +875,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithReclamations) {
|
||||
|
||||
IOAddress candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
EXPECT_TRUE(candidate.isV6Zero());
|
||||
double r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
|
||||
auto i = 0;
|
||||
for (auto const& address_lease : leases) {
|
||||
@ -822,6 +887,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithReclamations) {
|
||||
}
|
||||
++i;
|
||||
}
|
||||
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(.5, r);
|
||||
|
||||
for (auto j = 0; j < 128; ++j) {
|
||||
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
@ -834,8 +901,10 @@ TEST_F(FreeLeaseQueueAllocatorTest6, singlePdPoolWithReclamations) {
|
||||
|
||||
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 0);
|
||||
EXPECT_TRUE(candidate.isV6Zero());
|
||||
}
|
||||
|
||||
r = alloc.getOccupancyRate(IOAddress("3000::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating delegated prefixes from multiple pools.
|
||||
TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPools) {
|
||||
@ -869,6 +938,9 @@ TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPools) {
|
||||
}
|
||||
// Make sure that unique prefixes have been returned.
|
||||
EXPECT_EQ(total, prefixes.size());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
}
|
||||
|
||||
// Test allocating delegated prefixes from multiple pools.
|
||||
@ -890,7 +962,6 @@ TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferLower) {
|
||||
ASSERT_NO_THROW(alloc.initAfterConfigure());
|
||||
auto& lease_mgr = LeaseMgrFactory::instance();
|
||||
|
||||
|
||||
Pool6Ptr pool;
|
||||
|
||||
std::set<IOAddress> prefixes;
|
||||
@ -904,6 +975,13 @@ TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferLower) {
|
||||
}
|
||||
// Make sure that unique prefixes have been returned.
|
||||
EXPECT_EQ(total, prefixes.size());
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 120, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 128, cc_);
|
||||
EXPECT_EQ(65536. / 68096., r);
|
||||
r = alloc.getOccupancyRate(IOAddress("2001:db8:1:2::"), 64, cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
}
|
||||
|
||||
// Test allocating delegated prefixes from multiple pools.
|
||||
@ -938,6 +1016,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferEqual) {
|
||||
}
|
||||
// Make sure that unique prefixes have been returned.
|
||||
EXPECT_EQ(total, prefixes.size());
|
||||
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
|
||||
EXPECT_EQ(2560. / 68096., r);
|
||||
}
|
||||
|
||||
// Test allocating delegated prefixes from multiple pools.
|
||||
@ -972,6 +1052,8 @@ TEST_F(FreeLeaseQueueAllocatorTest6, manyPdPoolsPreferHigher) {
|
||||
}
|
||||
// Make sure that unique prefixes have been returned.
|
||||
EXPECT_EQ(total, prefixes.size());
|
||||
double r = alloc.getOccupancyRate(IOAddress("3001::"), 128, cc_);
|
||||
EXPECT_EQ(2560. / 68096., r);
|
||||
}
|
||||
|
||||
// Test that the allocator respects client class guards.
|
||||
@ -1008,8 +1090,16 @@ TEST_F(FreeLeaseQueueAllocatorTest6, pdPoolsClientClasses) {
|
||||
|
||||
candidate = alloc.pickPrefix(cc_, pool, duid_, Allocator::PREFIX_LEN_HIGHER, IOAddress("::"), 64);
|
||||
EXPECT_TRUE(candidate.isV6Zero());
|
||||
}
|
||||
|
||||
double r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
|
||||
EXPECT_EQ(1., r);
|
||||
cc_.insert("foo");
|
||||
r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
|
||||
EXPECT_EQ(256. / 65792., r);
|
||||
cc_.clear();
|
||||
r = alloc.getOccupancyRate(IOAddress("3000:1::"), 128, cc_);
|
||||
EXPECT_EQ(0., r);
|
||||
}
|
||||
|
||||
} // end of isc::dhcp::test namespace
|
||||
} // end of isc::dhcp namespace
|
||||
|
@ -186,6 +186,7 @@ TEST_F(NetworkTest, inheritanceSupport4) {
|
||||
globals_->set("ddns-ttl", Element::create(400));
|
||||
globals_->set("ddns-ttl-min", Element::create(200));
|
||||
globals_->set("ddns-ttl-max", Element::create(600));
|
||||
globals_->set("adaptive-lease-time-threshold", Element::create(.90));
|
||||
|
||||
// For each parameter for which inheritance is supported run
|
||||
// the test that checks if the values are inherited properly.
|
||||
@ -393,6 +394,12 @@ TEST_F(NetworkTest, inheritanceSupport4) {
|
||||
&Network::setDdnsTtlMax,
|
||||
500, 600);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("adaptive-lease-time-threshold");
|
||||
testNetworkInheritance<TestNetwork4>(&Network::getAdaptiveLeaseTimeThreshold,
|
||||
&Network::setAdaptiveLeaseTimeThreshold,
|
||||
.80, .90);
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that the inheritance is supported for DHCPv6
|
||||
@ -420,6 +427,7 @@ TEST_F(NetworkTest, inheritanceSupport6) {
|
||||
globals_->set("ddns-ttl-max", Element::create(600));
|
||||
globals_->set("cache-threshold", Element::create(.35));
|
||||
globals_->set("cache-max-age", Element::create(20));
|
||||
globals_->set("adaptive-lease-time-threshold", Element::create(.90));
|
||||
|
||||
// For each parameter for which inheritance is supported run
|
||||
// the test that checks if the values are inherited properly.
|
||||
@ -558,6 +566,12 @@ TEST_F(NetworkTest, inheritanceSupport6) {
|
||||
&Network::setCacheMaxAge,
|
||||
10, 20);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("adaptive-lease-time-threshold");
|
||||
testNetworkInheritance<TestNetwork4>(&Network::getAdaptiveLeaseTimeThreshold,
|
||||
&Network::setAdaptiveLeaseTimeThreshold,
|
||||
.80, .90);
|
||||
}
|
||||
|
||||
// Interface-id requires special type of test.
|
||||
boost::shared_ptr<TestNetwork6> net_child(new TestNetwork6());
|
||||
|
@ -299,6 +299,7 @@ public:
|
||||
" \"store-extended-info\": true,"
|
||||
" \"cache-threshold\": 0.123,"
|
||||
" \"cache-max-age\": 123,"
|
||||
" \"adaptive-lease-time-threshold\": .90,"
|
||||
" \"offer-lifetime\": 777,"
|
||||
" \"ddns-update-on-renew\": true,"
|
||||
" \"option-data\": ["
|
||||
@ -336,7 +337,8 @@ public:
|
||||
" \"hostname-char-set\": \"\","
|
||||
" \"cache-threshold\": .20,"
|
||||
" \"cache-max-age\": 50,"
|
||||
" \"allocator\": \"random\""
|
||||
" \"allocator\": \"random\","
|
||||
" \"adaptive-lease-time-threshold\": .80"
|
||||
" },"
|
||||
" {"
|
||||
" \"id\": 2,"
|
||||
@ -362,7 +364,8 @@ public:
|
||||
" \"t1-percent\": .40,"
|
||||
" \"t2-percent\": .80,"
|
||||
" \"cache-threshold\": 0.0,"
|
||||
" \"cache-max-age\": 0"
|
||||
" \"cache-max-age\": 0,"
|
||||
" \"adaptive-lease-time-threshold\": .70"
|
||||
" }"
|
||||
" ]"
|
||||
"}";
|
||||
@ -432,6 +435,7 @@ TEST_F(SharedNetwork4ParserTest, parse) {
|
||||
EXPECT_EQ(777, network->getOfferLft().get());
|
||||
EXPECT_TRUE(network->getDdnsUpdateOnRenew().get());
|
||||
EXPECT_EQ("iterative", network->getAllocatorType().get());
|
||||
EXPECT_EQ(.90, network->getAdaptiveLeaseTimeThreshold().get());
|
||||
|
||||
// Relay information.
|
||||
auto relay_info = network->getRelayInfo();
|
||||
@ -730,6 +734,7 @@ public:
|
||||
" \"ddns-update-on-renew\": true,"
|
||||
" \"allocator\": \"random\","
|
||||
" \"pd-allocator\": \"iterative\","
|
||||
" \"adaptive-lease-time-threshold\": .90,"
|
||||
" \"option-data\": ["
|
||||
" {"
|
||||
" \"name\": \"dns-servers\","
|
||||
@ -845,6 +850,7 @@ TEST_F(SharedNetwork6ParserTest, parse) {
|
||||
EXPECT_TRUE(network->getDdnsUpdateOnRenew().get());
|
||||
EXPECT_EQ("random", network->getAllocatorType().get());
|
||||
EXPECT_EQ("iterative", network->getPdAllocatorType().get());
|
||||
EXPECT_EQ(.90, network->getAdaptiveLeaseTimeThreshold().get());
|
||||
|
||||
// Relay information.
|
||||
auto relay_info = network->getRelayInfo();
|
||||
|
@ -54,10 +54,14 @@ InterprocessSyncFile::do_lock(int cmd, short l_type) {
|
||||
|
||||
// Open the lockfile in the constructor so it doesn't do the access
|
||||
// checks every time a message is logged.
|
||||
const mode_t mode = umask(S_IXUSR | S_IXGRP | S_IXOTH); // 0111
|
||||
fd_ = open(lockfile_path.c_str(), O_CREAT | O_RDWR,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); // 0660
|
||||
umask(mode);
|
||||
if (fd_ != -1) {
|
||||
if (fchmod(fd_, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0) {
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_ == -1) {
|
||||
std::stringstream tmp;
|
||||
|
@ -246,7 +246,7 @@ public:
|
||||
/// @return validated path as a string (supported path + input file name)
|
||||
///
|
||||
/// @throw BadValue if the input path does not include a file name.
|
||||
/// @trhow SecurityError if the parent path does not path the supported path and
|
||||
/// @throw SecurityError if the parent path does not path the supported path and
|
||||
/// security is being enforced, SecurityWarn if it is not being enforced.
|
||||
std::string validatePath(const std::string input_path_str,
|
||||
bool enforce_path = shouldEnforceSecurity()) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user