LOG_DEBUG(packet_logger, DBG_DHCP6_BASIC_DATA, DHCP6_PACKET_RECEIVED)
.arg(query->getLabel())
.arg(query->getName())
- .arg(query->getType())
+ .arg(static_cast<int>(query->getType()))
.arg(query->getRemoteAddr())
.arg(query->getLocalAddr())
.arg(query->getIface());
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
+ ctx.allow_new_leases_in_renewals_ = true;
// Extract the addresses that the client is trying to obtain.
OptionCollection addrs = ia->getOptions();
// we extend, cancel or otherwise deal with the leases.
bool hints_present = !ctx.hints_.empty();
- /// @todo: This was clarified in draft-ietf-dhc-dhcpv6-stateful-issues that
- /// the server is allowed to assign new leases in both Renew and Rebind. For
- /// now, we only support it in Renew, because it breaks a lot of Rebind
- /// unit-tests. Ultimately, whether we allow it or not, should be exposed
- /// as configurable policy. See ticket #3717.
- if (query->getType() == DHCPV6_RENEW) {
- ctx.allow_new_leases_in_renewals_ = true;
- }
-
Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
// Ok, now we have the leases extended. We have:
ctx.ia_rsp_ = ia_rsp;
ctx.hwaddr_ = orig_ctx.hwaddr_;
ctx.host_ = orig_ctx.host_;
+ ctx.allow_new_leases_in_renewals_ = true;
// Extract prefixes that the client is trying to renew.
OptionCollection addrs = ia->getOptions();
// Let's try to get a MAC
HWAddrPtr hwaddr = reply->getMAC(HWAddr::HWADDR_SOURCE_ANY);
- // Set the global status code to default: success and not received.
- config_.resetGlobalStatusCode();
for (Opts::const_iterator opt = opts.begin(); opt != opts.end(); ++opt) {
Option6IAPtr ia = boost::dynamic_pointer_cast<Option6IA>(opt->second);
if (!ia) {
for (Opts::const_iterator iter_ia_opt = ia_opts.begin();
iter_ia_opt != ia_opts.end(); ++iter_ia_opt) {
OptionPtr ia_opt = iter_ia_opt->second;
- LeaseInfo lease_info;
+ LeaseInfo lease_info(ia->getType());
+ lease_info.lease_.iaid_ = ia->getIAID();
+
switch (ia_opt->getType()) {
case D6O_IAADDR:
{
// lease and keep IAID around.
lease_info.lease_ = Lease6();
lease_info.lease_.type_ = Lease::TYPE_NA;
- lease_info.lease_.iaid_ = ia->getIAID();
break;
}
// lease and keep IAID around.
lease_info.lease_ = Lease6();
lease_info.lease_.type_ = Lease::TYPE_PD;
- lease_info.lease_.iaid_ = ia->getIAID();
break;
}
lease_info.lease_ = Lease6(Lease::TYPE_PD,
config_.leases_[i] = lease_info;
return;
- } else if (lease_info.lease_.addr_ == asiolink::IOAddress("::")) {
+ } else if ((existing_lease.iaid_ == lease_info.lease_.iaid_) &&
+ (lease_info.lease_.addr_ == asiolink::IOAddress("::"))) {
+ config_.leases_[i] = lease_info;
config_.leases_[i].status_code_ = lease_info.status_code_;
return;
}
}
+
// It is a new lease. Add it.
config_.leases_.push_back(lease_info);
}
for (std::set<uint32_t>::const_iterator iaid = iaids.begin();
iaid != iaids.end(); ++iaid) {
std::vector<Lease6> leases = getLeasesByIAID(*iaid);
+ // Only a valid lease should be included. If we have received an
+ // error status code, it should not be copied.
+ if (leases[0].valid_lft_ == 0) {
+ continue;
+ }
Option6IAPtr opt(new Option6IA(leases[0].type_ == Lease::TYPE_NA ?
D6O_IA_NA : D6O_IA_PD, *iaid));
opt->setT1(leases[0].t1_);
// let's apply received configuration.
if (use_rapid_commit_ && context_.response_ &&
context_.response_->getType() == DHCPV6_REPLY) {
+ config_.clear();
applyRcvdConfiguration(context_.response_);
}
}
// Apply new configuration only if the server has responded.
if (context_.response_) {
+ config_.clear();
applyRcvdConfiguration(context_.response_);
}
}
context_.response_ = receiveOneMsg();
// Apply configuration only if the server has responded.
if (context_.response_) {
+ config_.clear();
applyRcvdConfiguration(context_.response_);
}
}
context_.response_ = receiveOneMsg();
// Apply configuration only if the server has responded.
if (context_.response_) {
+ config_.clear();
applyRcvdConfiguration(context_.response_);
}
}
// Set the global status code to default: success and not received.
config_.resetGlobalStatusCode();
if (context_.response_) {
+ config_.resetGlobalStatusCode();
applyRcvdConfiguration(context_.response_);
}
}
return (leases);
}
-std::vector<Lease6>
+std::vector<Dhcp6Client::LeaseInfo>
Dhcp6Client::getLeasesByType(const Lease::Type& lease_type) const {
- std::vector<Lease6> leases;
+ std::vector<Dhcp6Client::LeaseInfo> leases;
LeaseInfo lease_info;
BOOST_FOREACH(lease_info, config_.leases_) {
if (lease_info.lease_.type_ == lease_type) {
- leases.push_back(lease_info.lease_);
+ leases.push_back(lease_info);
}
}
return (leases);
///
/// - Configuration 0:
/// - only addresses (no prefixes)
-/// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::64
-/// - 1 subnet for eth0 and 1 subnet for eth1
+/// - 1 subnet with 2001:db8:1::/64 pool
///
/// - Configuration 1:
-/// - similar to Configuration 0 but different subnets
-/// - pools configured: 2001:db8:3::/64 and 2001:db8:4::/64
+/// - only prefixes (no addresses)
+/// - prefix pool: 3000::/72
///
/// - Configuration 2:
-/// - similar to Configuration 0 and Configuration 1
-/// - pools configured: 3000:1::/64 and 3000:2::/64
-/// - this specific configuration is used by tests using relays
+/// - addresses and prefixes
+/// - 1 subnet with one address pool and one prefix pool
+/// - address pool: 2001:db8:1::/64
+/// - prefix pool: 3000::/72
///
const char* RENEW_CONFIGS[] = {
// Configuration 0
"\"valid-lifetime\": 4000 }",
// Configuration 1
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": ["
+ " { \"prefix\": \"3000::\", "
+ " \"prefix-len\": 72, "
+ " \"delegated-len\": 80"
+ " } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }",
+
+// Configuration 2
"{ \"interfaces-config\": {"
" \"interfaces\": [ \"*\" ]"
"},"
client.fastFwdTime(1000);
// Make sure that the client has acquired NA lease.
- std::vector<Lease6> leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_na =
+ client.getLeasesByType(Lease::TYPE_NA);
ASSERT_EQ(1, leases_client_na.size());
// The client should not acquire a PD lease.
- std::vector<Lease6> leases_client_pd = client.getLeasesByType(Lease::TYPE_PD);
- ASSERT_TRUE(leases_client_pd.empty());
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_pd =
+ client.getLeasesByType(Lease::TYPE_PD);
+ ASSERT_EQ(1, leases_client_pd.size());
+ ASSERT_EQ(STATUS_NoPrefixAvail, leases_client_pd[0].status_code_);
// Reconfigure the server to use both NA and PD pools.
- configure(RENEW_CONFIGS[1], *client.getServer());
+ configure(RENEW_CONFIGS[2], *client.getServer());
// Send Renew message to the server, including IA_NA and requesting IA_PD.
ASSERT_NO_THROW(client.doRenew());
// Make sure that the client has acquired NA lease.
- std::vector<Lease6> leases_client_na_renewed = client.getLeasesByType(Lease::TYPE_NA);
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_na_renewed =
+ client.getLeasesByType(Lease::TYPE_NA);
ASSERT_EQ(1, leases_client_na_renewed.size());
+ EXPECT_EQ(STATUS_Success, leases_client_na_renewed[0].status_code_);
// The lease should have been renewed.
- EXPECT_EQ(1000, leases_client_na_renewed[0].cltt_ - leases_client_na[0].cltt_);
+ EXPECT_EQ(1000, leases_client_na_renewed[0].lease_.cltt_ -
+ leases_client_na[0].lease_.cltt_);
// The client should now also acquire a PD lease.
leases_client_pd = client.getLeasesByType(Lease::TYPE_PD);
ASSERT_EQ(1, leases_client_pd.size());
+ EXPECT_EQ(STATUS_Success, leases_client_pd[0].status_code_);
+}
+
+// This test verifies that the client can request the prefix delegation
+// while it is renewing an address lease.
+TEST_F(RenewTest, requestAddressInRenew) {
+ Dhcp6Client client;
+
+ // Configure client to request IA_NA and IA_PD.
+ client.useNA();
+ client.usePD();
+
+ // Configure the server with PD pools only.
+ ASSERT_NO_THROW(configure(RENEW_CONFIGS[1], *client.getServer()));
+
+ // Perform 4-way exchange.
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Simulate aging of leases.
+ client.fastFwdTime(1000);
+
+ // Make sure that the client has acquired PD lease.
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_pd =
+ client.getLeasesByType(Lease::TYPE_PD);
+ ASSERT_EQ(1, leases_client_pd.size());
+ EXPECT_EQ(STATUS_Success, leases_client_pd[0].status_code_);
+
+ // The client should not acquire a NA lease.
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_na =
+ client.getLeasesByType(Lease::TYPE_NA);
+ ASSERT_EQ(1, leases_client_na.size());
+ ASSERT_EQ(STATUS_NoAddrsAvail, leases_client_na[0].status_code_);
+
+ // Reconfigure the server to use both NA and PD pools.
+ configure(RENEW_CONFIGS[2], *client.getServer());
+
+ // Send Renew message to the server, including IA_PD and requesting IA_NA.
+ ASSERT_NO_THROW(client.doRenew());
+
+ // Make sure that the client has renewed PD lease.
+ std::vector<Dhcp6Client::LeaseInfo> leases_client_pd_renewed =
+ client.getLeasesByType(Lease::TYPE_PD);
+ ASSERT_EQ(1, leases_client_pd_renewed.size());
+ EXPECT_EQ(STATUS_Success, leases_client_pd_renewed[0].status_code_);
+ EXPECT_EQ(1000, leases_client_pd_renewed[0].lease_.cltt_ -
+ leases_client_pd[0].lease_.cltt_);
+
+ // The client should now also acquire a NA lease.
+ leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+ ASSERT_EQ(1, leases_client_na.size());
+ EXPECT_EQ(STATUS_Success, leases_client_na[0].status_code_);
}