/// @brief Array of server configurations used throughout the tests.
const char* NETWORKS_CONFIG[] = {
// Configuration #0.
+// - one shared network with two subnets, each with address and prefix pools
+// - one plain subnet
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #1.
+// - one shared network with relay-ip specified and one subnet with address pool
+// - one plain subnet with relay-ip specified and one address pool
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #2.
+// - two classes specified
+// - one shared network with two subnets (the first has class restrictions)
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"a-devices\","
"}",
// Configuration #3.
+// - two classes defined
+// - one shared network with two subnets, each with a different class restriction
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"a-devices\","
"}",
// Configuration #4.
+// - one shared network with two subnets. Each subnet has:
+// - address and prefix pool
+// - reservation
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
" ]"
"}",
-// Configuration #5.
+// Configuration #5 (similar to #4, but without prefix pool and using different
+// DUID for reservations)
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #6.
+// - one class
+// - one shared network with two subnets:
+// - first subnet has address pool, class restriction and a reservation
+// - second subnet has just an address pool
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"a-devices\","
"}",
// Configuration #7.
+// - option defined on global level
+// - one shared network with two options and two subnets
+// - the first subnet has its own options defined as well
+// - plain subnet with its own options
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"option-data\": ["
" {"
" \"name\": \"nis-servers\","
"}",
// Configuration #8.
+// - two shared networks
+// - first network with two subnets, each with its own address pool
+// - second network with two subnets, each with its own address pool
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
" ]"
"}",
-// Configuration #9.
+// Configuration #9 (similar to #8, but with relay-ip addresses specified)
+// - two shared networks, each with relay IP addresses specified
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #10.
+// - one class with an option (and not test expression)
+// - one shared network with two subnets
+// - first subnet with one address pool
+// - second with a pool and reservation that assigns client to a class
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"class-with-dns-servers\","
"}",
// Configuration #11.
+// - two classes defined
+// - two shared networks, each with one subnet and class restriction
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"a-devices\","
"}",
// Configuration #12.
+// - one client class
+// - one shared network with two subnets, the second subnet has class restriction
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"client-classes\": ["
" {"
" \"name\": \"b-devices\","
"}",
// Configuration #13.
+// - one shared network, with two subnets, each with the same relay-ip addresses
+// - one plain subnet, with its own (different) relay-ip address
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #14.
+// - one share network with interface-id specified and one subnet
+// - one plain subnet, with its own interface-id
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
"}",
// Configuration #15.
+// - one shared network, with two subnets, each with the same interface-id
+// - one plain subnet, with its own interface-id
"{"
- " \"interfaces-config\": {"
- " \"interfaces\": [ \"*\" ]"
- " },"
- " \"preferred-lifetime\": 3000,"
- " \"rebind-timer\": 2000, "
- " \"renew-timer\": 1000, "
" \"shared-networks\": ["
" {"
" \"name\": \"frog\","
" ]"
" }"
" ]"
+ "}",
+
+// Configuration #16
+// - one shared network with two subnets
+// - first subnet has the rapid commit enabled
+// - second subnet has the rapid commit disabled
+ "{"
+ " \"shared-networks\": ["
+ " {"
+ " \"name\": \"frog\","
+ " \"interface\": \"eth1\","
+ " \"subnet6\": ["
+ " {"
+ " \"subnet\": \"2001:db8:1::/64\","
+ " \"id\": 10,"
+ " \"rapid-commit\": true,"
+ " \"pools\": ["
+ " {"
+ " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\""
+ " }"
+ " ]"
+ " },"
+ " {"
+ " \"subnet\": \"2001:db8:2::/64\","
+ " \"id\": 100,"
+ " \"rapid-commit\": false,"
+ " \"pools\": ["
+ " {"
+ " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\""
+ " }"
+ " ]"
+ " }"
+ " ]"
+ " }"
+ " ]"
"}"
};
// Make sure that the subnet id is not messed up in the lease.
if (subnet->getID() != lease->subnet_id_) {
ADD_FAILURE() << "invalid subnet identifier found in the lease for"
- " address " << address;
+ " address " << address << ", expected " << subnet->getID()
+ << ", got " << lease->subnet_id_;
return (false);
}
}
ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20")));
}
+// Check that the rapid-commit works with shared networks:
+// - that it can be defined on per subnet basis
+// - that its value can be mixed (some subnets have enabled, others disabled)
+TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkRapidCommit) {
+
+ // Create client #1. This clients wants to use rapid-commit.
+ Dhcp6Client client1;
+ client1.setInterface("eth1");
+ client1.useRapidCommit(true);
+
+ Dhcp6Client client2;
+ client2.setInterface("eth1");
+ client2.useRapidCommit(true);
+
+ // Configure the server with a shared network.
+ ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[16], *client1.getServer()));
+
+ // Ok, client should have one
+ EXPECT_EQ(0, client1.getLeaseNum());
+
+ std::cout << "Client 1 got " << client1.getLeaseNum() << " lease(s): ";
+ for (int i = 0; i < client1.getLeaseNum(); i++) {
+ Lease6 lease = client1.getLease(i);
+ std::cout << lease.addr_.toText() << " ";
+ }
+ std::cout << std::endl;
+
+ // Client #1 should be assigned an address from shared network. The first
+ // subnet has rapid-commit enabled, so the address should be assigned.
+ ASSERT_NO_THROW(client1.requestAddress(0xabca0));
+ testAssigned([this, &client1] {
+ ASSERT_NO_THROW(client1.doSolicit());
+ });
+
+ std::cout << "Client 1 got " << client1.getLeaseNum() << " lease(s): ";
+ for (int i = 0; i < client1.getLeaseNum(); i++) {
+ Lease6 lease = client1.getLease(i);
+ std::cout << lease.addr_.toText() << " ";
+ }
+ std::cout << std::endl;
+
+ // Make sure that REPLY was sent back.
+ ASSERT_TRUE(client1.getContext().response_);
+ EXPECT_EQ(DHCPV6_REPLY, client1.getContext().response_->getType());
+
+ // Create client #2. This client behaves the same as the first one, but the
+ // first subnet is already full (it's a really small subnet) and the second
+ // subnet does not allow rapid-commit.
+ testAssigned([this, &client2] {
+ ASSERT_NO_THROW(client2.doSolicit());
+ });
+
+ EXPECT_EQ(0, client2.getLeaseNum());
+
+ // Make sure that ADVERTISE was sent back.
+ ASSERT_TRUE(client2.getContext().response_);
+ EXPECT_EQ(DHCPV6_ADVERTISE, client2.getContext().response_->getType());
+
+ // Just make sure the client didn't get an address.
+ EXPECT_FALSE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"),
+ LeaseOnServer::MUST_NOT_EXIST));
+}
+
} // end of anonymous namespace