namespace isc {
namespace flex_option {
-FlexOptionImpl::OptionConfig::OptionConfig(uint16_t code)
- : code_(code), action_(NONE), csv_format_(false) {
+FlexOptionImpl::OptionConfig::OptionConfig(uint16_t code,
+ OptionDefinitionPtr def)
+ : code_(code), def_(def), action_(NONE), csv_format_(false) {
}
FlexOptionImpl::OptionConfig::~OptionConfig() {
ConstElementPtr code_elem = option->get("code");
ConstElementPtr name_elem = option->get("name");
ConstElementPtr csv_format_elem = option->get("csv-format");
+ OptionDefinitionPtr def;
if (!code_elem && !name_elem) {
isc_throw(BadValue, "'code' or 'name' must be specified: "
<< option->str());
}
+ string space;
+ Option::Universe universe;
+ if (family == AF_INET) {
+ space = DHCP4_OPTION_SPACE;
+ universe = Option::V4;
+ } else {
+ space = DHCP6_OPTION_SPACE;
+ universe = Option::V6;
+ }
uint16_t code;
if (code_elem) {
if (code_elem->getType() != Element::integer) {
}
}
code = static_cast<uint16_t>(value);
+ def = isc::dhcp::LibDHCP::getOptionDef(space, code);
+ if (!def) {
+ def = isc::dhcp::LibDHCP::getRuntimeOptionDef(space, code);
+ }
+ if (!def) {
+ def = isc::dhcp::LibDHCP::getLastResortOptionDef(space, code);
+ }
+ if (!def) {
+ isc_throw(BadValue, "no known option with code '" << code
+ << "' in '" << space << "' space");
+ }
}
if (name_elem) {
if (name_elem->getType() != Element::string) {
if (name.empty()) {
isc_throw(BadValue, "'name' must not be empty");
}
- string space;
- if (family == AF_INET) {
- space = DHCP4_OPTION_SPACE;
- } else {
- space = DHCP6_OPTION_SPACE;
- }
- OptionDefinitionPtr def = LibDHCP::getOptionDef(space, name);
+ def = LibDHCP::getOptionDef(space, name);
if (!def) {
def = LibDHCP::getRuntimeOptionDef(space, name);
}
csv_format = csv_format_elem->boolValue();
}
- Option::Universe universe;
- if (family == AF_INET) {
- universe = Option::V4;
- } else {
- universe = Option::V6;
- }
-
- OptionConfigPtr opt_cfg(new OptionConfig(code));
+ OptionConfigPtr opt_cfg(new OptionConfig(code, def));
if (csv_format_elem) {
opt_cfg->setCSVFormat(csv_format);
/// @brief Constructor.
///
/// @param code the option code.
- OptionConfig(uint16_t code);
+ OptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def);
/// @brief Destructor.
virtual ~OptionConfig();
return (code_);
}
+ /// @brief Return option definition.
+ ///
+ /// @return option definition.
+ isc::dhcp::OptionDefinitionPtr getOptionDef() const {
+ return (def_);
+ }
+
/// @brief Set action.
///
/// @param action the action.
/// @brief The code.
uint16_t code_;
+ /// @brief The option definition.
+ isc::dhcp::OptionDefinitionPtr def_;
+
/// @brief The action.
Action action_;
template <typename PktType>
void process(isc::dhcp::Option::Universe universe,
PktType query, PktType response) {
- std::string space = (universe == isc::dhcp::Option::V4 ?
- DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE);
-
for (auto pair : getOptionConfigMap()) {
const OptionConfigPtr& opt_cfg = pair.second;
std::string value;
isc::dhcp::OptionBuffer buffer;
isc::dhcp::OptionPtr opt = response->getOption(opt_cfg->getCode());
- isc::dhcp::OptionDefinitionPtr def;
+ isc::dhcp::OptionDefinitionPtr def = opt_cfg->getOptionDef();
switch (opt_cfg->getAction()) {
case NONE:
break;
if (value.empty()) {
break;
}
-
+ // Check for cvs format.
if (opt_cfg->getCSVFormat()) {
- def = isc::dhcp::LibDHCP::getOptionDef(space, opt_cfg->getCode());
-
- if (!def) {
- def = isc::dhcp::LibDHCP::getRuntimeOptionDef(space, opt_cfg->getCode());
- }
-
- if (!def) {
- def = isc::dhcp::LibDHCP::getLastResortOptionDef(space, opt_cfg->getCode());
- }
-
if (!def) {
buffer.assign(value.begin(), value.end());
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
buffer));
}
-
// Add the option.
response->addOption(opt);
logAction(ADD, opt_cfg->getCode(), value);
response->delOption(opt_cfg->getCode());
opt = response->getOption(opt_cfg->getCode());
}
-
+ // Check for cvs format.
if (opt_cfg->getCSVFormat()) {
- def = isc::dhcp::LibDHCP::getOptionDef(space, opt_cfg->getCode());
-
- if (!def) {
- def = isc::dhcp::LibDHCP::getRuntimeOptionDef(space, opt_cfg->getCode());
- }
-
- if (!def) {
- def = isc::dhcp::LibDHCP::getLastResortOptionDef(space, opt_cfg->getCode());
- }
-
if (!def) {
buffer.assign(value.begin(), value.end());
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
buffer));
}
-
// Add the option.
response->addOption(opt);
logAction(SUPERSEDE, opt_cfg->getCode(), value);
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
- code = Element::create(254);
+ code = Element::create(2);
option->set("code", code);
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
- code = Element::create(65535);
+ code = Element::create(2);
option->set("code", code);
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
ElementPtr add = Element::create(string("'ab'"));
option->set("add", add);
ElementPtr name = Element::create(string("foobar"));
- option->set("name",name);
+ option->set("name", name);
EXPECT_THROW(impl_->testConfigure(options), BadValue);
EXPECT_EQ("no known 'foobar' option in 'dhcp4' space", impl_->getErrMsg());
}
+// Verify that the code must be a known option.
+TEST_F(FlexOptionTest, optionConfigUnknownCode) {
+ ElementPtr options = Element::createList();
+ ElementPtr option = Element::createMap();
+ options->add(option);
+ ElementPtr add = Element::create(string("'ab'"));
+ option->set("add", add);
+ ElementPtr code = Element::create(109);
+ option->set("code", code);
+ EXPECT_THROW(impl_->testConfigure(options), BadValue);
+ EXPECT_EQ("no known option with code '109' in 'dhcp4' space", impl_->getErrMsg());
+}
+
// Verify that the name can be a standard option.
TEST_F(FlexOptionTest, optionConfigStandardName) {
ElementPtr options = Element::createList();
TEST_F(FlexOptionTest, processNone) {
CfgMgr::instance().setFamily(AF_INET6);
+ OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP6_OPTION_SPACE, D6O_BOOTFILE_URL);
FlexOptionImpl::OptionConfigPtr
- opt_cfg(new FlexOptionImpl::OptionConfig(D6O_BOOTFILE_URL));
+ opt_cfg(new FlexOptionImpl::OptionConfig(D6O_BOOTFILE_URL, def));
EXPECT_EQ(FlexOptionImpl::NONE, opt_cfg->getAction());
auto map = impl_->getMutableOptionConfigMap();
map[DHO_HOST_NAME] = opt_cfg;
// Verify that ADD action adds the specified option in csv format.
TEST_F(FlexOptionTest, processAddEnableCSVFormat) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(true);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(DHO_HOST_NAME);
option->set("code", code);
add = Element::create(string("'example.com'"));
option->set("add", add);
- option->set("csv-format", csv_format);
+ // fqdn option data is parsed using option definition in csv format.
+ option->set("csv-format", Element::create(true));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
// Verify that ADD action adds the specified option in raw format.
TEST_F(FlexOptionTest, processAddDisableCSVFormat) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(false);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(DHO_HOST_NAME);
option->set("code", code);
add = Element::create(string("0x076578616d706c6503636f6d00"));
option->set("add", add);
- option->set("csv-format", csv_format);
+ // fqdn option data is specified in raw format.
+ option->set("csv-format", Element::create(false));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
// Verify that SUPERSEDE action supersedes the specified option in csv format.
TEST_F(FlexOptionTest, processSupersedeEnableCSVFormat) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(true);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(DHO_HOST_NAME);
option->set("code", code);
supersede = Element::create(string("'example.com'"));
option->set("supersede", supersede);
- option->set("csv-format", csv_format);
+ // fqdn option data is parsed using option definition in csv format.
+ option->set("csv-format", Element::create(true));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
// Verify that SUPERSEDE action supersedes the specified option in raw format.
TEST_F(FlexOptionTest, processSupersedeDisableCSVFormat) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(false);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(DHO_HOST_NAME);
option->set("code", code);
supersede = Element::create(string("0x076578616d706c6503636f6d00"));
option->set("supersede", supersede);
- option->set("csv-format", csv_format);
+ // fqdn option data is specified in raw format.
+ option->set("csv-format", Element::create(false));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
CfgMgr::instance().setFamily(AF_INET6);
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(true);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(D6O_BOOTFILE_URL);
option->set("code", code);
supersede = Element::create(string("'example.com'"));
option->set("supersede", supersede);
- option->set("csv-format", csv_format);
+ // fqdn option data is parsed using option definition in csv format.
+ option->set("csv-format", Element::create(true));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
// Verify that complex strings with escaped characters are properly parsed on add.
TEST_F(FlexOptionTest, processFullAddWithComplexString) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(true);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(D6O_NEW_POSIX_TIMEZONE);
string expr = "ifelse(option[39].exists,'EST5EDT4\\,M3.2.0/02:00\\,M11.1.0/02:00','')";
ElementPtr add = Element::create(expr);
option->set("add", add);
- option->set("csv-format", csv_format);
+ // strings with escape characters are parsed in csv format.
+ option->set("csv-format", Element::create(true));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
// Verify that complex strings with escaped characters are properly parsed on supersede.
TEST_F(FlexOptionTest, processFullSupersedeWithComplexString) {
ElementPtr options = Element::createList();
- ElementPtr csv_format = Element::create(true);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(D6O_NEW_POSIX_TIMEZONE);
string expr = "ifelse(option[39].exists,'EST5EDT4\\,M3.2.0/02:00\\,M11.1.0/02:00','')";
ElementPtr supersede = Element::create(expr);
option->set("supersede", supersede);
- option->set("csv-format", csv_format);
+ // strings with escape characters are parsed in csv format.
+ option->set("csv-format", Element::create(true));
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());