51 string expr_text = elem->stringValue();
52 if (expr_text.empty()) {
58 opt_cfg->setAction(action);
59 opt_cfg->setText(expr_text);
62 eval_ctx.parseString(expr_text, parser_type);
64 opt_cfg->setExpr(expr);
65 }
catch (
const std::exception& ex) {
67 << expr_text <<
"] error: " << ex.
what());
75namespace flex_option {
78 {
"code", Element::integer },
79 {
"name", Element::string },
80 {
"space", Element::string },
81 {
"csv-format", Element::boolean },
82 {
"add", Element::string },
83 {
"supersede", Element::string },
84 {
"remove", Element::string },
85 {
"sub-options", Element::list },
86 {
"client-class", Element::string },
87 {
"comment", Element::string }
91 {
"code", Element::integer },
92 {
"name", Element::string },
93 {
"space", Element::string },
94 {
"csv-format", Element::boolean },
95 {
"add", Element::string },
96 {
"supersede", Element::string },
97 {
"remove", Element::string },
98 {
"container-add", Element::boolean },
99 {
"container-remove", Element::boolean },
100 {
"client-class", Element::string },
101 {
"comment", Element::string }
106 :
code_(code), def_(def), action_(
NONE), class_(
"") {
115 :
OptionConfig(code, def), container_(container), vendor_id_(0),
116 container_action_(
NONE) {
129 sub_option_config_map_.clear();
130 option_config_map_.clear();
138 if (options->getType() != Element::list) {
141 if (options->empty()) {
144 for (
auto option : options->listValue()) {
145 parseOptionConfig(option);
151 uint16_t family = CfgMgr::instance().getFamily();
155 if (option->getType() != Element::map) {
159 for (
auto entry : option->mapValue()) {
160 if (OPTION_PARAMETERS.count(entry.first) == 0) {
164 if (entry.second->getType() == expected) {
168 << (expected == Element::integer ?
"an " :
"a ")
169 << Element::typeToName(expected)
170 <<
": " << entry.second->str());
178 if (!code_elem && !name_elem) {
184 if (family == AF_INET) {
186 universe = Option::V4;
189 universe = Option::V6;
192 space = space_elem->stringValue();
193 if (!OptionSpace::validateName(space)) {
199 int64_t value = code_elem->intValue();
201 if (family == AF_INET) {
202 max_code = numeric_limits<uint8_t>::max();
204 max_code = numeric_limits<uint16_t>::max();
206 if ((value < 0) || (value > max_code)) {
208 <<
" not in [0.." << max_code <<
"]");
213 "invalid 'code' value 0: reserved for PAD");
216 "invalid 'code' value 255: reserved for END");
223 code =
static_cast<uint16_t
>(value);
227 string name = name_elem->stringValue();
231 def = LibDHCP::getOptionDef(space, name);
233 def = LibDHCP::getRuntimeOptionDef(space, name);
236 def = LibDHCP::getLastResortOptionDef(space, name);
240 << space <<
"' space");
242 if (code_elem && (def->getCode() != code)) {
244 << def->getCode() <<
", not the specified code: "
247 code = def->getCode();
250 bool csv_format =
false;
251 if (csv_format_elem) {
252 csv_format = csv_format_elem->boolValue();
255 if (!csv_format && !sub_options) {
269 if (!def && csv_format) {
271 <<
"' in '" << space <<
"' space");
277 opt_cfg->setClass(class_elem->stringValue());
283 if (option->contains(
"add")) {
285 }
else if (option->contains(
"supersede")) {
286 action =
"supersede";
287 }
else if (option->contains(
"remove")) {
290 if (!action.empty()) {
292 <<
"incompatible in the same entry");
294 parseSubOptions(sub_options, opt_cfg, universe);
296 parseAction(option, opt_cfg, universe,
297 "add",
ADD, EvalContext::PARSER_STRING);
298 parseAction(option, opt_cfg, universe,
299 "supersede",
SUPERSEDE, EvalContext::PARSER_STRING);
300 parseAction(option, opt_cfg, universe,
301 "remove",
REMOVE, EvalContext::PARSER_BOOL);
303 if (opt_cfg->getAction() ==
NONE) {
310 opt_lst.push_back(opt_cfg);
319 parseSubOption(sub_option, opt_cfg, universe);
330 if (sub_option->getType() != Element::map) {
334 for (
auto entry : sub_option->mapValue()) {
335 if (SUB_OPTION_PARAMETERS.count(entry.first) == 0) {
339 if (entry.second->getType() == expected) {
343 << (expected == Element::integer ?
"an " :
"a ")
344 << Element::typeToName(expected)
345 <<
": " << entry.second->str());
352 if (!code_elem && !name_elem) {
354 << sub_option->str());
358 space = space_elem->stringValue();
359 if (!OptionSpace::validateName(space)) {
367 space = opt_def->getEncapsulatedSpace();
372 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
375 int64_t value = code_elem->intValue();
377 if (universe == Option::V4) {
378 max_code = numeric_limits<uint8_t>::max();
380 max_code = numeric_limits<uint16_t>::max();
382 if ((value < 0) || (value > max_code)) {
384 <<
" not in [0.." << max_code <<
"]");
386 code =
static_cast<uint16_t
>(value);
390 string name = name_elem->stringValue();
394 def = LibDHCP::getOptionDef(space, name);
395 if (!def && vendor_id) {
396 def = LibDHCP::getVendorOptionDef(universe, vendor_id, name);
399 def = LibDHCP::getRuntimeOptionDef(space, name);
403 << space <<
"' space");
405 if (code_elem && (def->getCode() != code)) {
407 <<
"' is defined as code: " << def->getCode()
408 <<
", not the specified code: " << code);
410 code = def->getCode();
413 bool csv_format =
false;
414 if (csv_format_elem) {
415 csv_format = csv_format_elem->boolValue();
426 if (!def && vendor_id) {
427 def = LibDHCP::getVendorOptionDef(universe, vendor_id, code);
434 <<
"' in '" << space <<
"' space");
440 if (((universe == Option::V4) &&
442 ((universe == Option::V6) &&
444 sub_cfg->setVendorId(vendor_id);
448 sub_cfg->setClass(class_elem->stringValue());
452 parseAction(sub_option, sub_cfg, universe,
453 "add",
ADD, EvalContext::PARSER_STRING);
454 parseAction(sub_option, sub_cfg, universe,
455 "supersede",
SUPERSEDE, EvalContext::PARSER_STRING);
456 parseAction(sub_option, sub_cfg, universe,
457 "remove",
REMOVE, EvalContext::PARSER_BOOL);
459 if (sub_cfg->getAction() ==
NONE) {
464 ConstElementPtr container_remove = sub_option->get(
"container-remove");
465 if ((sub_cfg->getAction() ==
ADD) || (sub_cfg->getAction() ==
SUPERSEDE)) {
466 sub_cfg->setContainerAction(
ADD);
467 if (container_add && !container_add->boolValue()) {
468 sub_cfg->setContainerAction(
NONE);
470 }
else if (sub_cfg->getAction() ==
REMOVE) {
471 sub_cfg->setContainerAction(
REMOVE);
472 if (container_remove && !container_remove->boolValue()) {
473 sub_cfg->setContainerAction(
NONE);
479 uint16_t opt_code = opt_cfg->getCode();
481 if (sub_map.count(code)) {
483 <<
" was already specified");
485 sub_map[code] = sub_cfg;
499 const string& value) {
500 if (action ==
NONE) {
511 repr <<
"'" << value <<
"'";
514 for (
const char& ch : value) {
515 repr << setw(2) << setfill('0') << static_cast<unsigned>(ch);
533 uint32_t vendor_id) {
549 uint16_t container_code) {
554 .arg(container_code);
560 uint16_t container_code,
561 const string& value) {
562 if (action ==
NONE) {
569 .arg(container_code);
574 repr <<
"'" << value <<
"'";
577 for (
const char& ch : value) {
578 repr << setw(2) << setfill('0') << static_cast<unsigned>(ch);
598 OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
599 bool ret = (!vendor || (vendor->getVendorId() == vendor_id));
604 .arg(vendor->getVendorId())
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
static OptionDefinitionPtr getRuntimeOptionDef(const std::string &space, const uint16_t code)
Returns runtime (non-standard) option definition by space and option code.
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Universe
defines option universe DHCPv4 or DHCPv6
Evaluation context, an interface to the expression evaluation.
ParserType
Specifies what type of expression the parser is expected to see.
Base option configuration.
virtual ~OptionConfig()
Destructor.
OptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def)
Constructor.
SubOptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def, OptionConfigPtr container)
Constructor.
virtual ~SubOptionConfig()
Destructor.
void configure(isc::data::ConstElementPtr options)
Configure the Flex Option implementation.
boost::shared_ptr< OptionConfig > OptionConfigPtr
The type of shared pointers to option config.
~FlexOptionImpl()
Destructor.
boost::shared_ptr< SubOptionConfig > SubOptionConfigPtr
The type of shared pointers to sub-option config.
static void logAction(Action action, uint16_t code, const std::string &value)
Log the action for option.
static void logSubClass(const isc::dhcp::ClientClass &client_class, uint16_t code, uint16_t container_code)
Log the client class for sub-option.
static void logSubAction(Action action, uint16_t code, uint16_t container_code, const std::string &value)
Log the action for sub-option.
FlexOptionImpl()
Constructor.
std::list< OptionConfigPtr > OptionConfigList
The type of lists of shared pointers to option config.
static bool checkVendor(isc::dhcp::OptionPtr opt, uint32_t vendor_id)
Check vendor option vendor id mismatch.
std::map< uint16_t, SubOptionConfigPtr > SubOptionConfigMap
The type of the sub-option config map.
static void logClass(const isc::dhcp::ClientClass &client_class, uint16_t code)
Log the client class for option.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const isc::log::MessageID FLEX_OPTION_PROCESS_VENDOR_ID_MISMATCH
const isc::log::MessageID FLEX_OPTION_PROCESS_CLIENT_CLASS
const isc::log::MessageID FLEX_OPTION_PROCESS_ADD
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_SUPERSEDE
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_CLIENT_CLASS
const isc::log::MessageID FLEX_OPTION_PROCESS_REMOVE
const isc::log::MessageID FLEX_OPTION_PROCESS_SUPERSEDE
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_ADD
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_REMOVE
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
boost::shared_ptr< const Element > ConstElementPtr
std::map< std::string, isc::data::Element::types > SimpleKeywords
This specifies all accepted keywords with their types.
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
std::string ClientClass
Defines a single class name.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< Expression > ExpressionPtr
std::vector< TokenPtr > Expression
This is a structure that holds an expression converted to RPN.
boost::shared_ptr< Option > OptionPtr
isc::log::Logger flex_option_logger("flex-option-hooks")
const int DBGLVL_TRACE_BASIC
Trace basic operations.
bool isPrintable(const std::string &content)
Check if a string is printable.
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE