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());
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();
141 if (options->empty()) {
144 for (
auto const& option : options->listValue()) {
145 parseOptionConfig(option);
159 for (
auto const& entry : option->mapValue()) {
160 if (OPTION_PARAMETERS.count(entry.first) == 0) {
164 if (entry.second->getType() == expected) {
167 isc_throw(BadValue,
"'" << entry.first <<
"' must be "
170 <<
": " << entry.second->str());
178 if (!code_elem && !name_elem) {
179 isc_throw(BadValue,
"'code' or 'name' must be specified: "
184 if (family == AF_INET) {
192 space = space_elem->stringValue();
194 isc_throw(BadValue,
"'" << space <<
"' is not a valid space name");
200 int64_t value = code_elem->intValue();
202 if (family == AF_INET) {
203 max_code = numeric_limits<uint8_t>::max();
205 max_code = numeric_limits<uint16_t>::max();
207 if ((value < 0) || (value > max_code)) {
208 isc_throw(OutOfRange,
"invalid 'code' value " << value
209 <<
" not in [0.." << max_code <<
"]");
214 "invalid 'code' value 0: reserved for PAD");
217 "invalid 'code' value 255: reserved for END");
221 isc_throw(BadValue,
"invalid 'code' value 0: reserved");
224 code =
static_cast<uint16_t
>(value);
228 string name = name_elem->stringValue();
230 isc_throw(BadValue,
"'name' must not be empty");
240 isc_throw(BadValue,
"no known '" << name <<
"' option in '"
241 << space <<
"' space");
243 if (code_elem && (def->getCode() != code)) {
244 isc_throw(BadValue,
"option '" << name <<
"' is defined as code: "
245 << def->getCode() <<
", not the specified code: "
248 code = def->getCode();
251 bool csv_format =
false;
252 if (csv_format_elem) {
253 csv_format = csv_format_elem->boolValue();
256 if (!csv_format && !sub_options) {
270 if (!def && csv_format) {
271 isc_throw(BadValue,
"no known option with code '" << code
272 <<
"' in '" << space <<
"' space");
278 opt_cfg->setClass(class_elem->stringValue());
284 if (option->contains(
"add")) {
286 }
else if (option->contains(
"supersede")) {
287 action =
"supersede";
288 }
else if (option->contains(
"remove")) {
291 if (!action.empty()) {
292 isc_throw(BadValue,
"'sub-options' and '" << action <<
"' are "
293 <<
"incompatible in the same entry");
295 parseSubOptions(sub_options, opt_cfg, universe);
297 parseAction(option, opt_cfg, universe,
299 parseAction(option, opt_cfg, universe,
301 parseAction(option, opt_cfg, universe,
304 if (opt_cfg->getAction() ==
NONE) {
305 isc_throw(BadValue,
"no action: " << option->str());
311 opt_lst.push_back(opt_cfg);
319 for (
auto const& sub_option : sub_options->listValue()) {
320 parseSubOption(sub_option, opt_cfg, universe);
329 isc_throw(BadValue,
"null sub-option element");
332 isc_throw(BadValue,
"sub-option element is not a map");
335 for (
auto const& entry : sub_option->mapValue()) {
336 if (SUB_OPTION_PARAMETERS.count(entry.first) == 0) {
337 isc_throw(BadValue,
"unknown parameter '" << entry.first <<
"'");
340 if (entry.second->getType() == expected) {
343 isc_throw(BadValue,
"'" << entry.first <<
"' must be "
346 <<
": " << entry.second->str());
353 if (!code_elem && !name_elem) {
354 isc_throw(BadValue,
"'code' or 'name' must be specified: "
355 << sub_option->str());
359 space = space_elem->stringValue();
361 isc_throw(BadValue,
"'" << space <<
"' is not a valid space name");
366 isc_throw(BadValue,
"container is not defined: can't get space");
368 space = opt_def->getEncapsulatedSpace();
370 isc_throw(BadValue,
"container does not encapsulate a space");
376 int64_t value = code_elem->intValue();
379 max_code = numeric_limits<uint8_t>::max();
381 max_code = numeric_limits<uint16_t>::max();
383 if ((value < 0) || (value > max_code)) {
384 isc_throw(OutOfRange,
"invalid 'code' value " << value
385 <<
" not in [0.." << max_code <<
"]");
387 code =
static_cast<uint16_t
>(value);
391 string name = name_elem->stringValue();
393 isc_throw(BadValue,
"'name' must not be empty");
396 if (!def && vendor_id) {
403 isc_throw(BadValue,
"no known '" << name <<
"' sub-option in '"
404 << space <<
"' space");
406 if (code_elem && (def->getCode() != code)) {
407 isc_throw(BadValue,
"sub-option '" << name
408 <<
"' is defined as code: " << def->getCode()
409 <<
", not the specified code: " << code);
411 code = def->getCode();
414 bool csv_format =
false;
415 if (csv_format_elem) {
416 csv_format = csv_format_elem->boolValue();
427 if (!def && vendor_id) {
434 isc_throw(BadValue,
"no known sub-option with code '" << code
435 <<
"' in '" << space <<
"' space");
445 sub_cfg->setVendorId(vendor_id);
449 sub_cfg->setClass(class_elem->stringValue());
453 parseAction(sub_option, sub_cfg, universe,
455 parseAction(sub_option, sub_cfg, universe,
457 parseAction(sub_option, sub_cfg, universe,
460 if (sub_cfg->getAction() ==
NONE) {
461 isc_throw(BadValue,
"no action: " << sub_option->str());
465 ConstElementPtr container_remove = sub_option->get(
"container-remove");
466 if ((sub_cfg->getAction() ==
ADD) || (sub_cfg->getAction() ==
SUPERSEDE)) {
467 sub_cfg->setContainerAction(
ADD);
468 if (container_add && !container_add->boolValue()) {
469 sub_cfg->setContainerAction(
NONE);
471 }
else if (sub_cfg->getAction() ==
REMOVE) {
472 sub_cfg->setContainerAction(
REMOVE);
473 if (container_remove && !container_remove->boolValue()) {
474 sub_cfg->setContainerAction(
NONE);
480 uint16_t opt_code = opt_cfg->getCode();
482 if (sub_map.count(code)) {
483 isc_throw(BadValue,
"sub-option " << code <<
" of option " << opt_code
484 <<
" was already specified");
486 sub_map[code] = sub_cfg;
500 const string& value) {
501 if (action ==
NONE) {
512 repr <<
"'" << value <<
"'";
515 for (
const char& ch : value) {
516 repr << setw(2) << setfill('0') << static_cast<unsigned>(ch);
534 uint32_t vendor_id) {
550 uint16_t container_code) {
561 uint16_t container_code,
562 const string& value) {
563 if (action ==
NONE) {
570 .arg(container_code);
575 repr <<
"'" << value <<
"'";
578 for (
const char& ch : value) {
579 repr << setw(2) << setfill('0') << static_cast<unsigned>(ch);
599 OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
600 bool ret = (!vendor || (vendor->getVendorId() == vendor_id));
605 .arg(vendor->getVendorId())
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
types
The types that an Element can hold.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
A generic exception that is thrown when an unexpected error condition occurs.
uint16_t getFamily() const
Returns address family.
static CfgMgr & instance()
returns a single instance of Configuration Manager
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
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.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
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.
@ PARSER_BOOL
expression is expected to evaluate to bool
@ PARSER_STRING
expression is expected to evaluate to string
Base option configuration.
virtual ~OptionConfig()
Destructor.
OptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def)
Constructor.
Sub-option configuration.
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 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