mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 13:07:50 +00:00
[#3257] Suppress NCRs when reusing leases
/src/bin/dhcp4/dhcp4_srv.cc Dhcpv4Srv::createNameChangeRequests() - modified to check for reused lease /src/bin/dhcp4/tests/dora_unittest.cc DORATest::leaseCaching() - modified to verify suppression of NCRs /src/bin/dhcp6/dhcp6_srv.cc Dhcpv6Srv::createNameChangeRequests() - modified to iteralte over IA contexts rather than IA options in response and to check for reused leases /src/bin/dhcp6/tests/fqdn_unittest.cc Updated tests to populate IAContexts /src/bin/dhcp6/tests/sarr_unittest.cc SARRTest::leaseCaching()- modified to verify suppression of NCRs /src/lib/dhcpsrv/alloc_engine.* AllocEngine::ClientContext6::IAContext - added reused_leases_ container AllocEngine::ClientContext6::getIAContexts() - new function
This commit is contained in:
parent
fe77360b49
commit
3862bab83f
@ -1,3 +1,9 @@
|
|||||||
|
2303. [bug] tmark
|
||||||
|
Modified both kea-dhcp4 and kea-dhcp6 to avoid
|
||||||
|
generating DDNS update requests when leases are
|
||||||
|
being reused due to lease caching.
|
||||||
|
(Gitlab #3257)
|
||||||
|
|
||||||
Kea 2.7.4 (development) released on October 30, 2024
|
Kea 2.7.4 (development) released on October 30, 2024
|
||||||
|
|
||||||
2302. [func] tmark
|
2302. [func] tmark
|
||||||
|
@ -2893,7 +2893,8 @@ Dhcpv4Srv::createNameChangeRequests(const Lease4Ptr& lease,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!old_lease || ddns_params.getUpdateOnRenew() || !lease->hasIdenticalFqdn(*old_lease)) {
|
if ((!lease->reuseable_valid_lft_) &&
|
||||||
|
(!old_lease || ddns_params.getUpdateOnRenew() || !lease->hasIdenticalFqdn(*old_lease))) {
|
||||||
if (old_lease) {
|
if (old_lease) {
|
||||||
// Queue's up a remove of the old lease's DNS (if needed)
|
// Queue's up a remove of the old lease's DNS (if needed)
|
||||||
queueNCR(CHG_REMOVE, old_lease);
|
queueNCR(CHG_REMOVE, old_lease);
|
||||||
|
@ -633,6 +633,11 @@ const char* DORA_CONFIGS[] = {
|
|||||||
"interfaces-config": {
|
"interfaces-config": {
|
||||||
"interfaces": [ "*" ]
|
"interfaces": [ "*" ]
|
||||||
},
|
},
|
||||||
|
"dhcp-ddns": {
|
||||||
|
"enable-updates": true
|
||||||
|
},
|
||||||
|
"ddns-send-updates": true,
|
||||||
|
"ddns-update-on-renew": true,
|
||||||
"subnet4": [
|
"subnet4": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -3049,10 +3054,18 @@ DORATest::leaseCaching() {
|
|||||||
// Configure a DHCP client.
|
// Configure a DHCP client.
|
||||||
Dhcp4Client client;
|
Dhcp4Client client;
|
||||||
client.includeClientId("11:22");
|
client.includeClientId("11:22");
|
||||||
|
// Include the Client FQDN option.
|
||||||
|
ASSERT_NO_THROW(client.includeFQDN((Option4ClientFqdn::FLAG_S
|
||||||
|
| Option4ClientFqdn::FLAG_E),
|
||||||
|
"first.example.com.",
|
||||||
|
Option4ClientFqdn::FULL));
|
||||||
// Configure a DHCP server.
|
// Configure a DHCP server.
|
||||||
configure(DORA_CONFIGS[18], *client.getServer());
|
configure(DORA_CONFIGS[18], *client.getServer());
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(client.getServer()->startD2());
|
||||||
|
auto& d2_mgr = CfgMgr::instance().getD2ClientMgr();
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Obtain a lease from the server using the 4-way exchange.
|
// Obtain a lease from the server using the 4-way exchange.
|
||||||
ASSERT_NO_THROW(client.doDORA());
|
ASSERT_NO_THROW(client.doDORA());
|
||||||
|
|
||||||
@ -3078,6 +3091,12 @@ DORATest::leaseCaching() {
|
|||||||
// There should only be the default statistic point in the other subnet.
|
// There should only be the default statistic point in the other subnet.
|
||||||
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be a single NCR.
|
||||||
|
ASSERT_EQ(1, d2_mgr.getQueueSize());
|
||||||
|
// Clear the NCR queue.
|
||||||
|
ASSERT_NO_THROW(d2_mgr.runReadyIO());
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Assume the client enters init-reboot and does a request.
|
// Assume the client enters init-reboot and does a request.
|
||||||
client.setState(Dhcp4Client::INIT_REBOOT);
|
client.setState(Dhcp4Client::INIT_REBOOT);
|
||||||
ASSERT_NO_THROW(client.doRequest());
|
ASSERT_NO_THROW(client.doRequest());
|
||||||
@ -3104,6 +3123,9 @@ DORATest::leaseCaching() {
|
|||||||
// Statistics for the other subnet should not be affected.
|
// Statistics for the other subnet should not be affected.
|
||||||
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be no NCRs queued.
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Let's say the client suddenly decides to do a full DORA.
|
// Let's say the client suddenly decides to do a full DORA.
|
||||||
ASSERT_NO_THROW(client.doDORA());
|
ASSERT_NO_THROW(client.doDORA());
|
||||||
|
|
||||||
@ -3129,6 +3151,9 @@ DORATest::leaseCaching() {
|
|||||||
// Statistics for the other subnet should not be affected.
|
// Statistics for the other subnet should not be affected.
|
||||||
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be no NCRs queued.
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Try to request a different address than the client has. The server
|
// Try to request a different address than the client has. The server
|
||||||
// should respond with DHCPNAK.
|
// should respond with DHCPNAK.
|
||||||
client.config_.lease_.addr_ = IOAddress("10.0.0.30");
|
client.config_.lease_.addr_ = IOAddress("10.0.0.30");
|
||||||
@ -3153,6 +3178,9 @@ DORATest::leaseCaching() {
|
|||||||
|
|
||||||
// Statistics for the other subnet should certainly not be affected.
|
// Statistics for the other subnet should certainly not be affected.
|
||||||
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
checkStat("subnet[2].v4-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be no NCRs queued.
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DORATest, leaseCaching) {
|
TEST_F(DORATest, leaseCaching) {
|
||||||
|
@ -2439,13 +2439,17 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
|
|||||||
// Compute DHCID from Client Identifier and FQDN.
|
// Compute DHCID from Client Identifier and FQDN.
|
||||||
isc::dhcp_ddns::D2Dhcid dhcid(*duid, buf_vec);
|
isc::dhcp_ddns::D2Dhcid dhcid(*duid, buf_vec);
|
||||||
|
|
||||||
// Get all IAs from the answer. For each IA, holding an address we will
|
// Iterate over the IAContexts (there should be one per client IA processed).
|
||||||
// create a corresponding NameChangeRequest.
|
// For the first address in each IA_NA, create the appropriate NCR(s).
|
||||||
for (auto const& answer_ia : answer->getOptions(D6O_IA_NA)) {
|
for (auto& ia_ctx : ctx.getIAContexts()) {
|
||||||
|
if ((ia_ctx.type_ != Lease::TYPE_NA) || !ia_ctx.ia_rsp_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/// @todo IA_NA may contain multiple addresses. We should process
|
/// @todo IA_NA may contain multiple addresses. We should process
|
||||||
/// each address individually. Currently we get only one.
|
/// each address individually. Currently we only process the first one.
|
||||||
Option6IAAddrPtr iaaddr = boost::static_pointer_cast<
|
Option6IAAddrPtr iaaddr = boost::static_pointer_cast
|
||||||
Option6IAAddr>(answer_ia.second->getOption(D6O_IAADDR));
|
<Option6IAAddr>(ia_ctx.ia_rsp_->getOption(D6O_IAADDR));
|
||||||
|
|
||||||
// We need an address to create a name-to-address mapping.
|
// We need an address to create a name-to-address mapping.
|
||||||
// If address is missing for any reason, go to the next IA.
|
// If address is missing for any reason, go to the next IA.
|
||||||
@ -2453,19 +2457,33 @@ Dhcpv6Srv::createNameChangeRequests(const Pkt6Ptr& answer,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool extended_only = false;
|
||||||
|
// If the lease is being reused (i.e. lease caching in effect) skip it.
|
||||||
|
IOAddress ia_address = iaaddr->getAddress();
|
||||||
|
for (auto const& l : ia_ctx.reused_leases_) {
|
||||||
|
if (l->addr_ == ia_address) {
|
||||||
|
extended_only = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extended_only) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If the lease for iaaddr is in the list of changed leases, we need
|
// If the lease for iaaddr is in the list of changed leases, we need
|
||||||
// to determine if the changes included changes to the FQDN. If so
|
// to determine if the changes included changes to the FQDN. If so
|
||||||
// then we may need to do a CHG_REMOVE.
|
// then we may need to do a CHG_REMOVE.
|
||||||
bool extended_only = false;
|
for (auto const& l : ia_ctx.changed_leases_) {
|
||||||
for (auto const& l : ctx.currentIA().changed_leases_) {
|
|
||||||
|
|
||||||
if (l->addr_ == iaaddr->getAddress()) {
|
if (l->addr_ == ia_address) {
|
||||||
// The address is the same so this must be renewal. If we're not
|
// The address is the same so this must be renewal. If we're not
|
||||||
// always updating on renew, then we only renew if DNS info has
|
// always updating on renew, then we only renew if DNS info has
|
||||||
// changed.
|
// changed.
|
||||||
if (!ctx.getDdnsParams()->getUpdateOnRenew() &&
|
if (l->reuseable_valid_lft_ ||
|
||||||
|
(!ctx.getDdnsParams()->getUpdateOnRenew() &&
|
||||||
(l->hostname_ == opt_fqdn->getDomainName() &&
|
(l->hostname_ == opt_fqdn->getDomainName() &&
|
||||||
l->fqdn_fwd_ == do_fwd && l->fqdn_rev_ == do_rev)) {
|
l->fqdn_fwd_ == do_fwd && l->fqdn_rev_ == do_rev))) {
|
||||||
extended_only = true;
|
extended_only = true;
|
||||||
} else {
|
} else {
|
||||||
// Queue a CHG_REMOVE of the old data.
|
// Queue a CHG_REMOVE of the old data.
|
||||||
@ -2630,6 +2648,7 @@ Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query,
|
|||||||
// Do not use OptionDefinition to create option's instance so
|
// Do not use OptionDefinition to create option's instance so
|
||||||
// as we can initialize IAID using a constructor.
|
// as we can initialize IAID using a constructor.
|
||||||
Option6IAPtr ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
|
Option6IAPtr ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
|
||||||
|
ctx.currentIA().ia_rsp_ = ia_rsp;
|
||||||
|
|
||||||
if (lease) {
|
if (lease) {
|
||||||
// We have a lease! Let's wrap its content into IA_NA option
|
// We have a lease! Let's wrap its content into IA_NA option
|
||||||
@ -2648,6 +2667,8 @@ Dhcpv6Srv::assignIA_NA(const Pkt6Ptr& query,
|
|||||||
} else {
|
} else {
|
||||||
lease->valid_lft_ = lease->reuseable_valid_lft_;
|
lease->valid_lft_ = lease->reuseable_valid_lft_;
|
||||||
lease->preferred_lft_ = lease->reuseable_preferred_lft_;
|
lease->preferred_lft_ = lease->reuseable_preferred_lft_;
|
||||||
|
std::cout << __LINE__ << " flagged as resuseable: " << lease->addr_.toText() << std::endl;
|
||||||
|
ctx.currentIA().reused_leases_.push_back(lease);
|
||||||
LOG_INFO(lease6_logger, DHCP6_LEASE_REUSE)
|
LOG_INFO(lease6_logger, DHCP6_LEASE_REUSE)
|
||||||
.arg(query->getLabel())
|
.arg(query->getLabel())
|
||||||
.arg(lease->addr_.toText())
|
.arg(lease->addr_.toText())
|
||||||
@ -2751,6 +2772,7 @@ Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query,
|
|||||||
ctx.currentIA().addHint(hint, 0);
|
ctx.currentIA().addHint(hint, 0);
|
||||||
}
|
}
|
||||||
ctx.currentIA().type_ = Lease::TYPE_PD;
|
ctx.currentIA().type_ = Lease::TYPE_PD;
|
||||||
|
ctx.currentIA().ia_rsp_ = ia_rsp;
|
||||||
|
|
||||||
// Use allocation engine to pick a lease for this client. Allocation engine
|
// Use allocation engine to pick a lease for this client. Allocation engine
|
||||||
// will try to honor the hint, but it is just a hint - some other address
|
// will try to honor the hint, but it is just a hint - some other address
|
||||||
|
@ -255,12 +255,17 @@ public:
|
|||||||
///
|
///
|
||||||
/// @param iaid IAID
|
/// @param iaid IAID
|
||||||
/// @param pkt A DHCPv6 message to which the IA option should be added.
|
/// @param pkt A DHCPv6 message to which the IA option should be added.
|
||||||
void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt) {
|
/// @param cxt allocation engine context to which IA option should be
|
||||||
|
/// added.
|
||||||
|
void addIA(const uint32_t iaid, const IOAddress& addr, Pkt6Ptr& pkt,
|
||||||
|
AllocEngine::ClientContext6& ctx) {
|
||||||
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
||||||
Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
|
Option6IAAddrPtr opt_iaaddr(new Option6IAAddr(D6O_IAADDR, addr,
|
||||||
300, 500));
|
300, 500));
|
||||||
opt_ia->addOption(opt_iaaddr);
|
opt_ia->addOption(opt_iaaddr);
|
||||||
pkt->addOption(opt_ia);
|
pkt->addOption(opt_ia);
|
||||||
|
ctx.createIAContext();
|
||||||
|
ctx.currentIA().ia_rsp_ = opt_ia;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Adds IA option to the message.
|
/// @brief Adds IA option to the message.
|
||||||
@ -270,10 +275,15 @@ public:
|
|||||||
/// @param iaid IAID
|
/// @param iaid IAID
|
||||||
/// @param status_code Status code
|
/// @param status_code Status code
|
||||||
/// @param pkt A DHCPv6 message to which the option should be added.
|
/// @param pkt A DHCPv6 message to which the option should be added.
|
||||||
void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt) {
|
/// @param cxt allocation engine context to which IA option should be
|
||||||
|
/// added.
|
||||||
|
void addIA(const uint32_t iaid, const uint16_t status_code, Pkt6Ptr& pkt,
|
||||||
|
AllocEngine::ClientContext6& ctx) {
|
||||||
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
Option6IAPtr opt_ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
|
||||||
addStatusCode(status_code, "", opt_ia);
|
addStatusCode(status_code, "", opt_ia);
|
||||||
pkt->addOption(opt_ia);
|
pkt->addOption(opt_ia);
|
||||||
|
ctx.createIAContext();
|
||||||
|
ctx.currentIA().ia_rsp_ = opt_ia;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Creates status code with the specified code and message.
|
/// @brief Creates status code with the specified code and message.
|
||||||
@ -347,13 +357,13 @@ public:
|
|||||||
? DHCPV6_ADVERTISE :
|
? DHCPV6_ADVERTISE :
|
||||||
DHCPV6_REPLY);
|
DHCPV6_REPLY);
|
||||||
|
|
||||||
// Create three IAs, each having different address.
|
|
||||||
addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
|
||||||
|
|
||||||
AllocEngine::ClientContext6 ctx;
|
AllocEngine::ClientContext6 ctx;
|
||||||
// Set the selected subnet so ddns params get returned correctly.
|
// Set the selected subnet so ddns params get returned correctly.
|
||||||
ctx.subnet_ = subnet_;
|
ctx.subnet_ = subnet_;
|
||||||
|
|
||||||
|
// Create three IAs, each having different address.
|
||||||
|
addIA(1234, IOAddress("2001:db8:1::1"), answer, ctx);
|
||||||
|
|
||||||
ASSERT_NO_THROW(srv_->processClientFqdn(question, answer, ctx));
|
ASSERT_NO_THROW(srv_->processClientFqdn(question, answer, ctx));
|
||||||
Option6ClientFqdnPtr answ_fqdn = boost::dynamic_pointer_cast<
|
Option6ClientFqdnPtr answ_fqdn = boost::dynamic_pointer_cast<
|
||||||
Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
|
Option6ClientFqdn>(answer->getOption(D6O_CLIENT_FQDN));
|
||||||
@ -823,10 +833,15 @@ TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
|
|||||||
// Create Reply message with Client Id and Server id.
|
// Create Reply message with Client Id and Server id.
|
||||||
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
||||||
|
|
||||||
|
// Create NameChangeRequest for the first allocated address.
|
||||||
|
AllocEngine::ClientContext6 ctx;
|
||||||
|
ctx.subnet_ = subnet_;
|
||||||
|
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
||||||
|
|
||||||
// Create three IAs, each having different address.
|
// Create three IAs, each having different address.
|
||||||
addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
addIA(1234, IOAddress("2001:db8:1::1"), answer, ctx);
|
||||||
addIA(2345, IOAddress("2001:db8:1::2"), answer);
|
addIA(2345, IOAddress("2001:db8:1::2"), answer, ctx);
|
||||||
addIA(3456, IOAddress("2001:db8:1::3"), answer);
|
addIA(3456, IOAddress("2001:db8:1::3"), answer, ctx);
|
||||||
|
|
||||||
// Use domain name in upper case. It should be converted to lower-case
|
// Use domain name in upper case. It should be converted to lower-case
|
||||||
// before DHCID is calculated. So, we should get the same result as if
|
// before DHCID is calculated. So, we should get the same result as if
|
||||||
@ -836,10 +851,7 @@ TEST_F(FqdnDhcpv6SrvTest, createNameChangeRequests) {
|
|||||||
Option6ClientFqdn::FULL);
|
Option6ClientFqdn::FULL);
|
||||||
answer->addOption(fqdn);
|
answer->addOption(fqdn);
|
||||||
|
|
||||||
// Create NameChangeRequest for the first allocated address.
|
|
||||||
AllocEngine::ClientContext6 ctx;
|
|
||||||
ctx.subnet_ = subnet_;
|
|
||||||
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
|
||||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
||||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||||
|
|
||||||
@ -857,8 +869,14 @@ TEST_F(FqdnDhcpv6SrvTest, noConflictResolution) {
|
|||||||
// Create Reply message with Client Id and Server id.
|
// Create Reply message with Client Id and Server id.
|
||||||
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
||||||
|
|
||||||
|
// Create NameChangeRequest for the first allocated address.
|
||||||
|
AllocEngine::ClientContext6 ctx;
|
||||||
|
subnet_->setDdnsConflictResolutionMode("no-check-with-dhcid");
|
||||||
|
ctx.subnet_ = subnet_;
|
||||||
|
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
||||||
|
|
||||||
// Create three IAs, each having different address.
|
// Create three IAs, each having different address.
|
||||||
addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
addIA(1234, IOAddress("2001:db8:1::1"), answer, ctx);
|
||||||
|
|
||||||
// Use domain name in upper case. It should be converted to lower-case
|
// Use domain name in upper case. It should be converted to lower-case
|
||||||
// before DHCID is calculated. So, we should get the same result as if
|
// before DHCID is calculated. So, we should get the same result as if
|
||||||
@ -868,11 +886,6 @@ TEST_F(FqdnDhcpv6SrvTest, noConflictResolution) {
|
|||||||
Option6ClientFqdn::FULL);
|
Option6ClientFqdn::FULL);
|
||||||
answer->addOption(fqdn);
|
answer->addOption(fqdn);
|
||||||
|
|
||||||
// Create NameChangeRequest for the first allocated address.
|
|
||||||
AllocEngine::ClientContext6 ctx;
|
|
||||||
subnet_->setDdnsConflictResolutionMode("no-check-with-dhcid");
|
|
||||||
ctx.subnet_ = subnet_;
|
|
||||||
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
|
||||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
||||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||||
|
|
||||||
@ -893,8 +906,13 @@ TEST_F(FqdnDhcpv6SrvTest, noAddRequestsWhenDisabled) {
|
|||||||
// Create Reply message with Client Id and Server id.
|
// Create Reply message with Client Id and Server id.
|
||||||
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
||||||
|
|
||||||
|
// An attempt to send a NCR would throw.
|
||||||
|
AllocEngine::ClientContext6 ctx;
|
||||||
|
ctx.subnet_ = subnet_;
|
||||||
|
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
||||||
|
|
||||||
// Create three IAs, each having different address.
|
// Create three IAs, each having different address.
|
||||||
addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
addIA(1234, IOAddress("2001:db8:1::1"), answer, ctx);
|
||||||
|
|
||||||
// Use domain name in upper case. It should be converted to lower-case
|
// Use domain name in upper case. It should be converted to lower-case
|
||||||
// before DHCID is calculated. So, we should get the same result as if
|
// before DHCID is calculated. So, we should get the same result as if
|
||||||
@ -904,10 +922,6 @@ TEST_F(FqdnDhcpv6SrvTest, noAddRequestsWhenDisabled) {
|
|||||||
Option6ClientFqdn::FULL);
|
Option6ClientFqdn::FULL);
|
||||||
answer->addOption(fqdn);
|
answer->addOption(fqdn);
|
||||||
|
|
||||||
// An attempt to send a NCR would throw.
|
|
||||||
AllocEngine::ClientContext6 ctx;
|
|
||||||
ctx.subnet_ = subnet_;
|
|
||||||
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
|
||||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2153,8 +2167,15 @@ TEST_F(FqdnDhcpv6SrvTest, ddnsTtlPercent) {
|
|||||||
// Create Reply message with Client Id and Server id.
|
// Create Reply message with Client Id and Server id.
|
||||||
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
Pkt6Ptr answer = generateMessageWithIds(DHCPV6_REPLY);
|
||||||
|
|
||||||
|
// Create NameChangeRequest for the first allocated address.
|
||||||
|
AllocEngine::ClientContext6 ctx;
|
||||||
|
subnet_->setDdnsConflictResolutionMode("no-check-with-dhcid");
|
||||||
|
subnet_->setDdnsTtlPercent(Optional<double>(0.10));
|
||||||
|
ctx.subnet_ = subnet_;
|
||||||
|
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
||||||
|
|
||||||
// Create an IA.
|
// Create an IA.
|
||||||
addIA(1234, IOAddress("2001:db8:1::1"), answer);
|
addIA(1234, IOAddress("2001:db8:1::1"), answer, ctx);
|
||||||
|
|
||||||
// Use domain name in upper case. It should be converted to lower-case
|
// Use domain name in upper case. It should be converted to lower-case
|
||||||
// before DHCID is calculated. So, we should get the same result as if
|
// before DHCID is calculated. So, we should get the same result as if
|
||||||
@ -2164,12 +2185,6 @@ TEST_F(FqdnDhcpv6SrvTest, ddnsTtlPercent) {
|
|||||||
Option6ClientFqdn::FULL);
|
Option6ClientFqdn::FULL);
|
||||||
answer->addOption(fqdn);
|
answer->addOption(fqdn);
|
||||||
|
|
||||||
// Create NameChangeRequest for the first allocated address.
|
|
||||||
AllocEngine::ClientContext6 ctx;
|
|
||||||
subnet_->setDdnsConflictResolutionMode("no-check-with-dhcid");
|
|
||||||
subnet_->setDdnsTtlPercent(Optional<double>(0.10));
|
|
||||||
ctx.subnet_ = subnet_;
|
|
||||||
ctx.fwd_dns_update_ = ctx.rev_dns_update_ = true;
|
|
||||||
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
ASSERT_NO_THROW(srv_->createNameChangeRequests(answer, ctx));
|
||||||
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
ASSERT_EQ(1, d2_mgr_.getQueueSize());
|
||||||
|
|
||||||
|
@ -313,6 +313,11 @@ const char* CONFIGS[] = {
|
|||||||
"interfaces-config": {
|
"interfaces-config": {
|
||||||
"interfaces": [ "*" ]
|
"interfaces": [ "*" ]
|
||||||
},
|
},
|
||||||
|
"dhcp-ddns": {
|
||||||
|
"enable-updates": true
|
||||||
|
},
|
||||||
|
"ddns-send-updates": true,
|
||||||
|
"ddns-update-on-renew": true,
|
||||||
"subnet6": [
|
"subnet6": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -1367,6 +1372,16 @@ SARRTest::leaseCaching() {
|
|||||||
ASSERT_NO_THROW(client.requestAddress(1234, asiolink::IOAddress("2001:db8::10")));
|
ASSERT_NO_THROW(client.requestAddress(1234, asiolink::IOAddress("2001:db8::10")));
|
||||||
ASSERT_NO_THROW(client.requestPrefix(5678, 32, asiolink::IOAddress("2001:db8:1::")));
|
ASSERT_NO_THROW(client.requestPrefix(5678, 32, asiolink::IOAddress("2001:db8:1::")));
|
||||||
|
|
||||||
|
// Include FQDN to trigger generation of name change requests.
|
||||||
|
ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
|
||||||
|
"client-name.example.org",
|
||||||
|
Option6ClientFqdn::FULL));
|
||||||
|
|
||||||
|
// Start D2 client mgr and verify the NCR queue is empty.
|
||||||
|
ASSERT_NO_THROW(client.getServer()->startD2());
|
||||||
|
auto& d2_mgr = CfgMgr::instance().getD2ClientMgr();
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Perform 4-way exchange.
|
// Perform 4-way exchange.
|
||||||
ASSERT_NO_THROW(client.doSARR());
|
ASSERT_NO_THROW(client.doSARR());
|
||||||
|
|
||||||
@ -1393,6 +1408,12 @@ SARRTest::leaseCaching() {
|
|||||||
checkStat("subnet[1].v6-ia-pd-lease-reuses", 1, 0);
|
checkStat("subnet[1].v6-ia-pd-lease-reuses", 1, 0);
|
||||||
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be a single NCR.
|
||||||
|
ASSERT_EQ(1, d2_mgr.getQueueSize());
|
||||||
|
// Clear the NCR queue.
|
||||||
|
ASSERT_NO_THROW(d2_mgr.runReadyIO());
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Request the same prefix with a different length. The server should
|
// Request the same prefix with a different length. The server should
|
||||||
// return an existing lease.
|
// return an existing lease.
|
||||||
client.clearRequestedIAs();
|
client.clearRequestedIAs();
|
||||||
@ -1415,6 +1436,9 @@ SARRTest::leaseCaching() {
|
|||||||
checkStat("subnet[1].v6-ia-pd-lease-reuses", 2, 1);
|
checkStat("subnet[1].v6-ia-pd-lease-reuses", 2, 1);
|
||||||
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be no NCRs queued.
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
|
|
||||||
// Try to request another prefix. The client should still get the existing
|
// Try to request another prefix. The client should still get the existing
|
||||||
// lease.
|
// lease.
|
||||||
client.clearRequestedIAs();
|
client.clearRequestedIAs();
|
||||||
@ -1436,6 +1460,9 @@ SARRTest::leaseCaching() {
|
|||||||
checkStat("v6-ia-pd-lease-reuses", 3, 2);
|
checkStat("v6-ia-pd-lease-reuses", 3, 2);
|
||||||
checkStat("subnet[1].v6-ia-pd-lease-reuses", 3, 2);
|
checkStat("subnet[1].v6-ia-pd-lease-reuses", 3, 2);
|
||||||
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
checkStat("subnet[2].v6-ia-pd-lease-reuses", 1, 0);
|
||||||
|
|
||||||
|
// There should be no NCRs queued.
|
||||||
|
ASSERT_EQ(0, d2_mgr.getQueueSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SARRTest, leaseCaching) {
|
TEST_F(SARRTest, leaseCaching) {
|
||||||
|
@ -224,7 +224,7 @@ AllocEngine::ClientContext6::ClientContext6(const ConstSubnet6Ptr& subnet,
|
|||||||
|
|
||||||
AllocEngine::ClientContext6::IAContext::IAContext()
|
AllocEngine::ClientContext6::IAContext::IAContext()
|
||||||
: iaid_(0), type_(Lease::TYPE_NA), hints_(), old_leases_(),
|
: iaid_(0), type_(Lease::TYPE_NA), hints_(), old_leases_(),
|
||||||
changed_leases_(), new_resources_(), ia_rsp_() {
|
changed_leases_(),reused_leases_(), new_resources_(), ia_rsp_() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2371,6 +2371,10 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
|
|||||||
lease->pool_id_ = pool->getID();
|
lease->pool_id_ = pool->getID();
|
||||||
}
|
}
|
||||||
LeaseMgrFactory::instance().updateLease6(lease);
|
LeaseMgrFactory::instance().updateLease6(lease);
|
||||||
|
} else {
|
||||||
|
// Server looks at changed_leases_ (i.e. old_data) when deciding
|
||||||
|
// on DNS updates etc.
|
||||||
|
old_data->reuseable_valid_lft_ = lease->reuseable_valid_lft_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_stats) {
|
if (update_stats) {
|
||||||
@ -2465,9 +2469,13 @@ AllocEngine::updateLeaseData(ClientContext6& ctx, const Lease6Collection& leases
|
|||||||
if (!fqdn_changed) {
|
if (!fqdn_changed) {
|
||||||
setLeaseReusable(lease, current_preferred_lft, ctx);
|
setLeaseReusable(lease, current_preferred_lft, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lease->reuseable_valid_lft_ == 0) {
|
if (lease->reuseable_valid_lft_ == 0) {
|
||||||
ctx.currentIA().changed_leases_.push_back(lease_it);
|
ctx.currentIA().changed_leases_.push_back(lease_it);
|
||||||
LeaseMgrFactory::instance().updateLease6(lease);
|
LeaseMgrFactory::instance().updateLease6(lease);
|
||||||
|
} else {
|
||||||
|
// Server needs to know about resused leases to avoid DNS updates.
|
||||||
|
ctx.currentIA().reused_leases_.push_back(lease_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_stats) {
|
if (update_stats) {
|
||||||
|
@ -322,6 +322,9 @@ public:
|
|||||||
/// FQDN has changed.
|
/// FQDN has changed.
|
||||||
Lease6Collection changed_leases_;
|
Lease6Collection changed_leases_;
|
||||||
|
|
||||||
|
/// @brief Set of leases marked for reuse by lease caching
|
||||||
|
Lease6Collection reused_leases_;
|
||||||
|
|
||||||
/// @brief Holds addresses and prefixes allocated for this IA.
|
/// @brief Holds addresses and prefixes allocated for this IA.
|
||||||
///
|
///
|
||||||
/// This collection is used to update at most once new leases.
|
/// This collection is used to update at most once new leases.
|
||||||
@ -424,6 +427,10 @@ public:
|
|||||||
return (ias_.back());
|
return (ias_.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<IAContext>& getIAContexts() {
|
||||||
|
return (ias_);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Creates new IA context.
|
/// @brief Creates new IA context.
|
||||||
///
|
///
|
||||||
/// This method should be invoked prior to processing a next IA included
|
/// This method should be invoked prior to processing a next IA included
|
||||||
|
Loading…
x
Reference in New Issue
Block a user