EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
checkResult(x, 1);
+ }
+ /// The goal of this test is to verify that Host Reservation modes can be
+ /// specified on a per-subnet basis.
+ TEST_F(Dhcp4ParserTest, hostReservationPerSubnet) {
- "{ \"interfaces\": [ \"*\" ],"
+ /// - Configuration:
+ /// - only addresses (no prefixes)
+ /// - 4 subnets with:
+ /// - 192.0.2.0/24 (all reservations enabled)
+ /// - 192.0.3.0/24 (out-of-pool reservations)
+ /// - 192.0.4.0/24 (reservations disabled)
+ /// - 192.0.5.0/24 (reservations not specified)
+ const char* hr_config =
++ "{ "
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pools\": [ { \"pool\": \"192.0.2.0/24\" } ],"
+ " \"subnet\": \"192.0.2.0/24\", "
+ " \"reservation-mode\": \"all\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"192.0.3.0/24\" } ],"
+ " \"subnet\": \"192.0.3.0/24\", "
+ " \"reservation-mode\": \"out-of-pool\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"192.0.4.0/24\" } ],"
+ " \"subnet\": \"192.0.4.0/24\", "
+ " \"reservation-mode\": \"disabled\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"192.0.5.0/24\" } ],"
+ " \"subnet\": \"192.0.5.0/24\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ElementPtr json = Element::fromJSON(hr_config);
+ ConstElementPtr result;
+ EXPECT_NO_THROW(result = configureDhcp4Server(*srv_, json));
+
+ // returned value should be 0 (success)
+ checkResult(result, 0);
+
+ // Let's get all subnets and check that there are 4 of them.
+ ConstCfgSubnets4Ptr subnets = CfgMgr::instance().getStagingCfg()->getCfgSubnets4();
+ ASSERT_TRUE(subnets);
+ const Subnet4Collection* subnet_col = subnets->getAll();
+ ASSERT_EQ(4, subnet_col->size()); // We expect 4 subnets
+
+ // Let's check if the parsed subnets have correct HR modes.
+
+ // Subnet 1
+ Subnet4Ptr subnet;
+ subnet = subnets->selectSubnet(IOAddress("192.0.2.1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
+
+ // Subnet 2
+ subnet = subnets->selectSubnet(IOAddress("192.0.3.1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_OUT_OF_POOL, subnet->getHostReservationMode());
+
+ // Subnet 3
+ subnet = subnets->selectSubnet(IOAddress("192.0.4.1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_DISABLED, subnet->getHostReservationMode());
+
+ // Subnet 4
+ subnet = subnets->selectSubnet(IOAddress("192.0.5.1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
}
}
continue;
}
ctx.hints_.push_back(make_pair(iaaddr->getAddress(), 128));
-
- // We need to remember it as we'll be removing hints from this list as
- // we extend, cancel or otherwise deal with the leases.
- hints_count++;
}
+ // We need to remember it as we'll be removing hints from this list as
+ // we extend, cancel or otherwise deal with the leases.
+ bool hints_present = !ctx.hints_.empty();
+
+ /// @todo: This was clarfied in draft-ietf-dhc-dhcpv6-stateful-issues that
+ /// the server is allowed to assign new leases in both Renew and Rebind. For
+ /// now, we only support it in Renew, because it breaks a lot of Rebind
+ /// unit-tests. Ultimately, whether we allow it or not, should be exposed
+ /// as configurable policy. See ticket #3717.
+ if (query->getType() == DHCPV6_RENEW) {
+ ctx.allow_new_leases_in_renewals_ = true;
+ }
+
Lease6Collection leases = alloc_engine_->renewLeases6(ctx);
// Ok, now we have the leases extended. We have:
// Put the client's prefix into the hints list.
ctx.hints_.push_back(make_pair(prf->getAddress(), prf->getLength()));
-
- // We need to remember it as we'll be removing hints from this list as
- // we extend, cancel or otherwise deal with the leases.
- hints_count++;
}
+ // We need to remember it as we'll be removing hints from this list as
+ // we extend, cancel or otherwise deal with the leases.
+ bool hints_present = !ctx.hints_.empty();
+ /// @todo: The draft-ietf-dhc-dhcpv6-stateful-issues added a new capability
+ /// of the server to to assign new PD leases in both Renew and Rebind.
+ /// There's allow_new_leases_in_renewals_ in the ClientContext6, but we
+ /// currently not use it in PD yet. This should be implemented as part
+ /// of the stateful-issues implementation effort. See ticket #3718.
+
// Call Allocation Engine and attempt to renew leases. Number of things
// may happen. Leases may be extended, revoked (if the lease is no longer
// valid or reserved for someone else), or new leases may be added.
checkResult(status, 1);
}
- "{ \"interfaces\": [ \"*\" ],"
+ /// The goal of this test is to verify that Host Reservation modes can be
+ /// specified on a per-subnet basis.
+ TEST_F(Dhcp6ParserTest, hostReservationPerSubnet) {
+
+ /// - Configuration:
+ /// - only addresses (no prefixes)
+ /// - 4 subnets with:
+ /// - 2001:db8:1::/64 (all reservations enabled)
+ /// - 2001:db8:2::/64 (out-of-pool reservations)
+ /// - 2001:db8:3::/64 (reservations disabled)
+ /// - 2001:db8:3::/64 (reservations not specified)
+ const char* HR_CONFIG =
++ "{"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"reservation-mode\": \"all\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ],"
+ " \"subnet\": \"2001:db8:2::/48\", "
+ " \"reservation-mode\": \"out-of-pool\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"2001:db8:3::/64\" } ],"
+ " \"subnet\": \"2001:db8:3::/48\", "
+ " \"reservation-mode\": \"disabled\""
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"2001:db8:4::/64\" } ],"
+ " \"subnet\": \"2001:db8:4::/48\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ConstElementPtr status;
+
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
+ Element::fromJSON(HR_CONFIG)));
+
+ // returned value should be 0 (success)
+ checkResult(status, 0);
+ CfgMgr::instance().commit();
+
+ // Let's get all subnets and check that there are 4 of them.
+ ConstCfgSubnets6Ptr subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6();
+ ASSERT_TRUE(subnets);
+ const Subnet6Collection* subnet_col = subnets->getAll();
+ ASSERT_EQ(4, subnet_col->size()); // We expect 4 subnets
+
+ // Let's check if the parsed subnets have correct HR modes.
+
+ // Subnet 1
+ Subnet6Ptr subnet;
+ subnet = subnets->selectSubnet(IOAddress("2001:db8:1::1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
+
+ // Subnet 2
+ subnet = subnets->selectSubnet(IOAddress("2001:db8:2::1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_OUT_OF_POOL, subnet->getHostReservationMode());
+
+ // Subnet 3
+ subnet = subnets->selectSubnet(IOAddress("2001:db8:3::1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_DISABLED, subnet->getHostReservationMode());
+
+ // Subnet 4
+ subnet = subnets->selectSubnet(IOAddress("2001:db8:4::1"));
+ ASSERT_TRUE(subnet);
+ EXPECT_EQ(Subnet::HR_ALL, subnet->getHostReservationMode());
+ }
+
};