EXPECT_TRUE(callback_name_.empty());
}
-//// Add a positive (vs this negative one) test with Solicit and rapid commit
-
-//// Looks for the same with park
-
// This test verifies that the leases6_committed hook point is not triggered
// for the CONFIRM.
TEST_F(HooksDhcpv6SrvTest, leases6CommittedConfirm) {
EXPECT_TRUE(callback_name_.empty());
}
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of SOLICIT message sent to allocate new
+// lease or renew an existing lease using Rapid Commit i.e. one exchange only.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRapidCommit) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"rapid-commit\": true, "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.useRapidCommit(true);
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doSolicit());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+}
+
+// This test verifies that it is possible to park a packet as a result of
+// the leases6_committed callouts using Rapid Commit SOLICITs and prefixes.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRapidCommitPrefixes) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"rapid-commit\": true, "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ // Create first client and perform SARR.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+ client1.useRapidCommit(true);
+
+ ASSERT_NO_THROW(configure(config, *client1.getServer()));
+
+ // This callout uses provided IO service object to post a function
+ // that unparks the packet. The packet is parked and can be unparked
+ // by simply calling IOService::poll.
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_park_callout));
+
+ ASSERT_NO_THROW(client1.doSolicit());
+
+ // We should be offered an address but the REPLY should not arrive
+ // at this point, because the packet is parked.
+ ASSERT_FALSE(client1.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be passed to the callout.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Reset all indicators because we'll be now creating a second client.
+ resetCalloutBuffers();
+
+ // Create the second client to test that it may communicate with the
+ // server while the previous packet is parked.
+ Dhcp6Client client2;
+ client2.setInterface("eth1");
+ client2.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:29::"));
+ client2.useRapidCommit(true);
+ ASSERT_NO_THROW(client2.doSolicit());
+
+ // The ADVERTISE should have been returned but not REPLAY, as this
+ // packet got parked too.
+ ASSERT_FALSE(client2.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed.
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // There should be now two actions scheduled on our IO service
+ // by the invoked callouts. They unpark both REPLY messages.
+ ASSERT_NO_THROW(io_service_->poll());
+
+ // Receive and check the first response.
+ ASSERT_NO_THROW(client1.receiveResponse());
+ ASSERT_TRUE(client1.getContext().response_);
+ Pkt6Ptr rsp = client1.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("2001:db8:1:28::"), 64));
+
+ // Receive and check the second response.
+ ASSERT_NO_THROW(client2.receiveResponse());
+ ASSERT_TRUE(client2.getContext().response_);
+ rsp = client2.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("2001:db8:1:29::"), 64));
+}
+
// This test verifies that the callout installed on the leases6_committed hook
// point is executed as a result of REQUEST message sent to allocate new
// lease or renew an existing lease.
EXPECT_TRUE(callback_deleted_leases6_->empty());
}
-//// same with prefix
-
-// This test verifies that it is possible to park a packet as a result of
-// the leases6_committed callouts.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequests) {
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of REQUEST message sent to allocate new
+// lease or renew an existing lease. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRequestPrefix) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
" \"subnet\": \"2001:db8:1::/48\", "
" \"interface\": \"eth1\" "
" } ],"
"\"valid-lifetime\": 4000 }";
- // Create first client and perform SARR.
- Dhcp6Client client1;
- client1.setInterface("eth1");
- client1.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
- ASSERT_NO_THROW(configure(config, *client1.getServer()));
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
- // This callout uses provided IO service object to post a function
- // that unparks the packet. The packet is parked and can be unparked
- // by simply calling IOService::poll.
ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "leases6_committed", leases6_committed_park_callout));
+ "leases6_committed", leases6_committed_callout));
- ASSERT_NO_THROW(client1.doSARR());
+ ASSERT_NO_THROW(client.doSARR());
- // We should be offered an address but the REPLY should not arrive
- // at this point, because the packet is parked.
- ASSERT_FALSE(client1.getContext().response_);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Newly allocated lease should be passed to the callout.
+ // Newly allocated lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
ASSERT_EQ(1, callback_new_leases6_->size());
Lease6Ptr lease = callback_new_leases6_->at(0);
ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
// Deleted lease must not be present, because it is a new allocation.
ASSERT_TRUE(callback_deleted_leases6_);
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
- // Reset all indicators because we'll be now creating a second client.
resetCalloutBuffers();
- // Create the second client to test that it may communicate with the
- // server while the previous packet is parked.
- Dhcp6Client client2;
- client2.setInterface("eth1");
- client2.requestAddress(0xabca, IOAddress("2001:db8:1::29"));
- ASSERT_NO_THROW(client2.doSARR());
+ // Request the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRequest());
- // The ADVERTISE should have been returned but not REPLAY, as this
- // packet got parked too.
- ASSERT_FALSE(client2.getContext().response_);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Check that the callback called is indeed the one we installed.
+ // Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
- // There should be now two actions scheduled on our IO service
- // by the invoked callouts. They unpark both REPLY messages.
- ASSERT_NO_THROW(io_service_->poll());
+ // Requested lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
- // Receive and check the first response.
- ASSERT_NO_THROW(client1.receiveResponse());
- ASSERT_TRUE(client1.getContext().response_);
- Pkt6Ptr rsp = client1.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
- // Receive and check the second response.
- ASSERT_NO_THROW(client2.receiveResponse());
- ASSERT_TRUE(client2.getContext().response_);
- rsp = client2.getContext().response_;
- EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
- EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::29")));
-}
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
-//// same with prefix
+ resetCalloutBuffers();
-// This test verifies that incoming (positive) RENEW can be handled properly,
-// and the lease6_renew callouts are triggered.
-TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
- NakedDhcpv6Srv srv(0);
+ // Let's try to request again but force the client to request a different
+ // prefix with a different IAID.
+ client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
- // Install lease6_renew_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_callout));
+ ASSERT_NO_THROW(client.doRequest());
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+ // New lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:29::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- 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));
+ // The old lease is kept.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
- // Check that the lease is really in the database
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // The requested prefix is just a hint.
+ client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
+
+ ASSERT_NO_THROW(client.doRequest());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(2);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Request an address: this should lead to an error as no address pool
+ // is configured.
+ client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(client.doRequest());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check the error.
+ EXPECT_EQ(STATUS_NoAddrsAvail, client.getStatusCode(0x1122));
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+}
+
+// This test verifies that it is possible to park a packet as a result of
+// the leases6_committed callouts.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequests) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ // Create first client and perform SARR.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(configure(config, *client1.getServer()));
+
+ // This callout uses provided IO service object to post a function
+ // that unparks the packet. The packet is parked and can be unparked
+ // by simply calling IOService::poll.
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_park_callout));
+
+ ASSERT_NO_THROW(client1.doSARR());
+
+ // We should be offered an address but the REPLY should not arrive
+ // at this point, because the packet is parked.
+ ASSERT_FALSE(client1.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be passed to the callout.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Reset all indicators because we'll be now creating a second client.
+ resetCalloutBuffers();
+
+ // Create the second client to test that it may communicate with the
+ // server while the previous packet is parked.
+ Dhcp6Client client2;
+ client2.setInterface("eth1");
+ client2.requestAddress(0xabca, IOAddress("2001:db8:1::29"));
+ ASSERT_NO_THROW(client2.doSARR());
+
+ // The ADVERTISE should have been returned but not REPLAY, as this
+ // packet got parked too.
+ ASSERT_FALSE(client2.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed.
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // There should be now two actions scheduled on our IO service
+ // by the invoked callouts. They unpark both REPLY messages.
+ ASSERT_NO_THROW(io_service_->poll());
+
+ // Receive and check the first response.
+ ASSERT_NO_THROW(client1.receiveResponse());
+ ASSERT_TRUE(client1.getContext().response_);
+ Pkt6Ptr rsp = client1.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28")));
+
+ // Receive and check the second response.
+ ASSERT_NO_THROW(client2.receiveResponse());
+ ASSERT_TRUE(client2.getContext().response_);
+ rsp = client2.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::29")));
+}
+
+// This test verifies that it is possible to park a packet as a result of
+// the leases6_committed callouts. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedParkRequestsPrefixes) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ // Create first client and perform SARR.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+
+ ASSERT_NO_THROW(configure(config, *client1.getServer()));
+
+ // This callout uses provided IO service object to post a function
+ // that unparks the packet. The packet is parked and can be unparked
+ // by simply calling IOService::poll.
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_park_callout));
+
+ ASSERT_NO_THROW(client1.doSARR());
+
+ // We should be offered an address but the REPLY should not arrive
+ // at this point, because the packet is parked.
+ ASSERT_FALSE(client1.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be passed to the callout.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ // Reset all indicators because we'll be now creating a second client.
+ resetCalloutBuffers();
+
+ // Create the second client to test that it may communicate with the
+ // server while the previous packet is parked.
+ Dhcp6Client client2;
+ client2.setInterface("eth1");
+ client2.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:29::"));
+ ASSERT_NO_THROW(client2.doSARR());
+
+ // The ADVERTISE should have been returned but not REPLAY, as this
+ // packet got parked too.
+ ASSERT_FALSE(client2.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed.
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // There should be now two actions scheduled on our IO service
+ // by the invoked callouts. They unpark both REPLY messages.
+ ASSERT_NO_THROW(io_service_->poll());
+
+ // Receive and check the first response.
+ ASSERT_NO_THROW(client1.receiveResponse());
+ ASSERT_TRUE(client1.getContext().response_);
+ Pkt6Ptr rsp = client1.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client1.hasLeaseForPrefix(IOAddress("2001:db8:1:28::"), 64));
+
+ // Receive and check the second response.
+ ASSERT_NO_THROW(client2.receiveResponse());
+ ASSERT_TRUE(client2.getContext().response_);
+ rsp = client2.getContext().response_;
+ EXPECT_EQ(DHCPV6_REPLY, rsp->getType());
+ EXPECT_TRUE(client2.hasLeaseForPrefix(IOAddress("2001:db8:1:29::"), 64));
+}
+
+// This test verifies that incoming (positive) RENEW can be handled properly,
+// and the lease6_renew callouts are triggered.
+TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
+ NakedDhcpv6Srv srv(0);
+
+ // Install lease6_renew_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_renew", lease6_renew_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 RENEW.
+ 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 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);
+ 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) RENEW can be handled properly,
+// and the lease6_renew callouts are able to set the skip flag that will
+// reject the renewal
+TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
+ NakedDhcpv6Srv srv(0);
+
+ // Install lease6_renew_skip_callout
+ EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "lease6_renew", lease6_renew_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 RENEW.
+ 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 RENEW
+ Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+ req->setRemoteAddr(IOAddress("fe80::abcd"));
+ req->setIface("eth0");
+ boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+
+ OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(renewed_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+
+ // Server-id is mandatory in RENEW
+ req->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRenew(req);
+ ASSERT_TRUE(reply);
+
+ // Check that our callback was called
+ EXPECT_EQ("lease6_renew", 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 renewal
+ 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 verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of RENEW message sent to allocate new
+// lease or renew an existing lease.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Renew the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRenew());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Renewed lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Let's try to renew again but force the client to renew a different
+ // address with a different IAID.
+ client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
+
+ ASSERT_NO_THROW(client.doRenew());
- // 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());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // 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_);
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // 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));
+ // New lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
- EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
-}
+ // The old lease is kept.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
-// This test verifies that incoming (positive) RENEW can be handled properly,
-// and the lease6_renew callouts are able to set the skip flag that will
-// reject the renewal
-TEST_F(HooksDhcpv6SrvTest, skipLease6Renew) {
- NakedDhcpv6Srv srv(0);
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
- // Install lease6_renew_skip_callout
- EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
- "lease6_renew", lease6_renew_skip_callout));
+ resetCalloutBuffers();
- const IOAddress addr("2001:db8:1:1::cafe:babe");
- const uint32_t iaid = 234;
+ // The renewed address is just a hint.
+ client.requestAddress(0x5577, IOAddress("4000::2"));
- // Generate client-id also duid_
- OptionPtr clientid = generateClientId();
+ ASSERT_NO_THROW(client.doRenew());
- // Check that the address we are about to use is indeed in pool
- ASSERT_TRUE(subnet_->inPool(Lease::TYPE_NA, addr));
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
- // value on purpose. They should be updated during RENEW.
- 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 callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Check that the lease is really in the database
- Lease6Ptr l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(2);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
- // 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));
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
- // Let's create a RENEW
- Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
- req->setRemoteAddr(IOAddress("fe80::abcd"));
- req->setIface("eth0");
- boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
+ resetCalloutBuffers();
- OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(renewed_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
+ // Renew a prefix: this should lead to an error as no prefix pool
+ // is configured.
+ client.requestPrefix(0x1122, 64, IOAddress("2001:db8:1000::"));
- // Server-id is mandatory in RENEW
- req->addOption(srv.getServerID());
+ ASSERT_NO_THROW(client.doRenew());
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRenew(req);
- ASSERT_TRUE(reply);
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
- // Check that our callback was called
- EXPECT_EQ("lease6_renew", callback_name_);
+ // Check the error.
+ EXPECT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(0x1122));
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, addr);
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Check that the old values are still there and they were not
- // updated by the renewal
- 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));
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
}
// This test verifies that the callout installed on the leases6_committed hook
// point is executed as a result of RENEW message sent to allocate new
-// lease or renew an existing lease.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenew) {
+// lease or renew an existing lease. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRenewPrefix) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
- " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
" \"subnet\": \"2001:db8:1::/48\", "
" \"interface\": \"eth1\" "
" } ],"
Dhcp6Client client;
client.setInterface("eth1");
- client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
ASSERT_NO_THROW(configure(config, *client.getServer()));
ASSERT_EQ(1, callback_new_leases6_->size());
Lease6Ptr lease = callback_new_leases6_->at(0);
ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
// Deleted lease must not be present, because it is a new allocation.
ASSERT_TRUE(callback_deleted_leases6_);
ASSERT_EQ(1, callback_new_leases6_->size());
lease = callback_new_leases6_->at(0);
ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
// Deleted lease must not be present, because it is a new allocation.
ASSERT_TRUE(callback_deleted_leases6_);
resetCalloutBuffers();
// Let's try to renew again but force the client to renew a different
- // address with a different IAID.
- client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
+ // prefix with a different IAID.
+ client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
ASSERT_NO_THROW(client.doRenew());
ASSERT_EQ(2, callback_new_leases6_->size());
lease = callback_new_leases6_->at(1);
ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
+ EXPECT_EQ("2001:db8:1:29::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
// The old lease is kept.
ASSERT_TRUE(callback_deleted_leases6_);
resetCalloutBuffers();
- // The renewed address is just a hint.
- client.requestAddress(0x5577, IOAddress("4000::2"));
+ // The renewed prefix is just a hint.
+ client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
ASSERT_NO_THROW(client.doRenew());
lease = callback_new_leases6_->at(2);
ASSERT_TRUE(lease);
EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
ASSERT_TRUE(callback_deleted_leases6_);
EXPECT_TRUE(callback_deleted_leases6_->empty());
resetCalloutBuffers();
- // Renew a prefix: this should lead to an error as no prefix pool
+ // Renew an address: this should lead to an error as no address pool
// is configured.
- client.requestPrefix(0x1122, 64, IOAddress("2001:db8:1000::"));
+ client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
ASSERT_NO_THROW(client.doRenew());
ASSERT_TRUE(client.getContext().response_);
// Check the error.
- EXPECT_EQ(STATUS_NoPrefixAvail, client.getStatusCode(0x1122));
+ EXPECT_EQ(STATUS_NoAddrsAvail, client.getStatusCode(0x1122));
// Check that the callback called is indeed the one we installed
EXPECT_EQ("leases6_committed", callback_name_);
EXPECT_TRUE(callback_deleted_leases6_->empty());
}
-//// same with prefix
-
// This test verifies that incoming (positive) RELEASE can be handled properly,
// that a REPLY is generated, that the response has status code and that the
// lease is indeed removed from the database.
req->setRemoteAddr(IOAddress("fe80::abcd"));
boost::shared_ptr<Option6IA> ia = generateIA(D6O_IA_NA, iaid, 1500, 3000);
- OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
- ia->addOption(released_addr_opt);
- req->addOption(ia);
- req->addOption(clientid);
+ OptionPtr released_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+ ia->addOption(released_addr_opt);
+ req->addOption(ia);
+ req->addOption(clientid);
+
+ // Server-id is mandatory in RELEASE
+ req->addOption(srv.getServerID());
+
+ // Pass it to the server and hope for a REPLY
+ Pkt6Ptr reply = srv.processRelease(req);
+
+ ASSERT_TRUE(reply);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("lease6_release", callback_name_);
+
+ // Check that the lease is still there
+ // get lease by address
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ addr);
+ ASSERT_TRUE(l);
+
+ // Get lease by subnetid/duid/iaid combination
+ l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
+ subnet_->getID());
+ ASSERT_TRUE(l);
+}
+
+// This test verifies that the leases6_committed callout is executed
+// with deleted leases as argument when RELEASE is processed.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRelease) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(client.doSARR());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doRelease());
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // No new allocations.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_TRUE(callback_new_leases6_->empty());
+
+ // Released lease should be returned.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_EQ(1, callback_deleted_leases6_->size());
+ Lease6Ptr lease = callback_deleted_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+}
+
+// This test verifies that the leases6_committed callout is executed
+// with deleted leases as argument when RELEASE is processed. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedReleasePrefix) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(client.doSARR());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doRelease());
- // Server-id is mandatory in RELEASE
- req->addOption(srv.getServerID());
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
- // Pass it to the server and hope for a REPLY
- Pkt6Ptr reply = srv.processRelease(req);
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
- ASSERT_TRUE(reply);
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
- // Check that the callback called is indeed the one we installed
- EXPECT_EQ("lease6_release", callback_name_);
+ // No new allocations.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_TRUE(callback_new_leases6_->empty());
- // Check that the lease is still there
- // get lease by address
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
- addr);
- ASSERT_TRUE(l);
+ // Released lease should be returned.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_EQ(1, callback_deleted_leases6_->size());
+ Lease6Ptr lease = callback_deleted_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
- // Get lease by subnetid/duid/iaid combination
- l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
- subnet_->getID());
- ASSERT_TRUE(l);
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that the leases6_committed callout is executed
// with deleted leases as argument when RELEASE is processed.
-TEST_F(HooksDhcpv6SrvTest, leases6CommittedRelease) {
+// Variant with two addresses and two prefixes.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedReleaseMultiple) {
IfaceMgrTestConfig test_config(true);
string config = "{ \"interfaces-config\": {"
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
- " \"subnet\": \"2001:db8:1::/48\", "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:2::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8::/32\", "
" \"interface\": \"eth1\" "
" } ],"
"\"valid-lifetime\": 4000 }";
Dhcp6Client client;
client.setInterface("eth1");
+ // In theory we can reuse the IAID but copyIAsFromLeases() copies
+ // only one lease...
client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestPrefix(0xabcb, 64, IOAddress("2001:db8:2:28::"));
+ client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
+ client.requestPrefix(0x2234, 64, IOAddress("2001:db8:2:29::"));
ASSERT_NO_THROW(configure(config, *client.getServer()));
// Released lease should be returned.
ASSERT_TRUE(callback_deleted_leases6_);
- EXPECT_EQ(1, callback_deleted_leases6_->size());
- Lease6Ptr lease = callback_deleted_leases6_->at(0);
- ASSERT_TRUE(lease);
- EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ EXPECT_EQ(4, callback_deleted_leases6_->size());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
}
-//// same with prefix
-//// same with addresses and prefixes (2+2)
-
// This test verifies that incoming (positive) REBIND can be handled properly,
// and the lease6_rebind callouts are triggered.
TEST_F(HooksDhcpv6SrvTest, basicLease6Rebind) {
EXPECT_TRUE(callback_deleted_leases6_->empty());
}
-//// same with prefix
+// This test verifies that the callout installed on the leases6_committed hook
+// point is executed as a result of REBIND message sent to allocate new
+// lease or renew an existing lease. Prefix variant.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedRebindPrefix) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pd-pools\": [ {"
+ " \"prefix\": \"2001:db8:1::\", "
+ " \"prefix-len\": 56, "
+ " \"delegated-len\": 64 } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestPrefix(0xabca, 64, IOAddress("2001:db8:1:28::"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Newly allocated lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Rebind the lease and make sure that the callout has been executed.
+ ASSERT_NO_THROW(client.doRebind());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Rebound lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:28::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // Deleted lease must not be present, because it is a new allocation.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Let's try to rebind again but force the client to rebind a different
+ // prefix with a different IAID.
+ client.requestPrefix(0x2233, 64, IOAddress("2001:db8:1:29::"));
+
+ ASSERT_NO_THROW(client.doRebind());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // New lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:29::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+
+ // The old lease is kept.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // The rebound prefix is just a hint.
+ client.requestPrefix(0x5577, 64, IOAddress("4000::1"));
+
+ ASSERT_NO_THROW(client.doRebind());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ lease = callback_new_leases6_->at(2);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::", lease->addr_.toText());
+ EXPECT_EQ(64, lease->prefixlen_);
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+
+ resetCalloutBuffers();
+
+ // Rebind an address: this should lead to an error as no address pool
+ // is configured.
+ client.requestAddress(0x1122, IOAddress("2001:db8:1::28"));
+
+ ASSERT_NO_THROW(client.doRebind());
+
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ // Check the error.
+ EXPECT_EQ(STATUS_NoAddrsAvail, client.getStatusCode(0x1122));
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ ASSERT_TRUE(callback_new_leases6_);
+ EXPECT_EQ(3, callback_new_leases6_->size());
+ ASSERT_TRUE(callback_deleted_leases6_);
+ EXPECT_TRUE(callback_deleted_leases6_->empty());
+}
// This test checks that the basic decline hook (lease6_decline) is
// triggered properly.
// Declined lease should be returned.
ASSERT_TRUE(callback_new_leases6_);
- EXPECT_EQ(1, callback_new_leases6_->size());
+ ASSERT_EQ(1, callback_new_leases6_->size());
+ Lease6Ptr lease = callback_new_leases6_->at(0);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+}
+
+// This test verifies that the leases6_committed callout is executed
+// with deleted leases as argument when DECLINE is processed.
+// Variant with 2 IA_NAs.
+TEST_F(HooksDhcpv6SrvTest, leases6CommittedDeclineTwoNAs) {
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ Dhcp6Client client;
+ client.setInterface("eth1");
+ client.requestAddress(0xabca, IOAddress("2001:db8:1::28"));
+ client.requestAddress(0x2233, IOAddress("2001:db8:1::29"));
+
+ ASSERT_NO_THROW(configure(config, *client.getServer()));
+
+ ASSERT_NO_THROW(client.doSARR());
+ // Make sure that we received a response
+ ASSERT_TRUE(client.getContext().response_);
+
+ ASSERT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+ "leases6_committed", leases6_committed_callout));
+
+ ASSERT_NO_THROW(client.doDecline());
+
+ // Check that the callback called is indeed the one we installed
+ EXPECT_EQ("leases6_committed", callback_name_);
+
+ // Check if all expected parameters were really received
+ vector<string> expected_argument_names;
+ expected_argument_names.push_back("query6");
+ expected_argument_names.push_back("deleted_leases6");
+ expected_argument_names.push_back("leases6");
+
+ sort(expected_argument_names.begin(), expected_argument_names.end());
+ EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // No deleted leases.
+ ASSERT_TRUE(callback_deleted_leases6_);
+ ASSERT_TRUE(callback_deleted_leases6_->empty());
+
+ // Declined lease should be returned.
+ ASSERT_TRUE(callback_new_leases6_);
+ ASSERT_EQ(2, callback_new_leases6_->size());
Lease6Ptr lease = callback_new_leases6_->at(0);
ASSERT_TRUE(lease);
EXPECT_EQ("2001:db8:1::28", lease->addr_.toText());
+ lease = callback_new_leases6_->at(1);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::29", lease->addr_.toText());
// Pkt passed to a callout must be configured to copy retrieved options.
EXPECT_TRUE(callback_qry_options_copy_);
}
-//// same with 2 IA_NA
-//// same with an IA_NA with 2 addresses (if I can get an example)
+// Should test with one NA and two addresses but need an example first...
// Checks if callout installed on host6_identifier can generate an
// identifier and whether that identifier is actually used.