/// @param addr is IPv4 address of the subnet.
/// @param len is the prefix length
void initSubnet(isc::asiolink::IOAddress addr, uint8_t len) {
- // Get all 'time' parameters using inheritance.
- // If the subnet-specific value is defined then use it, else
- // use the global value. The global value must always be
- // present. If it is not, it is an internal error and exception
- // is thrown.
- Triplet<uint32_t> t1 = getParam("renew-timer");
- Triplet<uint32_t> t2 = getParam("rebind-timer");
+ // The renew-timer and rebind-timer are optional. If not set, the
+ // option 58 and 59 will not be sent to a client. In this case the
+ // client will use default values based on the valid-lifetime.
+ Triplet<uint32_t> t1 = getOptionalParam("renew-timer");
+ Triplet<uint32_t> t2 = getOptionalParam("rebind-timer");
+ // The valid-lifetime is mandatory. It may be specified for a
+ // particular subnet. If not, the global value should be present.
+ // If there is no global value, exception is thrown.
Triplet<uint32_t> valid = getParam("valid-lifetime");
// Subnet ID is optional. If it is not supplied the value of 0 is used,
// which means autogenerate.
SubnetID subnet_id =
static_cast<SubnetID>(uint32_values_->getOptionalParam("id", 0));
- stringstream tmp;
- tmp << addr << "/" << (int)len
- << " with params t1=" << t1 << ", t2=" << t2 << ", valid=" << valid;
+ stringstream s;
+ s << addr << "/" << static_cast<int>(len) << " with params: ";
+ // t1 and t2 are optional may be not specified.
+ if (!t1.unspecified()) {
+ s << "t1=" << t1 << ", ";
+ }
+ if (!t2.unspecified()) {
+ s << "t2=" << t2 << ", ";
+ }
+ s <<"valid-lifetime=" << valid;
- LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(tmp.str());
+ LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(s.str());
Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
subnet_ = subnet4;
// is sane.
srv_.reset(new Dhcpv4Srv(0));
CfgMgr::instance().deleteActiveIfaces();
+ // Create fresh context.
+ globalContext()->copyContext(ParserContext(Option::V4));
}
// Check that no hooks libraries are loaded. This is a pre-condition for
checkGlobalUint32("valid-lifetime", 4000);
}
+/// Check that the renew-timer doesn't have to be specified, in which case
+/// it is marked unspecified in the Subnet.
+TEST_F(Dhcp4ParserTest, unspecifiedRenewTimer) {
+ ConstElementPtr status;
+
+ string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"rebind-timer\": 2000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // returned value should be 0 (success)
+ checkResult(status, 0);
+ checkGlobalUint32("rebind-timer", 2000);
+ checkGlobalUint32("valid-lifetime", 4000);
+
+ Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
+ classify_);
+ ASSERT_TRUE(subnet);
+ EXPECT_TRUE(subnet->getT1().unspecified());
+ EXPECT_FALSE(subnet->getT2().unspecified());
+ EXPECT_EQ(2000, subnet->getT2());
+ EXPECT_EQ(4000, subnet->getValid());
+
+ // Check that subnet-id is 1
+ EXPECT_EQ(1, subnet->getID());
+
+}
+
+/// Check that the rebind-timer doesn't have to be specified, in which case
+/// it is marked unspecified in the Subnet.
+TEST_F(Dhcp4ParserTest, unspecifiedRebindTimer) {
+ ConstElementPtr status;
+
+ string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"renew-timer\": 1000, "
+ "\"subnet4\": [ { "
+ " \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
+ " \"subnet\": \"192.0.2.0/24\" } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
+
+ // returned value should be 0 (success)
+ checkResult(status, 0);
+ checkGlobalUint32("renew-timer", 1000);
+ checkGlobalUint32("valid-lifetime", 4000);
+
+ Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"),
+ classify_);
+ ASSERT_TRUE(subnet);
+ EXPECT_FALSE(subnet->getT1().unspecified());
+ EXPECT_EQ(1000, subnet->getT1());
+ EXPECT_TRUE(subnet->getT2().unspecified());
+ EXPECT_EQ(4000, subnet->getValid());
+
+ // Check that subnet-id is 1
+ EXPECT_EQ(1, subnet->getID());
+}
+
/// The goal of this test is to verify if defined subnet uses global
/// parameter timer definitions.
TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
// belongs to the 'dhcp4' option space as it is the
// standard option.
string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
// Starting stage 1. Configure sub-options and their definitions.
string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
// that we will add to the base option.
// Let's create some dummy options: foo and foo2.
string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
// sharing the code 1 and belonging to the different vendor spaces.
// (different vendor-id values).
string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
// sharing the code 1 and belonging to the different vendor spaces.
// (different vendor-id values).
string config = "{ \"interfaces\": [ \"*\" ],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
// Append the remainder of the configuration.
config += string(
"],"
+ "\"valid-lifetime\": 4000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"