Kea 3.3.1
flex_option.cc
Go to the documentation of this file.
1// Copyright (C) 2019-2026 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <flex_option.h>
10#include <flex_option_log.h>
11#include <util/str.h>
12#include <cc/simple_parser.h>
13#include <dhcp/dhcp4.h>
14#include <dhcp/libdhcp++.h>
16#include <dhcp/option_space.h>
17#include <dhcp/option_vendor.h>
18#include <dhcpsrv/cfgmgr.h>
19#include <eval/eval_context.h>
20
21using namespace isc;
22using namespace isc::data;
23using namespace isc::dhcp;
24using namespace isc::eval;
25using namespace isc::flex_option;
26using namespace isc::log;
27using namespace isc::util;
28using namespace isc::util::str;
29using namespace std;
30
31namespace {
32
43void
44parseAction(ConstElementPtr option,
46 Option::Universe universe,
47 const string& name,
49 EvalContext::ParserType parser_type) {
50 ConstElementPtr elem = option->get(name);
51 if (elem) {
52 string expr_text = elem->stringValue();
53 if (expr_text.empty()) {
54 isc_throw(BadValue, "'" << name << "' must not be empty");
55 }
56 if (opt_cfg->getAction() != FlexOptionImpl::NONE) {
57 isc_throw(BadValue, "multiple actions: " << option->str());
58 }
59 opt_cfg->setAction(action);
60 opt_cfg->setText(expr_text);
61 try {
62 EvalContext eval_ctx(universe);
63 eval_ctx.parseString(expr_text, parser_type);
64 ExpressionPtr expr(new Expression(eval_ctx.expression_));
65 opt_cfg->setExpr(expr);
66 } catch (const std::exception& ex) {
67 isc_throw(BadValue, "can't parse " << name << " expression ["
68 << expr_text << "] error: " << ex.what());
69 }
70 }
71}
72
73} // end of anonymous namespace
74
75namespace isc {
76namespace flex_option {
77
78const SimpleKeywords FlexOptionImpl::OPTION_PARAMETERS = {
79 { "code", Element::integer },
80 { "name", Element::string },
81 { "space", Element::string },
82 { "csv-format", Element::boolean },
83 { "add", Element::string },
84 { "supersede", Element::string },
85 { "remove", Element::string },
86 { "sub-options", Element::list },
87 { "client-class", Element::string },
88 { "source", Element::string },
89 { "destination", Element::string },
90 { "comment", Element::string }
91};
92
93const SimpleKeywords FlexOptionImpl::SUB_OPTION_PARAMETERS = {
94 { "code", Element::integer },
95 { "name", Element::string },
96 { "space", Element::string },
97 { "csv-format", Element::boolean },
98 { "add", Element::string },
99 { "supersede", Element::string },
100 { "remove", Element::string },
101 { "container-add", Element::boolean },
102 { "container-remove", Element::boolean },
103 { "client-class", Element::string },
104 { "comment", Element::string }
105};
106
109 : code_(code), def_(def), action_(NONE), class_(""),
110 source_is_query_(true), dest_is_response_(true) {
111}
112
115
118 OptionConfigPtr container)
119 : OptionConfig(code, def), container_(container), vendor_id_(0),
120 container_action_(NONE) {
121 if (!container) {
122 isc_throw(Unexpected, "null container?");
123 }
124}
125
128
129FlexOptionImpl::FlexOptionImpl() : need_copy_classes_to_response_(false) {
130}
131
133 sub_option_config_map_.clear();
134 option_config_map_.clear();
135 need_copy_classes_to_response_ = false;
136}
137
138void
140 if (!options) {
141 isc_throw(BadValue, "'options' parameter is mandatory");
142 }
143 if (options->getType() != Element::list) {
144 isc_throw(BadValue, "'options' parameter must be a list");
145 }
146 if (options->empty()) {
147 return;
148 }
149 for (auto const& option : options->listValue()) {
150 parseOptionConfig(option);
151 }
152}
153
154void
155FlexOptionImpl::parseOptionConfig(ConstElementPtr option) {
156 uint16_t family = CfgMgr::instance().getFamily();
157 if (!option) {
158 isc_throw(BadValue, "null option element");
159 }
160 if (option->getType() != Element::map) {
161 isc_throw(BadValue, "option element is not a map");
162 }
163 // See SimpleParser::checkKeywords
164 for (auto const& entry : option->mapValue()) {
165 if (OPTION_PARAMETERS.count(entry.first) == 0) {
166 isc_throw(BadValue, "unknown parameter '" << entry.first << "'");
167 }
168 Element::types expected = OPTION_PARAMETERS.at(entry.first);
169 if (entry.second->getType() == expected) {
170 continue;
171 }
172 isc_throw(BadValue, "'" << entry.first << "' must be "
173 << (expected == Element::integer ? "an " : "a ")
174 << Element::typeToName(expected)
175 << ": " << entry.second->str());
176 }
177 ConstElementPtr code_elem = option->get("code");
178 ConstElementPtr name_elem = option->get("name");
179 ConstElementPtr space_elem = option->get("space");
180 ConstElementPtr csv_format_elem = option->get("csv-format");
181 ConstElementPtr class_elem = option->get("client-class");
182 ConstElementPtr sub_options = option->get("sub-options");
183 ConstElementPtr source_elem = option->get("source");
184 ConstElementPtr dest_elem = option->get("destination");
185 if (!code_elem && !name_elem) {
186 isc_throw(BadValue, "'code' or 'name' must be specified: "
187 << option->str());
188 }
189 string space;
190 Option::Universe universe;
191 if (family == AF_INET) {
192 space = DHCP4_OPTION_SPACE;
193 universe = Option::V4;
194 } else {
195 space = DHCP6_OPTION_SPACE;
196 universe = Option::V6;
197 }
198 if (space_elem) {
199 space = space_elem->stringValue();
200 if (!OptionSpace::validateName(space)) {
201 isc_throw(BadValue, "'" << space << "' is not a valid space name");
202 }
203 }
204 // The code is always set below but some compilers can't see that...
205 uint16_t code = 0;
206 if (code_elem) {
207 int64_t value = code_elem->intValue();
208 int64_t max_code;
209 if (family == AF_INET) {
210 max_code = numeric_limits<uint8_t>::max();
211 } else {
212 max_code = numeric_limits<uint16_t>::max();
213 }
214 if ((value < 0) || (value > max_code)) {
215 isc_throw(OutOfRange, "invalid 'code' value " << value
216 << " not in [0.." << max_code << "]");
217 }
218 if (space == DHCP4_OPTION_SPACE) {
219 if (value == DHO_PAD) {
220 isc_throw(BadValue,
221 "invalid 'code' value 0: reserved for PAD");
222 } else if (value == DHO_END) {
223 isc_throw(BadValue,
224 "invalid 'code' value 255: reserved for END");
225 }
226 } else if (space == DHCP6_OPTION_SPACE) {
227 if (value == 0) {
228 isc_throw(BadValue, "invalid 'code' value 0: reserved");
229 }
230 }
231 code = static_cast<uint16_t>(value);
232 }
234 if (name_elem) {
235 string name = name_elem->stringValue();
236 if (name.empty()) {
237 isc_throw(BadValue, "'name' must not be empty");
238 }
239 def = LibDHCP::getOptionDef(space, name);
240 if (!def) {
241 def = LibDHCP::getRuntimeOptionDef(space, name);
242 }
243 if (!def) {
244 def = LibDHCP::getLastResortOptionDef(space, name);
245 }
246 if (!def) {
247 isc_throw(BadValue, "no known '" << name << "' option in '"
248 << space << "' space");
249 }
250 if (code_elem && (def->getCode() != code)) {
251 isc_throw(BadValue, "option '" << name << "' is defined as code: "
252 << def->getCode() << ", not the specified code: "
253 << code);
254 }
255 code = def->getCode();
256 }
257
258 bool csv_format = false;
259 if (csv_format_elem) {
260 csv_format = csv_format_elem->boolValue();
261 }
262
263 if (!csv_format && !sub_options) {
264 // No definition means no csv format.
265 if (def) {
266 def.reset();
267 }
268 } else if (!def) {
269 // Definition is required with csv format.
270 def = isc::dhcp::LibDHCP::getOptionDef(space, code);
271 if (!def) {
273 }
274 if (!def) {
276 }
277 if (!def && csv_format) {
278 isc_throw(BadValue, "no known option with code '" << code
279 << "' in '" << space << "' space");
280 }
281 }
282
283 OptionConfigPtr opt_cfg(new OptionConfig(code, def));
284 if (class_elem) {
285 opt_cfg->setClass(class_elem->stringValue());
286 }
287
288 // opt_cfg default source is the query.
289 if (source_elem) {
290 string source = source_elem->stringValue();
291 if (source == "query") {
292 opt_cfg->setSource(true);
293 } else if (source == "response") {
294 opt_cfg->setSource(false);
295 } else {
296 isc_throw(BadValue, "unknown source '" << source
297 << "', valid values are 'query' and 'response'");
298 }
299 }
300
301 // opt_cfg default destination is the response.
302 if (dest_elem) {
303 string dest = dest_elem->stringValue();
304 if (dest == "query") {
305 opt_cfg->setDestination(false);
306 } else if (dest == "response") {
307 opt_cfg->setDestination(true);
308 } else {
309 isc_throw(BadValue, "unknown destination '" << dest
310 << "', valid values are 'response' and 'query'");
311 }
312 }
313
314 // Consistency: if the destination is the query the source must be
315 // the query too.
316 if (!opt_cfg->getDestination() && !opt_cfg->getSource()) {
317 isc_throw(BadValue, "destination 'query' requires source 'query'");
318 }
319
320 // Not working as expected: the destination is the query and classes
321 // are used.
322 if (!opt_cfg->getDestination() && !opt_cfg->getClass().empty()) {
324 .arg(code)
325 .arg(opt_cfg->getClass());
326 }
327
328 // opt_cfg initial action is NONE.
329 if (sub_options) {
330 string action;
331 if (option->contains("add")) {
332 action = "add";
333 } else if (option->contains("supersede")) {
334 action = "supersede";
335 } else if (option->contains("remove")) {
336 action = "remove";
337 }
338 if (!action.empty()) {
339 isc_throw(BadValue, "'sub-options' and '" << action << "' are "
340 << "incompatible in the same entry");
341 }
342 parseSubOptions(sub_options, opt_cfg, universe);
343 } else {
344 parseAction(option, opt_cfg, universe,
346 parseAction(option, opt_cfg, universe,
348 parseAction(option, opt_cfg, universe,
350
351 if (opt_cfg->getAction() == NONE) {
352 isc_throw(BadValue, "no action: " << option->str());
353 }
354
355 // The [] operator creates the item if it does not exist before
356 // returning a reference to it.
357 OptionConfigList& opt_lst = option_config_map_[code];
358 opt_lst.push_back(opt_cfg);
359 }
360
361 // Not working as expected: the destination is the query and
362 // TokenMember is used.
363 if (!opt_cfg->getDestination() && opt_cfg->getExpr()) {
364 for (auto const& tok : *opt_cfg->getExpr()) {
365 if (boost::dynamic_pointer_cast<TokenMember>(tok)) {
367 .arg(code)
368 .arg(opt_cfg->getText());
369 break;
370 }
371 }
372 }
373
374 // Check if we have to copy classes from the query to the response.
375 if (need_copy_classes_to_response_ ||
376 opt_cfg->getSource() ||
377 !opt_cfg->getExpr()) {
378 return;
379 }
380 for (auto const& tok : *opt_cfg->getExpr()) {
381 if (boost::dynamic_pointer_cast<TokenMember>(tok)) {
382 need_copy_classes_to_response_ = true;
383 break;
384 }
385 }
386}
387
388void
389FlexOptionImpl::parseSubOptions(ConstElementPtr sub_options,
390 OptionConfigPtr opt_cfg,
391 Option::Universe universe) {
392 for (auto const& sub_option : sub_options->listValue()) {
393 parseSubOption(sub_option, opt_cfg, universe);
394 }
395}
396
397void
398FlexOptionImpl::parseSubOption(ConstElementPtr sub_option,
399 OptionConfigPtr opt_cfg,
400 Option::Universe universe) {
401 if (!sub_option) {
402 isc_throw(BadValue, "null sub-option element");
403 }
404 if (sub_option->getType() != Element::map) {
405 isc_throw(BadValue, "sub-option element is not a map");
406 }
407 // See SimpleParser::checkKeywords
408 for (auto const& entry : sub_option->mapValue()) {
409 if (SUB_OPTION_PARAMETERS.count(entry.first) == 0) {
410 isc_throw(BadValue, "unknown parameter '" << entry.first << "'");
411 }
412 Element::types expected = SUB_OPTION_PARAMETERS.at(entry.first);
413 if (entry.second->getType() == expected) {
414 continue;
415 }
416 isc_throw(BadValue, "'" << entry.first << "' must be "
417 << (expected == Element::integer ? "an " : "a ")
418 << Element::typeToName(expected)
419 << ": " << entry.second->str());
420 }
421 ConstElementPtr code_elem = sub_option->get("code");
422 ConstElementPtr name_elem = sub_option->get("name");
423 ConstElementPtr space_elem = sub_option->get("space");
424 ConstElementPtr csv_format_elem = sub_option->get("csv-format");
425 ConstElementPtr class_elem = sub_option->get("client-class");
426 if (!code_elem && !name_elem) {
427 isc_throw(BadValue, "'code' or 'name' must be specified: "
428 << sub_option->str());
429 }
430 string space;
431 if (space_elem) {
432 space = space_elem->stringValue();
433 if (!OptionSpace::validateName(space)) {
434 isc_throw(BadValue, "'" << space << "' is not a valid space name");
435 }
436 } else {
437 OptionDefinitionPtr opt_def = opt_cfg->getOptionDef();
438 if (!opt_def) {
439 isc_throw(BadValue, "container is not defined: can't get space");
440 }
441 space = opt_def->getEncapsulatedSpace();
442 if (space.empty()) {
443 isc_throw(BadValue, "container does not encapsulate a space");
444 }
445 }
446 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
447 uint16_t code;
448 if (code_elem) {
449 int64_t value = code_elem->intValue();
450 int64_t max_code;
451 if (universe == Option::V4) {
452 max_code = numeric_limits<uint8_t>::max();
453 } else {
454 max_code = numeric_limits<uint16_t>::max();
455 }
456 if ((value < 0) || (value > max_code)) {
457 isc_throw(OutOfRange, "invalid 'code' value " << value
458 << " not in [0.." << max_code << "]");
459 }
460 code = static_cast<uint16_t>(value);
461 }
463 if (name_elem) {
464 string name = name_elem->stringValue();
465 if (name.empty()) {
466 isc_throw(BadValue, "'name' must not be empty");
467 }
468 def = LibDHCP::getOptionDef(space, name);
469 if (!def && vendor_id) {
470 def = LibDHCP::getVendorOptionDef(universe, vendor_id, name);
471 }
472 if (!def) {
473 def = LibDHCP::getRuntimeOptionDef(space, name);
474 }
475 if (!def) {
476 isc_throw(BadValue, "no known '" << name << "' sub-option in '"
477 << space << "' space");
478 }
479 if (code_elem && (def->getCode() != code)) {
480 isc_throw(BadValue, "sub-option '" << name
481 << "' is defined as code: " << def->getCode()
482 << ", not the specified code: " << code);
483 }
484 code = def->getCode();
485 }
486
487 bool csv_format = false;
488 if (csv_format_elem) {
489 csv_format = csv_format_elem->boolValue();
490 }
491
492 if (!csv_format) {
493 // No definition means no csv format.
494 if (def) {
495 def.reset();
496 }
497 } else if (!def) {
498 // Definition is required with csv format.
499 def = isc::dhcp::LibDHCP::getOptionDef(space, code);
500 if (!def && vendor_id) {
501 def = LibDHCP::getVendorOptionDef(universe, vendor_id, code);
502 }
503 if (!def) {
505 }
506 if (!def) {
507 isc_throw(BadValue, "no known sub-option with code '" << code
508 << "' in '" << space << "' space");
509 }
510 }
511
512 SubOptionConfigPtr sub_cfg(new SubOptionConfig(code, def, opt_cfg));
513 if (vendor_id) {
514 if (((universe == Option::V4) &&
515 (opt_cfg->getCode() == DHO_VIVSO_SUBOPTIONS)) ||
516 ((universe == Option::V6) &&
517 (opt_cfg->getCode() == D6O_VENDOR_OPTS))) {
518 sub_cfg->setVendorId(vendor_id);
519 }
520 }
521 if (class_elem) {
522 sub_cfg->setClass(class_elem->stringValue());
523 }
524
525 // Inherit source and destination.
526 sub_cfg->setSource(opt_cfg->getSource());
527 sub_cfg->setDestination(opt_cfg->getDestination());
528
529 // Not working as expected: the destination is the query and classes
530 // are used.
531 if (!opt_cfg->getDestination() && !sub_cfg->getClass().empty()) {
533 .arg(code)
534 .arg(opt_cfg->getCode())
535 .arg(sub_cfg->getClass());
536 }
537
538 // sub_cfg initial action is NONE.
539 parseAction(sub_option, sub_cfg, universe,
541 parseAction(sub_option, sub_cfg, universe,
543 parseAction(sub_option, sub_cfg, universe,
545
546 if (sub_cfg->getAction() == NONE) {
547 isc_throw(BadValue, "no action: " << sub_option->str());
548 }
549
550 // Not working as expected: the destination is the query and
551 // TokenMember is used.
552 if (!opt_cfg->getDestination() && sub_cfg->getExpr()) {
553 for (auto const& tok : *sub_cfg->getExpr()) {
554 if (boost::dynamic_pointer_cast<TokenMember>(tok)) {
557 .arg(code)
558 .arg(opt_cfg->getCode())
559 .arg(sub_cfg->getText());
560 break;
561 }
562 }
563 }
564
565 ConstElementPtr container_add = sub_option->get("container-add");
566 ConstElementPtr container_remove = sub_option->get("container-remove");
567 if ((sub_cfg->getAction() == ADD) || (sub_cfg->getAction() == SUPERSEDE)) {
568 sub_cfg->setContainerAction(ADD);
569 if (container_add && !container_add->boolValue()) {
570 sub_cfg->setContainerAction(NONE);
571 }
572 } else if (sub_cfg->getAction() == REMOVE) {
573 sub_cfg->setContainerAction(REMOVE);
574 if (container_remove && !container_remove->boolValue()) {
575 sub_cfg->setContainerAction(NONE);
576 }
577 }
578
579 // The [] operator creates the item if it does not exist before
580 // returning a reference to it.
581 uint16_t opt_code = opt_cfg->getCode();
582 SubOptionConfigMap& sub_map = sub_option_config_map_[opt_code];
583 if (sub_map.count(code)) {
584 isc_throw(BadValue, "sub-option " << code << " of option " << opt_code
585 << " was already specified");
586 }
587 sub_map[code] = sub_cfg;
588
589 // Check if we have to copy classes from the query to the response.
590 if (need_copy_classes_to_response_ ||
591 opt_cfg->getSource() ||
592 !sub_cfg->getExpr()) {
593 return;
594 }
595 for (auto const& tok : *sub_cfg->getExpr()) {
596 if (boost::dynamic_pointer_cast<TokenMember>(tok)) {
597 need_copy_classes_to_response_ = true;
598 break;
599 }
600 }
601}
602
603void
604FlexOptionImpl::logClass(const ClientClass& client_class, uint16_t code) {
607 .arg(code)
608 .arg(client_class);
609 return;
610}
611
612void
613FlexOptionImpl::logAction(Action action, uint16_t code,
614 const string& value) {
615 if (action == NONE) {
616 return;
617 }
618 if (action == REMOVE) {
621 .arg(code);
622 return;
623 }
624 ostringstream repr;
625 if (str::isPrintable(value)) {
626 repr << "'" << value << "'";
627 } else {
628 repr << "0x";
629 for (const char& ch : value) {
630 repr << byteToHex(ch);
631 }
632 }
633 if (action == SUPERSEDE) {
636 .arg(code)
637 .arg(repr.str());
638 } else {
641 .arg(code)
642 .arg(repr.str());
643 }
644}
645
646void
647FlexOptionImpl::logAction(Action action, uint16_t code,
648 uint32_t vendor_id) {
649 if (action == SUPERSEDE) {
652 .arg(code)
653 .arg(vendor_id);
654 } else {
657 .arg(code)
658 .arg(vendor_id);
659 }
660}
661
662void
663FlexOptionImpl::logSubClass(const ClientClass& client_class, uint16_t code,
664 uint16_t container_code) {
667 .arg(code)
668 .arg(container_code)
669 .arg(client_class);
670 return;
671}
672
673void
675 uint16_t container_code,
676 const string& value) {
677 if (action == NONE) {
678 return;
679 }
680 if (action == REMOVE) {
683 .arg(code)
684 .arg(container_code);
685 return;
686 }
687 ostringstream repr;
688 if (str::isPrintable(value)) {
689 repr << "'" << value << "'";
690 } else {
691 repr << "0x";
692 for (const char& ch : value) {
693 repr << byteToHex(ch);
694 }
695 }
696 if (action == SUPERSEDE) {
699 .arg(code)
700 .arg(container_code)
701 .arg(repr.str());
702 } else {
705 .arg(code)
706 .arg(container_code)
707 .arg(repr.str());
708 }
709}
710
711bool
712FlexOptionImpl::checkVendor(OptionPtr opt, uint32_t vendor_id) {
713 OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
714 bool ret = (!vendor || (vendor->getVendorId() == vendor_id));
715 if (!ret) {
718 .arg(opt->getType())
719 .arg(vendor->getVendorId())
720 .arg(vendor_id);
721 }
722 return (ret);
723}
724
725} // end of namespace flex_option
726} // end of namespace isc
static std::string typeToName(Element::types type)
Returns the name of the given type as a string.
Definition data.cc:716
types
The types that an Element can hold.
Definition data.h:152
@ map
Definition data.h:160
@ integer
Definition data.h:153
@ boolean
Definition data.h:155
@ list
Definition data.h:159
@ string
Definition data.h:157
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.
Definition cfgmgr.h:246
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition cfgmgr.cc:29
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition libdhcp++.cc:132
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.
Definition libdhcp++.cc:174
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.
Definition libdhcp++.cc:195
static OptionDefinitionPtr getLastResortOptionDef(const std::string &space, const uint16_t code)
Returns last resort option definition by space and option code.
Definition libdhcp++.cc:253
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:90
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
OptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def)
Constructor.
SubOptionConfig(uint16_t code, isc::dhcp::OptionDefinitionPtr def, OptionConfigPtr container)
Constructor.
void configure(isc::data::ConstElementPtr options)
Configure the Flex Option implementation.
boost::shared_ptr< OptionConfig > OptionConfigPtr
The type of shared pointers to option config.
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.
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.
@ D6O_VENDOR_OPTS
Definition dhcp6.h:37
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const isc::log::MessageID FLEX_OPTION_CONFIG_SUB_USELESS_CLASS
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_CONFIG_USELESS_MEMBER
const isc::log::MessageID FLEX_OPTION_CONFIG_USELESS_CLASS
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_ADD
const isc::log::MessageID FLEX_OPTION_PROCESS_SUB_REMOVE
const isc::log::MessageID FLEX_OPTION_CONFIG_SUB_USELESS_MEMBER
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:30
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.
Definition classify.h:45
@ DHO_END
Definition dhcp4.h:229
@ DHO_PAD
Definition dhcp4.h:69
@ DHO_VIVSO_SUBOPTIONS
Definition dhcp4.h:189
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< Expression > ExpressionPtr
Definition token.h:31
std::vector< TokenPtr > Expression
This is a structure that holds an expression converted to RPN.
Definition token.h:29
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
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.
Definition str.cc:310
const std::string & byteToHex(uint8_t byte)
Converts a byte to a two hex digit string.
Definition str.cc:403
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE