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