/// @brief Global storage for option definitions.
OptionDefStorage option_def_intermediate;
-
/// @brief a dummy configuration parser
///
/// This is a debugging parser. It does not configure anything,
BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
std::string entry(param.first);
ParserPtr parser;
- if (entry == "name" || entry == "type" ||
- entry == "record-types" || entry == "space") {
+ if (entry == "name" || entry == "type" || entry == "record-types" ||
+ entry == "space" || entry == "encapsulate") {
StringParserPtr
str_parser(dynamic_cast<StringParser*>(StringParser::factory(entry)));
if (str_parser) {
uint32_t code = getParam<uint32_t>("code", uint32_values_);
std::string type = getParam<std::string>("type", string_values_);
bool array_type = getParam<bool>("array", boolean_values_);
+ std::string encapsulates = getParam<std::string>("encapsulate",
+ string_values_);
+
+ // Create option definition.
+ OptionDefinitionPtr def;
+ // We need to check if user has set encapsulated option space
+ // name. If so, different constructor will be used.
+ if (!encapsulates.empty()) {
+ // Arrays can't be used together with sub-options.
+ if (array_type) {
+ isc_throw(DhcpConfigError, "option '" << space << "."
+ << "name" << "', comprising an array of data"
+ << " fields may not encapsulate any option space");
+
+ } else if (encapsulates == space) {
+ isc_throw(DhcpConfigError, "option must not encapsulate"
+ << " an option space it belongs to: '"
+ << space << "." << name << "' is set to"
+ << " encapsulate '" << space << "'");
+
+ } else {
+ def.reset(new OptionDefinition(name, code, type,
+ encapsulates.c_str()));
+ }
+
+ } else {
+ def.reset(new OptionDefinition(name, code, type, array_type));
+
+ }
- OptionDefinitionPtr def(new OptionDefinition(name, code,
- type, array_type));
// The record-types field may carry a list of comma separated names
// of data types that form a record.
std::string record_types = getParam<std::string>("record-types",
}
} catch (const Exception& ex) {
isc_throw(DhcpConfigError, "invalid record type values"
- << " specified for the option definition: "
+ << " specified for the option definition: "
<< ex.what());
}
}
" \"type\": \"ipv6-address\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"record\","
" \"array\": False,"
" \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" },"
" {"
" \"name\": \"foo-2\","
" \"type\": \"ipv4-address\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" },"
" {"
" \"name\": \"foo-2\","
" \"type\": \"ipv4-address\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"uint32\","
" \"array\": True,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
EXPECT_TRUE(def->getArrayType());
}
+// The purpose of this test to verify that encapsulated option
+// space name may be specified.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulate) {
+
+ // Configuration string. Included the encapsulated
+ // option space name.
+ std::string config =
+ "{ \"option-def\": [ {"
+ " \"name\": \"foo\","
+ " \"code\": 100,"
+ " \"type\": \"uint32\","
+ " \"array\": False,"
+ " \"record-types\": \"\","
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"sub-opts-space\""
+ " } ]"
+ "}";
+ ElementPtr json = Element::fromJSON(config);
+
+ // Make sure that the particular option definition does not exist.
+ OptionDefinitionPtr def = CfgMgr::instance().getOptionDef("isc", 100);
+ ASSERT_FALSE(def);
+
+ // Use the configuration string to create new option definition.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ ASSERT_TRUE(status);
+ checkResult(status, 0);
+
+ // The option definition should now be available in the CfgMgr.
+ def = CfgMgr::instance().getOptionDef("isc", 100);
+ ASSERT_TRUE(def);
+
+ // Check the option data.
+ EXPECT_EQ("foo", def->getName());
+ EXPECT_EQ(100, def->getCode());
+ EXPECT_EQ(OPT_UINT32_TYPE, def->getType());
+ EXPECT_FALSE(def->getArrayType());
+ EXPECT_EQ("sub-opts-space", def->getEncapsulatedSpace());
+}
+
/// The purpose of this test is to verify that the option definition
/// with invalid name is not accepted.
TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"sting\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"record\","
" \"array\": False,"
" \"record-types\": \"uint32,uint8,sting\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
+ " } ]"
+ "}";
+ ElementPtr json = Element::fromJSON(config);
+
+ // Use the configuration string to create new option definition.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ ASSERT_TRUE(status);
+ // Expecting parsing error (error code 1).
+ checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the invalid encapsulated
+/// option space name is not accepted.
+TEST_F(Dhcp6ParserTest, optionDefInvalidEncapsulatedSpace) {
+ // Configuration string. The encapsulated option space
+ // name is invalid (% character is not allowed).
+ std::string config =
+ "{ \"option-def\": [ {"
+ " \"name\": \"foo\","
+ " \"code\": 100,"
+ " \"type\": \"uint32\","
+ " \"array\": False,"
+ " \"record-types\": \"\","
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"invalid%space%name\""
+ " } ]"
+ "}";
+ ElementPtr json = Element::fromJSON(config);
+
+ // Use the configuration string to create new option definition.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ ASSERT_TRUE(status);
+ // Expecting parsing error (error code 1).
+ checkResult(status, 1);
+}
+
+/// The goal of this test is to verify that the encapsulated
+/// option space name can't be specified for the option that
+/// comprises an array of data fields.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulatedSpaceAndArray) {
+ // Configuration string. The encapsulated option space
+ // name is set to non-empty value and the array flag
+ // is set.
+ std::string config =
+ "{ \"option-def\": [ {"
+ " \"name\": \"foo\","
+ " \"code\": 100,"
+ " \"type\": \"uint32\","
+ " \"array\": True,"
+ " \"record-types\": \"\","
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"valid-space-name\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
checkResult(status, 1);
}
+/// The goal of this test is to verify that the option may not
+/// encapsulate option space it belongs to.
+TEST_F(Dhcp6ParserTest, optionDefEncapsulateOwnSpace) {
+ // Configuration string. Option is set to encapsulate
+ // option space it belongs to.
+ std::string config =
+ "{ \"option-def\": [ {"
+ " \"name\": \"foo\","
+ " \"code\": 100,"
+ " \"type\": \"uint32\","
+ " \"array\": False,"
+ " \"record-types\": \"\","
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"isc\""
+ " } ]"
+ "}";
+ ElementPtr json = Element::fromJSON(config);
+
+ // Use the configuration string to create new option definition.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ ASSERT_TRUE(status);
+ // Expecting parsing error (error code 1).
+ checkResult(status, 1);
+}
/// The purpose of this test is to verify that it is not allowed
/// to override the standard option (that belongs to dhcp6 option
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"dhcp6\""
+ " \"space\": \"dhcp6\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"dhcp6\""
+ " \"space\": \"dhcp6\","
+ " \"encapsulate\": \"\""
" } ]"
"}";
json = Element::fromJSON(config);
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
- " \"space\": \"isc\""
+ " \"space\": \"isc\","
+ " \"encapsulate\": \"\""
" } ],"
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:1::/80\" ],"