Commit f16d079d authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2314] Configure encapsulated option space for DHCPv6 options.

parent 45b03507
......@@ -880,6 +880,7 @@ private:
<< ", code: " << option_code << "): "
<< ex.what());
}
}
// All went good, so we can set the option space name.
option_space_ = option_space;
......@@ -1139,7 +1140,7 @@ private:
}
} catch (const Exception& ex) {
isc_throw(DhcpConfigError, "invalid record type values"
<< " specified for the option definition: "
<< " specified for the option definition: "
<< ex.what());
}
}
......
......@@ -103,7 +103,6 @@ OptionStorage option_defaults;
/// @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,
......@@ -1037,8 +1036,8 @@ public:
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) {
......@@ -1122,9 +1121,36 @@ private:
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",
......@@ -1142,7 +1168,7 @@ private:
}
} catch (const Exception& ex) {
isc_throw(DhcpConfigError, "invalid record type values"
<< " specified for the option definition: "
<< " specified for the option definition: "
<< ex.what());
}
}
......
......@@ -86,6 +86,12 @@
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{ "item_name": "encapsulate",
"item_type": "string",
"item_optional": false,
"item_default": ""
} ]
}
},
......
......@@ -461,7 +461,8 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
" \"type\": \"ipv6-address\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -499,7 +500,8 @@ TEST_F(Dhcp6ParserTest, optionDefRecord) {
" \"type\": \"record\","
" \"array\": False,"
" \"record-types\": \"uint16, ipv4-address, ipv6-address, string\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -546,7 +548,8 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" },"
" {"
" \"name\": \"foo-2\","
......@@ -554,7 +557,8 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
" \"type\": \"ipv4-address\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -604,7 +608,8 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" },"
" {"
" \"name\": \"foo-2\","
......@@ -612,7 +617,8 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
" \"type\": \"ipv4-address\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -640,7 +646,8 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
" \"type\": \"uint32\","
" \"array\": True,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -666,6 +673,47 @@ TEST_F(Dhcp6ParserTest, optionDefArray) {
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) {
......@@ -678,7 +726,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidName) {
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -703,7 +752,8 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidType) {
" \"type\": \"sting\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -728,7 +778,62 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
" \"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);
......@@ -741,6 +846,31 @@ TEST_F(Dhcp6ParserTest, optionDefInvalidRecordType) {
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
......@@ -759,7 +889,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"dhcp6\""
" \"space\": \"dhcp6\","
" \"encapsulate\": \"\""
" } ]"
"}";
ElementPtr json = Element::fromJSON(config);
......@@ -794,7 +925,8 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
" \"type\": \"string\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"dhcp6\""
" \"space\": \"dhcp6\","
" \"encapsulate\": \"\""
" } ]"
"}";
json = Element::fromJSON(config);
......@@ -916,7 +1048,8 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
" \"type\": \"uint32\","
" \"array\": False,"
" \"record-types\": \"\","
" \"space\": \"isc\""
" \"space\": \"isc\","
" \"encapsulate\": \"\""
" } ],"
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:1::/80\" ],"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment