" \"interface\": \"eth0\"\n"
" }\n"
"]\n"
- "}"
+ "}",
+
+ // Configuration 8 both global and in-subnet
+ // 2 subnets, one reservations flags default (aka in-subnet),
+ // one reservations flags global and in-subnet.
+ // Host reservations for the same client, one global, one in each subnet
+ "{ \"interfaces-config\": {\n"
+ " \"interfaces\": [ \"*\" ]\n"
+ "},\n"
+ "\"valid-lifetime\": 600,\n"
+ "\"reservations\": [ \n"
+ "{\n"
+ " \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n"
+ " \"hostname\": \"global-host\"\n"
+ "}\n"
+ "],\n"
+ "\"subnet4\": [\n"
+ " {\n"
+ " \"subnet\": \"10.0.0.0/24\", \n"
+ " \"id\": 10,"
+ " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ],\n"
+ " \"interface\": \"eth0\",\n"
+ " \"reservations\": [ \n"
+ " {\n"
+ " \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n"
+ " \"hostname\": \"subnet-10-host\"\n"
+ " }]\n"
+ " },\n"
+ " {\n"
+ " \"subnet\": \"192.0.2.0/26\", \n"
+ " \"id\": 20,"
+ " \"pools\": [ { \"pool\": \"192.0.2.10-192.0.2.63\" } ],\n"
+ " \"interface\": \"eth1\",\n"
+ " \"reservations-global\": true,\n"
+ " \"reservations-in-subnet\": true,\n"
+ " \"reservations\": [ \n"
+ " {\n"
+ " \"hw-address\": \"aa:bb:cc:dd:ee:ff\",\n"
+ " \"hostname\": \"subnet-20-host\"\n"
+ " }]\n"
+ " }\n"
+ "]\n"
+ "}\n"
};
/// @brief Test fixture class for testing global v4 reservations.
runDoraTest(CONFIGS[3], client, "subnet-10-host", "10.0.0.105");
}
+// Verifies that when there are matching reservations at
+// both the global and subnet levels, client will be matched
+// to the subnet reservation, when subnet reservation true flags
+// are global and in-subnet, i.e. the subnet has the preference.
+TEST_F(HostTest, subnetOverGlobal) {
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+
+ // Hardware address matches all reservations
+ client.setHWAddress("aa:bb:cc:dd:ee:ff");
+
+ // Change to subnet 20
+ client.setIfaceName("eth1");
+ client.setIfaceIndex(ETH1_INDEX);
+
+ // Subnet 20 uses both global and in-subnet reservations flags,
+ // so the subnet reservation has the preference.
+ runDoraTest(CONFIGS[8], client, "subnet-20-host", "192.0.2.10");
+}
+
// Verifies that client class specified in the global reservation
// may be used to influence pool selection.
TEST_F(HostTest, clientClassGlobalPoolSelection) {
" \"client-classes\": [ \"reserved_class\" ]\n"
"}\n"
"],\n"
- "\"shared-networks\": [{"
+ "\"shared-networks\": [{"
" \"name\": \"frog\",\n"
" \"subnet6\": [\n"
" {\n"
// Should get dynamic address and host name
ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
}
+
+ {
+ SCOPED_TRACE("Subnet reservation preferred over global");
+ // Patch the second subnet to both global and in-subnet.
+ Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+ getCfgSubnets6()->getSubnet(2);
+ ASSERT_TRUE(subnet);
+ subnet->setHostReservationMode(Network::HR_IN_SUBNET|Network::HR_GLOBAL);
+ client.clearConfig();
+ client.setInterface("eth1");
+ client.setDUID("01:02:03:05");
+ client.requestAddress(1234, IOAddress("::"));
+ // Should get dynamic address and host name because it has preference
+ ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:2::1", "subnet-duid-host"));
+ }
}
// Verifies fundamental Global vs Subnet host reservations for PD leases
// Should get dynamic prefix and subnet reserved host name
ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
}
+
+ {
+ SCOPED_TRACE("Subnet reservation preferred over global");
+ // Patch the second subnet to both global and in-subnet.
+ Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg()->
+ getCfgSubnets6()->getSubnet(2);
+ ASSERT_TRUE(subnet);
+ subnet->setHostReservationMode(Network::HR_IN_SUBNET|Network::HR_GLOBAL);
+ client.clearConfig();
+ client.setInterface("eth1");
+ client.setDUID("01:02:03:05");
+ client.requestPrefix(1);
+ // Should get dynamic prefix and subnet reserved host name
+ // because it has preference over the global reservation.
+ ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::100", "subnet-duid-host"));
+ }
}
// Verifies that client class specified in the global reservation
return;
}
- if (allocateGlobalReservedLeases6(ctx, existing_leases)) {
- // global reservation provided the lease, we're done
- return;
- }
-
// Let's convert this from Lease::Type to IPv6Reserv::Type
IPv6Resrv::Type type = ctx.currentIA().type_ == Lease::TYPE_NA ?
IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD;
}
}
}
+
+ // Found no subnet reservations so now try the global reservation.
+ allocateGlobalReservedLeases6(ctx, existing_leases);
}
-bool
+void
AllocEngine::allocateGlobalReservedLeases6(ClientContext6& ctx,
Lease6Collection& existing_leases) {
// Get the global host
ConstHostPtr ghost = ctx.globalHost();
if (!ghost) {
- return (false);
+ return;
}
// We want to avoid allocating a new lease for an IA if there is already
LeaseMgrFactory::instance().updateLease6(lease);
}
- return(true);
+ return;
}
}
// a lease corresponding to it and will skip it and then pick
// the second reservation and turn it into the lease. This approach
// would work for any number of reservations.
- return (true);
+ return;
}
}
-
- return(false);
}
void
///
/// @param ctx client context that contains all details (subnet, client-id, etc.)
/// @param existing_leases leases that are already associated with the client
- bool
+ void
allocateGlobalReservedLeases6(ClientContext6& ctx, Lease6Collection& existing_leases);
/// @brief Removes leases that are reserved for someone else.
EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
- // We should allocate the reserverd address.
+ // We should allocate the reserved address.
Lease4Ptr lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_EQ("192.0.77.123", lease->addr_.toText());
EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
- // We should allocate the reserverd address.
+ // We should allocate the reserved address.
Lease4Ptr lease = engine.allocateLease4(ctx);
ASSERT_TRUE(lease);
EXPECT_EQ("192.0.77.123", lease->addr_.toText());
EXPECT_FALSE(ctx.old_lease_);
}
+// This test checks the behavior of the allocation engine in the following
+// scenario:
+// - Client has no lease in the database.
+// - Client has a subnet reservation.
+// - Client sends DISCOVER
+// - Client is allocated the reserved address.
+// - Lease is not added to the lease database
+TEST_F(AllocEngine4Test, mixedReservationReservedAddressDiscover) {
+ // Create reservation for the client.
+ HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, subnet_->getID(),
+ SUBNET_ID_UNUSED, IOAddress("192.0.2.123"),
+ "foo.example.org"));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 0, false);
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Query allocation engine for the lease to be assigned to this
+ // client without specifying the address to be assigned.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
+ IOAddress("0.0.0.0"), false, false,
+ "", true);
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+
+ // Look up the host.
+ AllocEngine::findReservation(ctx);
+
+ // We should have the correct current host
+ EXPECT_TRUE(ctx.currentHost());
+ EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
+ EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
+
+ // We should allocate the reserved address.
+ Lease4Ptr lease = engine.allocateLease4(ctx);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("192.0.2.123", lease->addr_.toText());
+
+ // This is a "fake" allocation so the returned lease should not be committed
+ // to the lease database.
+ EXPECT_FALSE(LeaseMgrFactory::instance().getLease4(lease->addr_));
+
+ // Client had no lease in the database, so the old lease returned should
+ // be NULL.
+ EXPECT_FALSE(ctx.old_lease_);
+}
+
+// This test checks the behavior of the allocation engine in the following
+// scenario:
+// - Client has no lease in the database.
+// - Client has a subnet reservation.
+// - Client sends REQUEST
+// - Client is allocated the reserved address.
+// - Lease is added to the lease database
+TEST_F(AllocEngine4Test, mixedReservationReservedAddressRequest) {
+ // Create reservation for the client.
+ HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, subnet_->getID(),
+ SUBNET_ID_UNUSED, IOAddress("192.0.2.123"),
+ "foo.example.org"));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 0, false);
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Query allocation engine for the lease to be assigned to this
+ // client without specifying the address to be assigned.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
+ IOAddress("0.0.0.0"), false, false,
+ "", false);
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+ // Look up the host.
+ AllocEngine::findReservation(ctx);
+
+ // We should have the correct current host
+ EXPECT_TRUE(ctx.currentHost());
+ EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
+ EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
+
+ // We should allocate the reserved address.
+ Lease4Ptr lease = engine.allocateLease4(ctx);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("192.0.2.123", lease->addr_.toText());
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease(lease, from_mgr);
+
+ // Client had no lease in the database, so the old lease returned should
+ // be NULL.
+ EXPECT_FALSE(ctx.old_lease_);
+}
+
+// This test checks the behavior of the allocation engine in the following
+// scenario:
+// - Client has no lease in the database.
+// - Client has a global and a subnet reservation.
+// - Client sends DISCOVER
+// - Client is allocated the reserved address.
+// - Lease is not added to the lease database
+TEST_F(AllocEngine4Test, bothReservationReservedAddressDiscover) {
+ // Create reservations for the client.
+ HostPtr ghost(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, SUBNET_ID_GLOBAL,
+ SUBNET_ID_UNUSED, IOAddress("192.0.77.123")));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(ghost);
+ HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, subnet_->getID(),
+ SUBNET_ID_UNUSED, IOAddress("192.0.2.123"),
+ "foo.example.org"));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 0, false);
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Query allocation engine for the lease to be assigned to this
+ // client without specifying the address to be assigned.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
+ IOAddress("0.0.0.0"), false, false,
+ "", true);
+ ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234));
+
+ // Look up the host.
+ AllocEngine::findReservation(ctx);
+
+ // We should have the correct current host
+ EXPECT_TRUE(ctx.currentHost());
+ EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
+ EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
+
+ // We should allocate the reserved address.
+ Lease4Ptr lease = engine.allocateLease4(ctx);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("192.0.2.123", lease->addr_.toText());
+
+ // This is a "fake" allocation so the returned lease should not be committed
+ // to the lease database.
+ EXPECT_FALSE(LeaseMgrFactory::instance().getLease4(lease->addr_));
+
+ // Client had no lease in the database, so the old lease returned should
+ // be NULL.
+ EXPECT_FALSE(ctx.old_lease_);
+}
+
+// This test checks the behavior of the allocation engine in the following
+// scenario:
+// - Client has no lease in the database.
+// - Client has a global and a subnet reservation.
+// - Client sends REQUEST
+// - Client is allocated the reserved address.
+// - Lease is added to the lease database
+TEST_F(AllocEngine4Test, bothReservationReservedAddressRequest) {
+ // Create reservations for the client.
+ HostPtr ghost(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, SUBNET_ID_GLOBAL,
+ SUBNET_ID_UNUSED, IOAddress("192.0.77.123")));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(ghost);
+ HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+ Host::IDENT_HWADDR, subnet_->getID(),
+ SUBNET_ID_UNUSED, IOAddress("192.0.2.123"),
+ "foo.example.org"));
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 0, false);
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Query allocation engine for the lease to be assigned to this
+ // client without specifying the address to be assigned.
+ AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
+ IOAddress("0.0.0.0"), false, false,
+ "", false);
+ ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+ // Look up the host.
+ AllocEngine::findReservation(ctx);
+
+ // We should have the correct current host
+ EXPECT_TRUE(ctx.currentHost());
+ EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname());
+ EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation());
+
+ // We should allocate the reserved address.
+ Lease4Ptr lease = engine.allocateLease4(ctx);
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("192.0.2.123", lease->addr_.toText());
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease(lease, from_mgr);
+
+ // Client had no lease in the database, so the old lease returned should
+ // be NULL.
+ EXPECT_FALSE(ctx.old_lease_);
+}
+
// Exercises AllocEnginer4Test::updateExtendedInfo4() through various
// permutations of client packet content.
HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_->getID(),
asiolink::IOAddress("0.0.0.0")));
-
host->setHostname("host1");
CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
<< "Lease lifetime was not extended, but it should";
}
+// Verifies that client with a subnet address reservation can get and
+// renew a lease for an address in the subnet.
+TEST_F(AllocEngine6Test, mixedHostReservedAddress) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+ ASSERT_TRUE(engine);
+
+ HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_->getID(),
+ asiolink::IOAddress("0.0.0.0")));
+ host->setHostname("mhost1");
+ IPv6Resrv resv(IPv6Resrv::TYPE_NA, asiolink::IOAddress("2001:db8:1::1c"), 128);
+ host->addReservation(resv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Create context which will be used to try to allocate leases
+ Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
+ AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query);
+ ctx.currentIA().iaid_ = iaid_;
+
+ // Look up the reservation.
+ findReservation(*engine, ctx);
+ // Make sure we found our host.
+ ConstHostPtr current = ctx.currentHost();
+ ASSERT_TRUE(current);
+ ASSERT_EQ("mhost1", current->getHostname());
+
+ // Check that we have been allocated the fixed address.
+ Lease6Ptr lease;
+ ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::1c", lease->addr_.toText());
+
+ // We're going to rollback the clock a little so we can verify a renewal.
+ // We verify the "time" change in case the lease returned to us
+ // by expectOneLease ever becomes a copy and not what is in the lease mgr.
+ --lease->cltt_;
+ lease->updateCurrentExpirationTime();
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+ lease->addr_);
+ ASSERT_TRUE(from_mgr);
+ EXPECT_EQ(from_mgr->cltt_, lease->cltt_);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::1c"), 128));
+
+ // Set test fixture hostname_ to the expected value. This gets checked in
+ // renewTest.
+ hostname_ = "mhost1";
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(*engine, pool_, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease->cltt_)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Verifies that client with a subnet prefix reservation can get and
+// renew a lease for a prefix in the subnet.
+TEST_F(AllocEngine6Test, mixedHostReservedPrefix) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+ ASSERT_TRUE(engine);
+
+ HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_->getID(),
+ asiolink::IOAddress("0.0.0.0")));
+ host->setHostname("mhost1");
+ IPv6Resrv resv(IPv6Resrv::TYPE_PD, asiolink::IOAddress("2001:db8:1:2::"), 64);
+ host->addReservation(resv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Create context which will be used to try to allocate leases
+ Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
+ AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query);
+ ctx.currentIA().type_ = Lease::TYPE_PD;
+ ctx.currentIA().iaid_ = iaid_;
+
+ // Look up the reservation.
+ findReservation(*engine, ctx);
+ // Make sure we found our host.
+ ConstHostPtr current = ctx.currentHost();
+ ASSERT_TRUE(current);
+ ASSERT_EQ("mhost1", current->getHostname());
+
+ // Check that we have been allocated the fixed prefix.
+ Lease6Ptr lease;
+ ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:2::", lease->addr_.toText());
+
+ // We're going to rollback the clock a little so we can verify a renewal.
+ // We verify the "time" change in case the lease returned to us
+ // by expectOneLease ever becomes a copy and not what is in the lease mgr.
+ --lease->cltt_;
+ lease->updateCurrentExpirationTime();
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+ lease->addr_);
+ ASSERT_TRUE(from_mgr);
+ EXPECT_EQ(from_mgr->cltt_, lease->cltt_);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1:2::"), 64));
+
+ // Set test fixture hostname_ to the expected value. This gets checked via
+ // renewTest.
+ hostname_ = "mhost1";
+
+ // We need a PD pool to fake renew_test
+ Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64));
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease->cltt_)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Verifies that client with a subnet and a global address reservation
+// can get and renew a lease for an address in the subnet.
+TEST_F(AllocEngine6Test, bothHostReservedAddress) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+ ASSERT_TRUE(engine);
+
+ HostPtr ghost(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, SUBNET_ID_GLOBAL,
+ asiolink::IOAddress("0.0.0.0")));
+ ghost->setHostname("ghost1");
+ IPv6Resrv gresv(IPv6Resrv::TYPE_NA, asiolink::IOAddress("3001::1"), 128);
+ ghost->addReservation(gresv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(ghost);
+
+ HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_->getID(),
+ asiolink::IOAddress("0.0.0.0")));
+ host->setHostname("mhost1");
+ IPv6Resrv resv(IPv6Resrv::TYPE_NA, asiolink::IOAddress("2001:db8:1::1c"), 128);
+ host->addReservation(resv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Create context which will be used to try to allocate leases
+ Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
+ AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query);
+ ctx.currentIA().iaid_ = iaid_;
+
+ // Look up the reservation.
+ findReservation(*engine, ctx);
+ // Make sure we found our host.
+ ConstHostPtr current = ctx.currentHost();
+ ASSERT_TRUE(current);
+ ASSERT_EQ("mhost1", current->getHostname());
+
+ // Check that we have been allocated the fixed address.
+ Lease6Ptr lease;
+ ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1::1c", lease->addr_.toText());
+
+ // We're going to rollback the clock a little so we can verify a renewal.
+ // We verify the "time" change in case the lease returned to us
+ // by expectOneLease ever becomes a copy and not what is in the lease mgr.
+ --lease->cltt_;
+ lease->updateCurrentExpirationTime();
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+ lease->addr_);
+ ASSERT_TRUE(from_mgr);
+ EXPECT_EQ(from_mgr->cltt_, lease->cltt_);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::1c"), 128));
+
+ // Set test fixture hostname_ to the expected value. This gets checked in
+ // renewTest.
+ hostname_ = "mhost1";
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(*engine, pool_, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease->cltt_)
+ << "Lease lifetime was not extended, but it should";
+}
+
+// Verifies that client with a subnet and a global prefix reservation
+// can get and renew a lease for a prefix in the subnet.
+TEST_F(AllocEngine6Test, bothHostReservedPrefix) {
+ boost::scoped_ptr<AllocEngine> engine;
+ ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+ ASSERT_TRUE(engine);
+
+ HostPtr ghost(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, SUBNET_ID_GLOBAL,
+ asiolink::IOAddress("0.0.0.0")));
+ ghost->setHostname("ghost1");
+ IPv6Resrv gresv(IPv6Resrv::TYPE_PD, asiolink::IOAddress("3001::"), 64);
+ ghost->addReservation(gresv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(ghost);
+
+ HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+ Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_->getID(),
+ asiolink::IOAddress("0.0.0.0")));
+ host->setHostname("mhost1");
+ IPv6Resrv resv(IPv6Resrv::TYPE_PD, asiolink::IOAddress("2001:db8:1:2::"), 64);
+ host->addReservation(resv);
+
+ CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+ CfgMgr::instance().commit();
+
+ subnet_->setHostReservationMode(Network::HR_GLOBAL|Network::HR_IN_SUBNET);
+
+ // Create context which will be used to try to allocate leases
+ Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234));
+ AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query);
+ ctx.currentIA().type_ = Lease::TYPE_PD;
+ ctx.currentIA().iaid_ = iaid_;
+
+ // Look up the reservation.
+ findReservation(*engine, ctx);
+ // Make sure we found our host.
+ ConstHostPtr current = ctx.currentHost();
+ ASSERT_TRUE(current);
+ ASSERT_EQ("mhost1", current->getHostname());
+
+ // Check that we have been allocated the fixed prefix.
+ Lease6Ptr lease;
+ ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+ ASSERT_TRUE(lease);
+ EXPECT_EQ("2001:db8:1:2::", lease->addr_.toText());
+
+ // We're going to rollback the clock a little so we can verify a renewal.
+ // We verify the "time" change in case the lease returned to us
+ // by expectOneLease ever becomes a copy and not what is in the lease mgr.
+ --lease->cltt_;
+ lease->updateCurrentExpirationTime();
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+ lease->addr_);
+ ASSERT_TRUE(from_mgr);
+ EXPECT_EQ(from_mgr->cltt_, lease->cltt_);
+
+ // This is what the client will send in his renew message.
+ AllocEngine::HintContainer hints;
+ hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1:2::"), 64));
+
+ // Set test fixture hostname_ to the expected value. This gets checked via
+ // renewTest.
+ hostname_ = "mhost1";
+
+ // We need a PD pool to fake renew_test
+ Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64));
+
+ // Client should receive a lease.
+ Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true);
+ ASSERT_EQ(1, renewed.size());
+
+ // And the lease lifetime should be extended.
+ EXPECT_GT(renewed[0]->cltt_, lease->cltt_)
+ << "Lease lifetime was not extended, but it should";
+}
+
/// @brief Test fixture class for testing storage of extended lease data.
/// It primarily creates several configuration items common to the
/// extended info tests.