/// no subnet object created yet to store them.
typedef std::vector<Pool6Ptr> PoolStorage;
+typedef std::vector<OptionPtr> OptionStorage;
+
/// @brief Global uint32 parameters that will be used as defaults.
Uint32Storage uint32_defaults;
OptionDataParser(const std::string&) {
}
+ void setStorage(OptionStorage* storage) {
+ options_ = storage;
+ }
+
void build(ConstElementPtr option_value) {
BOOST_FOREACH(ConfigPair param, option_value->mapValue()) {
ParserPtr parser;
name_parser->setStorage(&string_values_);
parser = name_parser;
}
- // @todo: what if this is NULL pointer. Shouldn't we throw exception?
} else if (param.first == "code") {
boost::shared_ptr<Uint32Parser>
code_parser(dynamic_cast<Uint32Parser*>(Uint32Parser::Factory(param.first)));
parser->build(param.second);
parsers_.push_back(parser);
}
+ createOption();
}
void commit() {
private:
+ void createOption() {
+ uint32_t option_code = getUint32Param("code");
+ if (option_code > std::numeric_limits<uint16_t>::max()) {
+ isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
+ << " exceed " << std::numeric_limits<uint16_t>::max());
+ }
+ std::string option_name = getStringParam("name");
+ if (option_name.empty()) {
+ isc_throw(Dhcp6ConfigError, "Parser error: option name must not be"
+ << " empty");
+ } else if (option_name.find(" ") != std::string::npos) {
+ isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain"
+ << " spaces");
+ }
+ /// @todo more sanity checks on option name are needed.
+ OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
+ OptionBuffer()));
+ options_->push_back(option);
+ }
+
+ std::string getStringParam(const std::string& param_id) const {
+ StringStorage::const_iterator param = string_values_.find(param_id);
+ if (param == string_values_.end()) {
+ isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
+ << " '" << param_id << "' not specified");
+ }
+ return (param->second);
+ }
+
+ uint32_t getUint32Param(const std::string& param_id) const {
+ Uint32Storage::const_iterator param = uint32_values_.find(param_id);
+ if (param == uint32_values_.end()) {
+ isc_throw(Dhcp6ConfigError, "Parser error: option-data parameter"
+ << " '" << param_id << "' not specified");
+ }
+ return (param->second);
+ }
+
Uint32Storage uint32_values_;
StringStorage string_values_;
+ OptionStorage* options_;
+
ParserCollection parsers_;
};
// No need to define FactoryMap here. There's only one type
// used: Subnet6ConfigParser
-
BOOST_FOREACH(ConstElementPtr option_value, option_value_list->listValue()) {
- ParserPtr parser(new OptionDataParser("option-data"));
+ boost::shared_ptr<OptionDataParser> parser(new OptionDataParser("option-data"));
+ parser->setStorage(options_);
parser->build(option_value);
option_values_.push_back(parser);
}
}
+ void setStorage(OptionStorage* storage) {
+ options_ = storage;
+ }
+
+
/// @brief commits subnets definitions.
///
/// Iterates over all Subnet6 parsers. Each parser contains definitions
return (new OptionDataListParser(param_name));
}
+ OptionStorage* options_;
+
ParserCollection option_values_;
};
if (poolParser) {
poolParser->setStorage(&pools_);
} else {
- boost::shared_ptr<OptionDataParser> option_data_parser =
- boost::dynamic_pointer_cast<OptionDataParser>(parser);
+ boost::shared_ptr<OptionDataListParser> option_data_list_parser =
+ boost::dynamic_pointer_cast<OptionDataListParser>(parser);
+ option_data_list_parser->setStorage(&options_);
}
}
}
subnet->addPool6(*it);
}
+ BOOST_FOREACH(OptionPtr option, options_) {
+ subnet->addOption(option);
+ }
+
CfgMgr::instance().addSubnet6(subnet);
}
/// storage for pools belonging to this subnet
PoolStorage pools_;
+ /// storage for options belonging to this subnet
+ OptionStorage options_;
+
/// parsers are stored here
ParserCollection parsers_;
};
EXPECT_EQ(4000, subnet->getValid());
}
-TEST_F(Dhcp6ParserTest, globalOptionValues) {
+TEST_F(Dhcp6ParserTest, multipleOptionValues) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:1::/80\" ],"
" \"subnet\": \"2001:db8:1::/64\", "
- " \"option-value\": [ { "
- " \"name\": \"option_foo\","
- " \"code\": 100,"
- " \"data\": \"XYZ, 1, 5\" } ]"
+ " \"option-data\": [ { "
+ " \"name\": \"option_foo\","
+ " \"code\": 100,"
+ " \"data\": \"ABCDEF 01 05\""
+ " },"
+ " {"
+ " \"name\": \"option_foo2\","
+ " \"code\": 101,"
+ " \"data\": \"1\""
+ " } ]"
" } ],"
"\"valid-lifetime\": 4000 }";
cout << config << endl;
EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
ASSERT_TRUE(x);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ const Subnet::OptionContainer& options = subnet->getOptions();
+ ASSERT_EQ(2, options.size());
}
};