Commit dedda6a3 authored by Francis Dupont's avatar Francis Dupont
Browse files

[master] Merge trac4500 lease6_rebind

parents 61f6b045 85279c47
......@@ -167,6 +167,38 @@ packet processing. Hook points that are not specific to packet processing
this fact; otherwise the client will think the lease was renewed and continue
to operate under this assumption.
@subsection dhcpv6HooksLease6Rebind lease6_rebind
- @b Arguments:
- name: @b query6, type: isc::dhcp::PktPtr, direction: <b>in</b>
- name: @b lease6, type: isc::dhcp::Lease6Ptr, direction: <b>in/out</b>
- name: @b ia_na, type: boost::shared_ptr<Option6IA>, direction: <b>in/out</b>
- @b Description: This callout is executed when the server engine is
about to rebind an existing lease. The client's request is provided as
the "query6" argument and the existing lease with the appropriate fields
already modified is given in the "lease6" argument. The final argument,
ia_na, is the IA_NA option that will be sent back to the client.
Callouts installed on the "lease6_rebind" may modify the content of
the "lease6" object. Care should be taken however, as that modified
information will be written to the database without any further
checking. \n\n Although the envisaged usage assumes modification of T1,
T2, preferred and valid lifetimes only, other parameters associated
with the lease may be modified as well. The only exception is the @c addr_
field, which must not be modified as it is used by the database to
select the existing lease to be updated. Care should also be taken to
modify the "ia_na" argument to match any changes in the "lease6" argument.
If a client sends more than one IA_NA option, callouts will be called
separately for each IA_NA instance. The callout will be called only
when the update is valid, i.e. conditions such as an invalid addresses
or invalid iaid rebinding attempts will not trigger this hook point.
- <b>Next step status</b>: If any callout installed on "lease6_rebind"
sets the status to SKIP, the server will not rebind the lease. Under these
circumstances, the callout should modify the "ia_na" argument to reflect
this fact; otherwise the client will think the lease was rebound and continue
to operate under this assumption.
@subsection dhcpv6HooksLease6Decline lease6_decline
- @b Arguments:
......
......@@ -56,6 +56,8 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
int hook_index_buffer6_send = -1;
int hook_index_lease6_renew = -1;
int hook_index_lease6_release = -1;
int hook_index_lease6_rebind = -1;
int hook_index_lease6_decline = -1;
int hook_index_pkt6_received = -1;
int hook_index_select_subnet = -1;
int hook_index_pkt6_send = -1;
......@@ -69,6 +71,10 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
.getIndex("lease6_renew"));
EXPECT_NO_THROW(hook_index_lease6_release = ServerHooks::getServerHooks()
.getIndex("lease6_release"));
EXPECT_NO_THROW(hook_index_lease6_rebind = ServerHooks::getServerHooks()
.getIndex("lease6_rebind"));
EXPECT_NO_THROW(hook_index_lease6_decline = ServerHooks::getServerHooks()
.getIndex("lease6_decline"));
EXPECT_NO_THROW(hook_index_pkt6_received = ServerHooks::getServerHooks()
.getIndex("pkt6_receive"));
EXPECT_NO_THROW(hook_index_select_subnet = ServerHooks::getServerHooks()
......@@ -83,6 +89,8 @@ TEST_F(Dhcpv6SrvTest, Hooks) {
EXPECT_TRUE(hook_index_buffer6_send > 0);
EXPECT_TRUE(hook_index_lease6_renew > 0);
EXPECT_TRUE(hook_index_lease6_release > 0);
EXPECT_TRUE(hook_index_lease6_rebind > 0);
EXPECT_TRUE(hook_index_lease6_decline > 0);
}
/// @brief a class dedicated to Hooks testing in DHCPv6 server
......@@ -382,22 +390,6 @@ public:
return (0);
}
/// Test callback that stores received callout name and pkt6 value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
lease6_rebind_callout(CalloutHandle& callout_handle) {
callback_name_ = string("lease6_rebind");
callout_handle.getArgument("query6", callback_qry_pkt6_);
callout_handle.getArgument("lease6", callback_lease6_);
callout_handle.getArgument("ia_na", callback_ia_na_);
callback_argument_names_ = callout_handle.getArgumentNames();
return (0);
}
/// The following values are used by the callout to override
/// renewed lease parameters
static const uint32_t override_iaid_;
......@@ -418,6 +410,8 @@ public:
callout_handle.getArgument("lease6", callback_lease6_);
callout_handle.getArgument("ia_na", callback_ia_na_);
// Should be an ASSERT but it is not allowed here
EXPECT_TRUE(callback_lease6_);
// Let's override some values in the lease
callback_lease6_->iaid_ = override_iaid_;
callback_lease6_->t1_ = override_t1_;
......@@ -425,6 +419,8 @@ public:
callback_lease6_->preferred_lft_ = override_preferred_;
callback_lease6_->valid_lft_ = override_valid_;
// Should be an ASSERT but it is not allowed here
EXPECT_TRUE(callback_ia_na_);
// Override the values to be sent to the client as well
callback_ia_na_->setIAID(override_iaid_);
callback_ia_na_->setT1(override_t1_);
......@@ -446,6 +442,76 @@ public:
return (0);
}
/// Test callback that stores received callout name and pkt6 value
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
lease6_rebind_callout(CalloutHandle& callout_handle) {
callback_name_ = string("lease6_rebind");
callout_handle.getArgument("query6", callback_qry_pkt6_);
callout_handle.getArgument("lease6", callback_lease6_);
callout_handle.getArgument("ia_na", callback_ia_na_);
callback_argument_names_ = callout_handle.getArgumentNames();
return (0);
}
/// Test callback that overrides received lease. It updates
/// T1, T2, preferred and valid lifetimes
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
lease6_rebind_update_callout(CalloutHandle& callout_handle) {
callback_name_ = string("lease6_rebind");
callout_handle.getArgument("query6", callback_qry_pkt6_);
callout_handle.getArgument("lease6", callback_lease6_);
callout_handle.getArgument("ia_na", callback_ia_na_);
// Should be an ASSERT but it is not allowed here
EXPECT_TRUE(callback_lease6_);
// Let's override some values in the lease
callback_lease6_->iaid_ = override_iaid_;
callback_lease6_->t1_ = override_t1_;
callback_lease6_->t2_ = override_t2_;
callback_lease6_->preferred_lft_ = override_preferred_;
callback_lease6_->valid_lft_ = override_valid_;
// Should be an ASSERT but it is not allowed here
EXPECT_TRUE(callback_ia_na_);
// Override the values to be sent to the client as well
callback_ia_na_->setIAID(override_iaid_);
callback_ia_na_->setT1(override_t1_);
callback_ia_na_->setT2(override_t2_);
callback_argument_names_ = callout_handle.getArgumentNames();
return (0);
}
/// Lease6_rebind callout that sets status to SKIP
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
lease6_rebind_skip_callout(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
return (lease6_rebind_callout(callout_handle));
}
/// Lease6_rebind callout that sets status to DROP
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
lease6_rebind_drop_callout(CalloutHandle& callout_handle) {
callout_handle.setStatus(CalloutHandle::NEXT_STEP_DROP);
return (lease6_rebind_callout(callout_handle));
}
/// Test callback that stores received callout name passed parameters
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
......@@ -538,7 +604,7 @@ public:
/// Pointer to lease6
static Lease6Ptr callback_lease6_;
/// Pointer to IA_NA option being renewed
/// Pointer to IA_NA option being renewed or rebound
static boost::shared_ptr<Option6IA> callback_ia_na_;
/// Pointer to a subnet received by callout
......@@ -1544,6 +1610,260 @@ TEST_F(HooksDhcpv6SrvTest, skipLease6Release) {
ASSERT_TRUE(l);
}
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are triggered.
TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
NakedDhcpv6Srv srv(0);
// Install pkt6_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"lease6_rebind", lease6_rebind_callout));
const IOAddress addr("2001:db8:1:1::cafe:babe");
const uint32_t iaid = 234;
// Generate client-id also duid_
OptionPtr clientid = generateClientId();
// Check that the address we are about to use is indeed in pool
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
// Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
// value on purpose. They should be updated during REBIND.
Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
501, 502, 503, 504, subnet_->getID(),
HWAddrPtr(), 0));
lease->cltt_ = 1234;
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Check that the lease is really in the database
Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
addr);
ASSERT_TRUE(l);
// Check that T1, T2, preferred, valid and cltt really set and not using
// previous (500, 501, etc.) values
EXPECT_NE(l->t1_, subnet_->getT1());
EXPECT_NE(l->t2_, subnet_->getT2());
EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
EXPECT_NE(l->valid_lft_, subnet_->getValid());
EXPECT_NE(l->cltt_, time(NULL));
// Let's create a REBIND
Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REBIND, 1234));
req->setRemoteAddr(IOAddress("fe80::abcd"));
req->setIface("eth0");
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
OptionPtr rebound_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
ia->addOption(rebound_addr_opt);
req->addOption(ia);
req->addOption(clientid);
// Pass it to the server and hope for a REPLY
Pkt6Ptr reply = srv.processRebind(req);
ASSERT_TRUE(reply);
// Check that the callback called is indeed the one we installed
EXPECT_EQ("lease6_rebind", callback_name_);
// Check that appropriate parameters are passed to the callouts
EXPECT_TRUE(callback_qry_pkt6_);
EXPECT_TRUE(callback_lease6_);
EXPECT_TRUE(callback_ia_na_);
// Check if all expected parameters were really received
vector<string> expected_argument_names;
expected_argument_names.push_back("query6");
expected_argument_names.push_back("lease6");
expected_argument_names.push_back("ia_na");
sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, 1234);
OptionPtr tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
// Check that IA_NA was returned and that there's an address included
boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
subnet_->getT2());
ASSERT_TRUE(addr_opt);
// Check that the lease is really in the database
l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
ASSERT_TRUE(l);
// Check that the lease has been returned
ASSERT_TRUE(callback_lease6_);
// Check that the returned lease6 in callout is the same as the one in the
// database
EXPECT_TRUE(*callback_lease6_ == *l);
}
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are able to change the lease being updated.
TEST_F(HooksDhcpv6SrvTest, leaseUpdateLease6Rebind) {
NakedDhcpv6Srv srv(0);
// Install pkt6_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"lease6_rebind", lease6_rebind_update_callout));
const IOAddress addr("2001:db8:1:1::cafe:babe");
const uint32_t iaid = 234;
// Generate client-id also duid_
OptionPtr clientid = generateClientId();
// Check that the address we are about to use is indeed in pool
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
// Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
// value on purpose. They should be updated during REBIND.
Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
501, 502, 503, 504, subnet_->getID(),
HWAddrPtr(), 0));
lease->cltt_ = 1234;
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Check that the lease is really in the database
Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
addr);
ASSERT_TRUE(l);
// Check that T1, T2, preferred, valid and cltt really set and not using
// previous (500, 501, etc.) values
EXPECT_NE(l->t1_, subnet_->getT1());
EXPECT_NE(l->t2_, subnet_->getT2());
EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
EXPECT_NE(l->valid_lft_, subnet_->getValid());
EXPECT_NE(l->cltt_, time(NULL));
// Let's create a REBIND
Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REBIND, 1234));
req->setRemoteAddr(IOAddress("fe80::abcd"));
req->setIface("eth0");
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
OptionPtr rebound_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
ia->addOption(rebound_addr_opt);
req->addOption(ia);
req->addOption(clientid);
// Pass it to the server and hope for a REPLY
Pkt6Ptr reply = srv.processRebind(req);
ASSERT_TRUE(reply);
// Check if we get response at all
checkResponse(reply, DHCPV6_REPLY, 1234);
OptionPtr tmp = reply->getOption(D6O_IA_NA);
ASSERT_TRUE(tmp);
// Check that IA_NA was returned and that there's an address included
boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 1000, 1001, 1002);
ASSERT_TRUE(addr_opt);
// Check that the lease is really in the database
l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
ASSERT_TRUE(l);
// Check that we chose the distinct override values
ASSERT_NE(override_t1_, subnet_->getT1());
ASSERT_NE(override_t2_, subnet_->getT2());
ASSERT_NE(override_preferred_, subnet_->getPreferred());
EXPECT_NE(override_valid_, subnet_->getValid());
// Check that T1, T2, preferred, valid were overridden the the callout
EXPECT_EQ(override_t1_, l->t1_);
EXPECT_EQ(override_t2_, l->t2_);
EXPECT_EQ(override_preferred_, l->preferred_lft_);
EXPECT_EQ(override_valid_, l->valid_lft_);
// Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
int32_t cltt = static_cast<int32_t>(l->cltt_);
int32_t expected = static_cast<int32_t>(time(NULL));
// Equality or difference by 1 between cltt and expected is ok.
EXPECT_GE(1, abs(cltt - expected));
EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
}
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are able to set the skip flag that will
// reject the rebinding
TEST_F(HooksDhcpv6SrvTest, skipLease6Rebind) {
NakedDhcpv6Srv srv(0);
// Install pkt6_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
"lease6_rebind", lease6_rebind_skip_callout));
const IOAddress addr("2001:db8:1:1::cafe:babe");
const uint32_t iaid = 234;
// Generate client-id also duid_
OptionPtr clientid = generateClientId();
// Check that the address we are about to use is indeed in pool
ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
// Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
// value on purpose. They should be updated during REBIND.
Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, duid_, iaid,
501, 502, 503, 504, subnet_->getID(),
HWAddrPtr(), 0));
lease->cltt_ = 1234;
ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
// Check that the lease is really in the database
Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
addr);
ASSERT_TRUE(l);
// Check that T1, T2, preferred, valid and cltt really set and not using
// previous (500, 501, etc.) values
EXPECT_NE(l->t1_, subnet_->getT1());
EXPECT_NE(l->t2_, subnet_->getT2());
EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
EXPECT_NE(l->valid_lft_, subnet_->getValid());
EXPECT_NE(l->cltt_, time(NULL));
// Let's create a REBIND
Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REBIND, 1234));
req->setRemoteAddr(IOAddress("fe80::abcd"));
req->setIface("eth0");
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
OptionPtr rebound_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
ia->addOption(rebound_addr_opt);
req->addOption(ia);
req->addOption(clientid);
// Pass it to the server and hope for a REPLY
Pkt6Ptr reply = srv.processRebind(req);
ASSERT_TRUE(reply);
// Check that our callback was called
EXPECT_EQ("lease6_rebind", callback_name_);
l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
// Check that the old values are still there and they were not
// updated by the rebinding
EXPECT_NE(l->t1_, subnet_->getT1());
EXPECT_NE(l->t2_, subnet_->getT2());
EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
EXPECT_NE(l->valid_lft_, subnet_->getValid());
EXPECT_NE(l->cltt_, time(NULL));
}
// This test checks that the basic decline hook (lease6_decline) is
// triggered properly.
TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment