mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 13:37:55 +00:00
[219-allow-an-option-value-to-be-set-from-an-expression] Checkpoint: wrote flex option code, to do tests, to finish doc
This commit is contained in:
@@ -1694,6 +1694,8 @@ AC_CONFIG_FILES([Makefile
|
|||||||
src/bin/shell/tests/shell_unittest.py
|
src/bin/shell/tests/shell_unittest.py
|
||||||
src/hooks/Makefile
|
src/hooks/Makefile
|
||||||
src/hooks/dhcp/Makefile
|
src/hooks/dhcp/Makefile
|
||||||
|
src/hooks/dhcp/flex_option/Makefile
|
||||||
|
src/hooks/dhcp/flex_option/tests/Makefile
|
||||||
src/hooks/dhcp/high_availability/Makefile
|
src/hooks/dhcp/high_availability/Makefile
|
||||||
src/hooks/dhcp/high_availability/tests/Makefile
|
src/hooks/dhcp/high_availability/tests/Makefile
|
||||||
src/hooks/dhcp/lease_cmds/Makefile
|
src/hooks/dhcp/lease_cmds/Makefile
|
||||||
|
@@ -4,4 +4,4 @@ if HAVE_MYSQL
|
|||||||
SUBDIRS += mysql_cb
|
SUBDIRS += mysql_cb
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS += stat_cmds user_chk
|
SUBDIRS += stat_cmds flex_option user_chk
|
||||||
|
1
src/hooks/dhcp/flex_option/.gitignore
vendored
Normal file
1
src/hooks/dhcp/flex_option/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/html
|
82
src/hooks/dhcp/flex_option/Makefile.am
Normal file
82
src/hooks/dhcp/flex_option/Makefile.am
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
SUBDIRS = . tests
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||||
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
|
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||||
|
|
||||||
|
# Ensure that the message file and doxygen file is included in the distribution
|
||||||
|
EXTRA_DIST = flex_option_messages.mes
|
||||||
|
EXTRA_DIST += flex_option.dox
|
||||||
|
|
||||||
|
CLEANFILES = *.gcno *.gcda
|
||||||
|
|
||||||
|
# convenience archive
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libflex_option.la
|
||||||
|
|
||||||
|
libflex_option_la_SOURCES = flex_option.cc flex_option.h
|
||||||
|
libflex_option_la_SOURCES += flex_option_callouts.cc
|
||||||
|
libflex_option_la_SOURCES += flex_option_log.cc flex_option_log.h
|
||||||
|
libflex_option_la_SOURCES += flex_option_messages.cc flex_option_messages.h
|
||||||
|
libflex_option_la_SOURCES += version.cc
|
||||||
|
|
||||||
|
libflex_option_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
libflex_option_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
|
||||||
|
# install the shared object into $(libdir)/kea/hooks
|
||||||
|
lib_hooksdir = $(libdir)/kea/hooks
|
||||||
|
lib_hooks_LTLIBRARIES = libdhcp_flex_option.la
|
||||||
|
|
||||||
|
libdhcp_flex_option_la_SOURCES =
|
||||||
|
libdhcp_flex_option_la_LDFLAGS = $(AM_LDFLAGS)
|
||||||
|
libdhcp_flex_option_la_LDFLAGS += -avoid-version -export-dynamic -module
|
||||||
|
libdhcp_flex_option_la_LIBADD = libflex_option.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/eval/libkea-eval.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(LOG4CPLUS_LIBS)
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(CRYPTO_LIBS)
|
||||||
|
libdhcp_flex_option_la_LIBADD += $(BOOST_LIBS)
|
||||||
|
|
||||||
|
# If we want to get rid of all generated messages files, we need to use
|
||||||
|
# make maintainer-clean. The proper way to introduce custom commands for
|
||||||
|
# that operation is to define maintainer-clean-local target. However,
|
||||||
|
# make maintainer-clean also removes Makefile, so running configure script
|
||||||
|
# is required. To make it easy to rebuild messages without going through
|
||||||
|
# reconfigure, a new target messages-clean has been added.
|
||||||
|
maintainer-clean-local:
|
||||||
|
rm -f flex_option_messages.h flex_option_messages.cc
|
||||||
|
|
||||||
|
# To regenerate messages files, one can do:
|
||||||
|
#
|
||||||
|
# make messages-clean
|
||||||
|
# make messages
|
||||||
|
#
|
||||||
|
# This is needed only when a .mes file is modified.
|
||||||
|
messages-clean: maintainer-clean-local
|
||||||
|
|
||||||
|
if GENERATE_MESSAGES
|
||||||
|
|
||||||
|
# Define rule to build logging source files from message file
|
||||||
|
messages: flex_option_messages.h flex_option_messages.cc
|
||||||
|
@echo Message files regenerated
|
||||||
|
|
||||||
|
flex_option_messages.h flex_option_messages.cc: flex_option_messages.mes
|
||||||
|
$(top_builddir)/src/lib/log/compiler/kea-msg-compiler $(top_srcdir)/src/hooks/dhcp/flex_option/flex_option_messages.mes
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
messages flex_option_messages.h flex_option_messages.cc:
|
||||||
|
@echo Messages generation disabled. Configure with --enable-generate-messages to enable it.
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
223
src/hooks/dhcp/flex_option/flex_option.cc
Normal file
223
src/hooks/dhcp/flex_option/flex_option.cc
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <flex_option.h>
|
||||||
|
#include <cc/simple_parser.h>
|
||||||
|
#include <dhcp/dhcp4.h>
|
||||||
|
#include <dhcp/libdhcp++.h>
|
||||||
|
#include <dhcp/option_definition.h>
|
||||||
|
#include <dhcp/option_space.h>
|
||||||
|
#include <dhcpsrv/cfgmgr.h>
|
||||||
|
#include <eval/eval_context.h>
|
||||||
|
|
||||||
|
using namespace isc;
|
||||||
|
using namespace isc::data;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::eval;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace flex_option {
|
||||||
|
|
||||||
|
FlexOptionImpl::OptionConfig::OptionConfig(uint16_t code) : code_(code) {
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexOptionImpl::OptionConfig::~OptionConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexOptionImpl::FlexOptionImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexOptionImpl::~FlexOptionImpl() {
|
||||||
|
option_config_map_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FlexOptionImpl::configure(ConstElementPtr options) {
|
||||||
|
if (!options) {
|
||||||
|
isc_throw(BadValue, "'options' parameter is mandatory");
|
||||||
|
}
|
||||||
|
if (options->getType() != Element::list) {
|
||||||
|
isc_throw(BadValue, "'options' parameter must be a list");
|
||||||
|
}
|
||||||
|
if (options->empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto option : options->listValue()) {
|
||||||
|
parseOptionConfig(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FlexOptionImpl::parseOptionConfig(ConstElementPtr option) {
|
||||||
|
uint16_t family = CfgMgr::instance().getFamily();
|
||||||
|
if (!option) {
|
||||||
|
isc_throw(BadValue, "null option element");
|
||||||
|
}
|
||||||
|
if (option->getType() != Element::map) {
|
||||||
|
isc_throw(BadValue, "option element is not a map");
|
||||||
|
}
|
||||||
|
ConstElementPtr code_elem = option->get("code");
|
||||||
|
ConstElementPtr name_elem = option->get("name");
|
||||||
|
if (!code_elem && !name_elem) {
|
||||||
|
isc_throw(BadValue, "'code' or 'name' must be specified: "
|
||||||
|
<< option->str());
|
||||||
|
}
|
||||||
|
uint16_t code;
|
||||||
|
if (code_elem) {
|
||||||
|
if (code_elem->getType() != Element::integer) {
|
||||||
|
isc_throw(BadValue, "'code' must be an integer: "
|
||||||
|
<< code_elem->str());
|
||||||
|
}
|
||||||
|
int64_t value = code_elem->intValue();
|
||||||
|
int64_t max_code;
|
||||||
|
if (family == AF_INET) {
|
||||||
|
max_code = numeric_limits<uint8_t>::max();
|
||||||
|
} else {
|
||||||
|
max_code = numeric_limits<uint16_t>::max();
|
||||||
|
}
|
||||||
|
if ((value < 0) || (value > max_code)) {
|
||||||
|
isc_throw(OutOfRange, "invalid 'code' value " << value
|
||||||
|
<< " not in [0.." << max_code << "]");
|
||||||
|
}
|
||||||
|
if (family == AF_INET) {
|
||||||
|
if (value == DHO_PAD) {
|
||||||
|
isc_throw(BadValue,
|
||||||
|
"invalid 'code' value 0: reserved for PAD");
|
||||||
|
} else if (value == DHO_END) {
|
||||||
|
isc_throw(BadValue,
|
||||||
|
"invalid 'code' value 255: reserved for END");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value == 0) {
|
||||||
|
isc_throw(BadValue, "invalid 'code' value 0: reserved");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
code = static_cast<uint16_t>(value);
|
||||||
|
}
|
||||||
|
if (name_elem) {
|
||||||
|
if (name_elem->getType() != Element::string) {
|
||||||
|
isc_throw(BadValue, "'name' must be a string: "
|
||||||
|
<< name_elem->str());
|
||||||
|
}
|
||||||
|
string name = name_elem->stringValue();
|
||||||
|
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);
|
||||||
|
if (!def) {
|
||||||
|
def = LibDHCP::getRuntimeOptionDef(space, name);
|
||||||
|
}
|
||||||
|
if (!def) {
|
||||||
|
def = LibDHCP::getLastResortOptionDef(space, name);
|
||||||
|
}
|
||||||
|
if (!def) {
|
||||||
|
isc_throw(BadValue, "no known '" << name << "' option in '"
|
||||||
|
<< space << "' space");
|
||||||
|
}
|
||||||
|
if (code_elem && (def->getCode() != code)) {
|
||||||
|
isc_throw(BadValue, "option '" << name << "' has code "
|
||||||
|
<< def->getCode() << " but 'code' is " << code);
|
||||||
|
}
|
||||||
|
code = def->getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option_config_map_.count(code)) {
|
||||||
|
isc_throw(BadValue, "option " << code << " was already specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
Option::Universe universe;
|
||||||
|
if (family == AF_INET) {
|
||||||
|
universe = Option::V4;
|
||||||
|
} else {
|
||||||
|
universe = Option::V6;
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionConfigPtr opt_cfg(new OptionConfig(code));
|
||||||
|
ConstElementPtr add_elem = option->get("add");
|
||||||
|
if (add_elem) {
|
||||||
|
if (add_elem->getType() != Element::string) {
|
||||||
|
isc_throw(BadValue, "'add' must be a string: "
|
||||||
|
<< add_elem->str());
|
||||||
|
}
|
||||||
|
string add = add_elem->stringValue();
|
||||||
|
if (add.empty()) {
|
||||||
|
isc_throw(BadValue, "'add' must not be empty");
|
||||||
|
}
|
||||||
|
opt_cfg->setAction(ADD);
|
||||||
|
opt_cfg->setText(add);
|
||||||
|
try {
|
||||||
|
EvalContext eval_ctx(universe);
|
||||||
|
eval_ctx.parseString(add, EvalContext::PARSER_STRING);
|
||||||
|
ExpressionPtr expr(new Expression(eval_ctx.expression));
|
||||||
|
opt_cfg->setExpr(expr);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
isc_throw(BadValue, "can't parse add expression ["
|
||||||
|
<< add << "] error: " << ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstElementPtr supersede_elem = option->get("supersede");
|
||||||
|
if (supersede_elem) {
|
||||||
|
if (supersede_elem->getType() != Element::string) {
|
||||||
|
isc_throw(BadValue, "'supersede' must be a string: "
|
||||||
|
<< supersede_elem->str());
|
||||||
|
}
|
||||||
|
string supersede = supersede_elem->stringValue();
|
||||||
|
if (supersede.empty()) {
|
||||||
|
isc_throw(BadValue, "'supersede' must not be empty");
|
||||||
|
}
|
||||||
|
if (opt_cfg->getAction() != NONE) {
|
||||||
|
isc_throw(BadValue, "multiple actions: " << option->str());
|
||||||
|
}
|
||||||
|
opt_cfg->setAction(SUPERSEDE);
|
||||||
|
opt_cfg->setText(supersede);
|
||||||
|
try {
|
||||||
|
EvalContext eval_ctx(universe);
|
||||||
|
eval_ctx.parseString(supersede, EvalContext::PARSER_STRING);
|
||||||
|
ExpressionPtr expr(new Expression(eval_ctx.expression));
|
||||||
|
opt_cfg->setExpr(expr);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
isc_throw(BadValue, "can't parse supersede expression ["
|
||||||
|
<< supersede << "] error: " << ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstElementPtr remove_elem = option->get("remove");
|
||||||
|
if (remove_elem) {
|
||||||
|
if (remove_elem->getType() != Element::string) {
|
||||||
|
isc_throw(BadValue, "'remove' must be a string: "
|
||||||
|
<< remove_elem->str());
|
||||||
|
}
|
||||||
|
string remove = remove_elem->stringValue();
|
||||||
|
if (remove.empty()) {
|
||||||
|
isc_throw(BadValue, "'remove' must not be empty");
|
||||||
|
}
|
||||||
|
if (opt_cfg->getAction() != NONE) {
|
||||||
|
isc_throw(BadValue, "multiple actions: " << option->str());
|
||||||
|
}
|
||||||
|
opt_cfg->setAction(REMOVE);
|
||||||
|
opt_cfg->setText(remove);
|
||||||
|
try {
|
||||||
|
EvalContext eval_ctx(universe);
|
||||||
|
eval_ctx.parseString(remove, EvalContext::PARSER_BOOL);
|
||||||
|
ExpressionPtr expr(new Expression(eval_ctx.expression));
|
||||||
|
opt_cfg->setExpr(expr);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
isc_throw(BadValue, "can't parse remove expression ["
|
||||||
|
<< remove << "] error: " << ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace flex_option
|
||||||
|
} // end of namespace isc
|
32
src/hooks/dhcp/flex_option/flex_option.dox
Normal file
32
src/hooks/dhcp/flex_option/flex_option.dox
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
@page libdhcp_flex_option Kea Flexible Option Hooks Library
|
||||||
|
|
||||||
|
@section libdhcp_flex_optionIntro Introduction
|
||||||
|
|
||||||
|
Welcome to Kea Flexible Option Hooks Library. This documentation is
|
||||||
|
addressed to developers who are interested in the internal operation
|
||||||
|
of the Flexible Option library. This file provides information needed
|
||||||
|
to understand and perhaps extend this library.
|
||||||
|
|
||||||
|
This documentation is stand-alone: you should have read and understood
|
||||||
|
the <a href="https://jenkins.isc.org/job/Kea_doc/doxygen/">Kea
|
||||||
|
Developer's Guide</a> and in particular its section about hooks.
|
||||||
|
|
||||||
|
@section flex_option Flexible Option Overview
|
||||||
|
|
||||||
|
Flexible Option (or flex_option) is a Hook library that can be loaded by
|
||||||
|
either kea-dhcp4 and kea-dhcp6 servers to extend them with additional
|
||||||
|
option value setting mechanisms.
|
||||||
|
|
||||||
|
@section flex_optionCode Flexible Option Code Overview
|
||||||
|
|
||||||
|
Todo
|
||||||
|
|
||||||
|
*/
|
214
src/hooks/dhcp/flex_option/flex_option.h
Normal file
214
src/hooks/dhcp/flex_option/flex_option.h
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#ifndef FLEX_OPTION_H
|
||||||
|
#define FLEX_OPTION_H
|
||||||
|
|
||||||
|
#include <cc/data.h>
|
||||||
|
#include <eval/evaluate.h>
|
||||||
|
#include <eval/token.h>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace flex_option {
|
||||||
|
|
||||||
|
/// @brief Flex Option implementation.
|
||||||
|
class FlexOptionImpl {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// @brief Action.
|
||||||
|
///
|
||||||
|
/// Currently supported actions are:
|
||||||
|
/// - add (if not already existing)
|
||||||
|
/// - supersede (as add but also when already existing)
|
||||||
|
/// - remove
|
||||||
|
enum Action {
|
||||||
|
NONE,
|
||||||
|
ADD,
|
||||||
|
SUPERSEDE,
|
||||||
|
REMOVE
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Option configuration.
|
||||||
|
///
|
||||||
|
/// Per option configuration.
|
||||||
|
class OptionConfig {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
///
|
||||||
|
/// @param option code.
|
||||||
|
OptionConfig(uint16_t code);
|
||||||
|
|
||||||
|
/// @brief Destructor.
|
||||||
|
virtual ~OptionConfig();
|
||||||
|
|
||||||
|
/// @brief Return option code.
|
||||||
|
///
|
||||||
|
/// @return option code.
|
||||||
|
uint16_t getCode() const {
|
||||||
|
return (code_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Set action.
|
||||||
|
///
|
||||||
|
/// @param action the action.
|
||||||
|
void setAction(Action action) {
|
||||||
|
action_ = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Return action.
|
||||||
|
///
|
||||||
|
/// @return action.
|
||||||
|
Action getAction() const {
|
||||||
|
return (action_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Set textual expression.
|
||||||
|
///
|
||||||
|
/// @param text the textual expression.
|
||||||
|
void setText(const std::string& text) {
|
||||||
|
text_ = text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Get textual expression.
|
||||||
|
///
|
||||||
|
/// @return textual expression.
|
||||||
|
const std::string& getText() const {
|
||||||
|
return (text_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Set match expression.
|
||||||
|
///
|
||||||
|
/// @param expr the match expression.
|
||||||
|
void setExpr(const isc::dhcp::ExpressionPtr& expr) {
|
||||||
|
expr_ = expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Get match expression.
|
||||||
|
///
|
||||||
|
/// @return the match expression.
|
||||||
|
const isc::dhcp::ExpressionPtr& getExpr() const {
|
||||||
|
return (expr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief The code.
|
||||||
|
uint16_t code_;
|
||||||
|
|
||||||
|
/// @brief The action.
|
||||||
|
Action action_;
|
||||||
|
|
||||||
|
/// @brief The textual expression.
|
||||||
|
std::string text_;
|
||||||
|
|
||||||
|
/// @brief The match expression.
|
||||||
|
isc::dhcp::ExpressionPtr expr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief The type of shared pointers to option config.
|
||||||
|
typedef boost::shared_ptr<OptionConfig> OptionConfigPtr;
|
||||||
|
|
||||||
|
/// @brief The type of the option config map.
|
||||||
|
typedef std::map<uint16_t, OptionConfigPtr> OptionConfigMap;
|
||||||
|
|
||||||
|
/// @brief Constructor.
|
||||||
|
FlexOptionImpl();
|
||||||
|
|
||||||
|
/// @brief Destructor.
|
||||||
|
~FlexOptionImpl();
|
||||||
|
|
||||||
|
/// @brief Get the option config map.
|
||||||
|
///
|
||||||
|
/// @return The option config map.
|
||||||
|
const OptionConfigMap& getOptionConfigMap() const {
|
||||||
|
return (option_config_map_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Configure the Flex Option implementation.
|
||||||
|
///
|
||||||
|
/// @param options The element with option config list.
|
||||||
|
/// @throw BadValue and similar exceptions on error.
|
||||||
|
void configure(isc::data::ConstElementPtr options);
|
||||||
|
|
||||||
|
/// @brief Process a query / response pair.
|
||||||
|
///
|
||||||
|
/// @tparam PktType The type of pointers to packets: Pkt4Ptr or Pkt6Ptr.
|
||||||
|
/// @param universe The option universe: Option::V4 or Option::V6.
|
||||||
|
/// @param query The query packet.
|
||||||
|
/// @param response The response packet.
|
||||||
|
template <typename PktType>
|
||||||
|
void process(isc::dhcp::Option::Universe universe,
|
||||||
|
PktType query, PktType response) {
|
||||||
|
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());
|
||||||
|
switch (opt_cfg->getAction()) {
|
||||||
|
case NONE:
|
||||||
|
break;
|
||||||
|
case ADD:
|
||||||
|
if (opt) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = isc::dhcp::evaluateString(*opt_cfg->getExpr(), *query);
|
||||||
|
if (value.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer.assign(value.begin(), value.end());
|
||||||
|
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
|
||||||
|
buffer));
|
||||||
|
response->addOption(opt);
|
||||||
|
break;
|
||||||
|
case SUPERSEDE:
|
||||||
|
value = isc::dhcp::evaluateString(*opt_cfg->getExpr(), *query);
|
||||||
|
if (value.empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (opt) {
|
||||||
|
response->delOption(opt_cfg->getCode());
|
||||||
|
opt = response->getOption(opt_cfg->getCode());
|
||||||
|
}
|
||||||
|
buffer.assign(value.begin(), value.end());
|
||||||
|
opt.reset(new isc::dhcp::Option(universe, opt_cfg->getCode(),
|
||||||
|
buffer));
|
||||||
|
response->addOption(opt);
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
if (!opt) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isc::dhcp::evaluateBool(*opt_cfg->getExpr(), *query)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (opt) {
|
||||||
|
response->delOption(opt_cfg->getCode());
|
||||||
|
opt = response->getOption(opt_cfg->getCode());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @brief The option config map (code and pointer to option config).
|
||||||
|
OptionConfigMap option_config_map_;
|
||||||
|
|
||||||
|
/// @brief Parse an option config.
|
||||||
|
///
|
||||||
|
/// @param option The element with option config.
|
||||||
|
/// @throw BadValue and similar exceptionson error.
|
||||||
|
void parseOptionConfig(isc::data::ConstElementPtr option);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief The type of shared pointers to Flex Option implementations.
|
||||||
|
typedef boost::shared_ptr<FlexOptionImpl> FlexOptionImplPtr;
|
||||||
|
|
||||||
|
} // end of namespace flex_option
|
||||||
|
} // end of namespace isc
|
||||||
|
#endif
|
115
src/hooks/dhcp/flex_option/flex_option_callouts.cc
Normal file
115
src/hooks/dhcp/flex_option/flex_option_callouts.cc
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the End User License
|
||||||
|
// Agreement. See COPYING file in the premium/ directory.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <flex_option.h>
|
||||||
|
#include <flex_option_log.h>
|
||||||
|
#include <cc/command_interpreter.h>
|
||||||
|
#include <hooks/hooks.h>
|
||||||
|
#include <dhcp/pkt4.h>
|
||||||
|
#include <dhcp/pkt6.h>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace flex_option {
|
||||||
|
|
||||||
|
FlexOptionImplPtr impl;
|
||||||
|
|
||||||
|
} // end of namespace flex_option
|
||||||
|
} // end of namespace isc
|
||||||
|
|
||||||
|
using namespace isc;
|
||||||
|
using namespace isc::data;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::hooks;
|
||||||
|
using namespace isc::flex_option;
|
||||||
|
|
||||||
|
// Functions accessed by the hooks framework use C linkage to avoid the name
|
||||||
|
// mangling that accompanies use of the C++ compiler as well as to avoid
|
||||||
|
// issues related to namespaces.
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
/// @brief This callout is called at the "pkt4_send" hook.
|
||||||
|
///
|
||||||
|
/// It retrieves v4 query and response packets, and then adds, supersedes
|
||||||
|
/// or removes option values in the response according to expressions
|
||||||
|
/// evaluated on the query.
|
||||||
|
///
|
||||||
|
/// @param handle CalloutHandle.
|
||||||
|
///
|
||||||
|
/// @return 0 upon success, non-zero otherwise
|
||||||
|
int pkt4_send(CalloutHandle& handle) {
|
||||||
|
// Get the parameters.
|
||||||
|
Pkt4Ptr query;
|
||||||
|
Pkt4Ptr response;
|
||||||
|
handle.getArgument("query4", query);
|
||||||
|
handle.getArgument("response4", response);
|
||||||
|
|
||||||
|
try {
|
||||||
|
impl->process<Pkt4Ptr>(Option::V4, query, response);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
LOG_ERROR(flex_option_logger, FLEX_OPTION_PROCESS_ERROR)
|
||||||
|
.arg(query->getLabel())
|
||||||
|
.arg(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief This callout is called at the "pkt6_send" hook.
|
||||||
|
///
|
||||||
|
/// It retrieves v6 query and response packets, and then adds, supersedes
|
||||||
|
/// or removes option values in the response according to expressions
|
||||||
|
/// evaluated on the query.
|
||||||
|
///
|
||||||
|
/// @param handle CalloutHandle.
|
||||||
|
///
|
||||||
|
/// @return 0 upon success, non-zero otherwise
|
||||||
|
int pkt6_send(CalloutHandle& handle) {
|
||||||
|
// Get the parameters.
|
||||||
|
Pkt6Ptr query;
|
||||||
|
Pkt6Ptr response;
|
||||||
|
handle.getArgument("query6", query);
|
||||||
|
handle.getArgument("response6", response);
|
||||||
|
|
||||||
|
try {
|
||||||
|
impl->process<Pkt6Ptr>(Option::V6, query, response);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
LOG_ERROR(flex_option_logger, FLEX_OPTION_PROCESS_ERROR)
|
||||||
|
.arg(query->getLabel())
|
||||||
|
.arg(ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief This function is called when the library is loaded.
|
||||||
|
///
|
||||||
|
/// @param handle library handle
|
||||||
|
/// @return 0 when initialization is successful, 1 otherwise
|
||||||
|
int load(LibraryHandle& handle) {
|
||||||
|
try {
|
||||||
|
impl.reset(new FlexOptionImpl());
|
||||||
|
ConstElementPtr options = handle.getParameter("options");
|
||||||
|
impl->configure(options);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
LOG_ERROR(flex_option_logger, FLEX_OPTION_LOAD_ERROR)
|
||||||
|
.arg(ex.what());
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief This function is called when the library is unloaded.
|
||||||
|
///
|
||||||
|
/// @return always 0.
|
||||||
|
int unload() {
|
||||||
|
impl.reset();
|
||||||
|
LOG_INFO(flex_option_logger, FLEX_OPTION_UNLOAD);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end extern "C"
|
17
src/hooks/dhcp/flex_option/flex_option_log.cc
Normal file
17
src/hooks/dhcp/flex_option/flex_option_log.cc
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <flex_option_log.h>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace flex_option {
|
||||||
|
|
||||||
|
isc::log::Logger flex_option_logger("flex-option-hooks");
|
||||||
|
|
||||||
|
} // namespace flex_option
|
||||||
|
} // namespace isc
|
21
src/hooks/dhcp/flex_option/flex_option_log.h
Normal file
21
src/hooks/dhcp/flex_option/flex_option_log.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#ifndef FLEX_OPTION_LOG_H
|
||||||
|
#define FLEX_OPTION_LOG_H
|
||||||
|
|
||||||
|
#include <log/logger_support.h>
|
||||||
|
#include <log/macros.h>
|
||||||
|
#include <flex_option_messages.h>
|
||||||
|
|
||||||
|
namespace isc {
|
||||||
|
namespace flex_option {
|
||||||
|
|
||||||
|
extern isc::log::Logger flex_option_logger;
|
||||||
|
|
||||||
|
} // end of namespace flex_option
|
||||||
|
} // end of namespace isc
|
||||||
|
#endif
|
23
src/hooks/dhcp/flex_option/flex_option_messages.cc
Normal file
23
src/hooks/dhcp/flex_option/flex_option_messages.cc
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// File created from ../../../../src/hooks/dhcp/flex_option/flex_option_messages.mes on Tue Oct 01 2019 14:08
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <log/message_types.h>
|
||||||
|
#include <log/message_initializer.h>
|
||||||
|
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_LOAD_ERROR = "FLEX_OPTION_LOAD_ERROR";
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_PROCESS_ERROR = "FLEX_OPTION_PROCESS_ERROR";
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_UNLOAD = "FLEX_OPTION_UNLOAD";
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char* values[] = {
|
||||||
|
"FLEX_OPTION_LOAD_ERROR", "loading Flex Option hooks library failed: %1",
|
||||||
|
"FLEX_OPTION_PROCESS_ERROR", "An error occurred processing query %1: %2",
|
||||||
|
"FLEX_OPTION_UNLOAD", "Flex Option hooks library has been unloaded",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const isc::log::MessageInitializer initializer(values);
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
12
src/hooks/dhcp/flex_option/flex_option_messages.h
Normal file
12
src/hooks/dhcp/flex_option/flex_option_messages.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// File created from ../../../../src/hooks/dhcp/flex_option/flex_option_messages.mes on Tue Oct 01 2019 14:08
|
||||||
|
|
||||||
|
#ifndef FLEX_OPTION_MESSAGES_H
|
||||||
|
#define FLEX_OPTION_MESSAGES_H
|
||||||
|
|
||||||
|
#include <log/message_types.h>
|
||||||
|
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_LOAD_ERROR;
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_PROCESS_ERROR;
|
||||||
|
extern const isc::log::MessageID FLEX_OPTION_UNLOAD;
|
||||||
|
|
||||||
|
#endif // FLEX_OPTION_MESSAGES_H
|
17
src/hooks/dhcp/flex_option/flex_option_messages.mes
Normal file
17
src/hooks/dhcp/flex_option/flex_option_messages.mes
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
|
||||||
|
% FLEX_OPTION_LOAD_ERROR loading Flex Option hooks library failed: %1
|
||||||
|
This error message indicates an error during loading the Flex Option
|
||||||
|
hooks library. The details of the error are provided as argument of
|
||||||
|
the log message.
|
||||||
|
|
||||||
|
% FLEX_OPTION_PROCESS_ERROR An error occurred processing query %1: %2
|
||||||
|
This error message indicates an error during processing of a query
|
||||||
|
by the Flex Option hooks library. The client identification information
|
||||||
|
from the query and the details of the error are provided as arguments
|
||||||
|
of the log message.
|
||||||
|
|
||||||
|
% FLEX_OPTION_UNLOAD Flex Option hooks library has been unloaded
|
||||||
|
This info message indicates that the Flex Option hooks library has been
|
||||||
|
unloaded.
|
||||||
|
|
1
src/hooks/dhcp/flex_option/tests/.gitignore
vendored
Normal file
1
src/hooks/dhcp/flex_option/tests/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/html
|
55
src/hooks/dhcp/flex_option/tests/Makefile.am
Normal file
55
src/hooks/dhcp/flex_option/tests/Makefile.am
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
SUBDIRS = .
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||||
|
AM_CPPFLAGS += -I$(top_builddir)/src/hooks/dhcp/flex_option -I$(top_srcdir)/src/hooks/dhcp/flex_option
|
||||||
|
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||||
|
AM_CPPFLAGS += -DFLEX_OPTION_LIB_SO=\"$(abs_top_builddir)/src/hooks/dhcp/flex_option/.libs/libdhcp_flex_option.so\"
|
||||||
|
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
|
||||||
|
|
||||||
|
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||||
|
|
||||||
|
if USE_STATIC_LINK
|
||||||
|
AM_LDFLAGS = -static
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Unit test data files need to get installed.
|
||||||
|
EXTRA_DIST =
|
||||||
|
|
||||||
|
CLEANFILES = *.gcno *.gcda
|
||||||
|
|
||||||
|
# TESTS_ENVIRONMENT = $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
|
||||||
|
LOG_COMPILER = $(LIBTOOL)
|
||||||
|
AM_LOG_FLAGS = --mode=execute
|
||||||
|
|
||||||
|
TESTS =
|
||||||
|
if HAVE_GTEST
|
||||||
|
TESTS += flex_option_unittests
|
||||||
|
|
||||||
|
flex_option_unittests_SOURCES = run_unittests.cc
|
||||||
|
flex_option_unittests_SOURCES += callout_unittests.cc
|
||||||
|
flex_option_unittests_SOURCES += load_unload_unittests.cc
|
||||||
|
|
||||||
|
flex_option_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
|
||||||
|
|
||||||
|
flex_option_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
|
||||||
|
|
||||||
|
flex_option_unittests_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
|
||||||
|
flex_option_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/eval/libkea-eval.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/database/libkea-database.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/cryptolink/libkea-cryptolink.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||||
|
flex_option_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||||
|
flex_option_unittests_LDADD += $(LOG4CPLUS_LIBS)
|
||||||
|
flex_option_unittests_LDADD += $(CRYPTO_LIBS)
|
||||||
|
flex_option_unittests_LDADD += $(BOOST_LIBS)
|
||||||
|
flex_option_unittests_LDADD += $(GTEST_LDADD)
|
||||||
|
endif
|
||||||
|
noinst_PROGRAMS = $(TESTS)
|
40
src/hooks/dhcp/flex_option/tests/callout_unittests.cc
Normal file
40
src/hooks/dhcp/flex_option/tests/callout_unittests.cc
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
/// @file This file contains tests which verify flexible option callouts.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <asiolink/asio_wrapper.h>
|
||||||
|
#include <exceptions/exceptions.h>
|
||||||
|
#include <dhcp/dhcp4.h>
|
||||||
|
#include <dhcp/dhcp6.h>
|
||||||
|
#include <dhcp/option.h>
|
||||||
|
#include <dhcp/pkt4.h>
|
||||||
|
#include <dhcp/pkt6.h>
|
||||||
|
#include <dhcpsrv/host.h>
|
||||||
|
#include <dhcp/option.h>
|
||||||
|
#include <dhcp/option_string.h>
|
||||||
|
#include <hooks/callout_manager.h>
|
||||||
|
#include <hooks/hooks.h>
|
||||||
|
#include <flex_option.h>
|
||||||
|
#include <flex_option_log.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace isc;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::hooks;
|
||||||
|
using namespace isc::flex_option;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern int pkt4_send(CalloutHandle& handle);
|
||||||
|
extern int pkt6_send(CalloutHandle& handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
79
src/hooks/dhcp/flex_option/tests/load_unload_unittests.cc
Normal file
79
src/hooks/dhcp/flex_option/tests/load_unload_unittests.cc
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
/// @file This file contains tests which exercise the load and unload
|
||||||
|
/// functions in the flexible option hook library. In order to test the load
|
||||||
|
/// function, one must be able to pass it hook library parameters. The
|
||||||
|
/// the only way to populate these parameters is by actually loading the
|
||||||
|
/// library via HooksManager::loadLibraries().
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <exceptions/exceptions.h>
|
||||||
|
#include <hooks/hooks_manager.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <cc/data.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace isc;
|
||||||
|
using namespace hooks;
|
||||||
|
using namespace isc::data;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// @brief Test fixture for testing loading and unloading the flex-id library
|
||||||
|
class LibLoadTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor
|
||||||
|
LibLoadTest() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Destructor
|
||||||
|
/// Removes files that may be left over from previous tests
|
||||||
|
virtual ~LibLoadTest() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Removes files that may be left over from previous tests
|
||||||
|
virtual void reset() {
|
||||||
|
HooksManager::unloadLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLib(const std::string& lib, ConstElementPtr params) {
|
||||||
|
libraries_.push_back(make_pair(lib, params));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadLibs() {
|
||||||
|
EXPECT_TRUE(HooksManager::loadLibraries(libraries_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void unloadLibs() {
|
||||||
|
EXPECT_NO_THROW(HooksManager::unloadLibraries());
|
||||||
|
}
|
||||||
|
|
||||||
|
HookLibsCollection libraries_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simple test that checks the library can be loaded and unloaded several times.
|
||||||
|
TEST_F(LibLoadTest, validLoad) {
|
||||||
|
|
||||||
|
// Prepare parameters for the callout parameters library.
|
||||||
|
ElementPtr params = Element::createMap();
|
||||||
|
ElementPtr options = Element::createList();
|
||||||
|
params->set("options", options);
|
||||||
|
|
||||||
|
addLib(FLEX_OPTION_LIB_SO, params);
|
||||||
|
|
||||||
|
loadLibs();
|
||||||
|
unloadLibs();
|
||||||
|
|
||||||
|
loadLibs();
|
||||||
|
unloadLibs();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
19
src/hooks/dhcp/flex_option/tests/run_unittests.cc
Normal file
19
src/hooks/dhcp/flex_option/tests/run_unittests.cc
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <log/logger_support.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char* argv[]) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
isc::log::initLogger();
|
||||||
|
int result = RUN_ALL_TESTS();
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
17
src/hooks/dhcp/flex_option/version.cc
Normal file
17
src/hooks/dhcp/flex_option/version.cc
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <hooks/hooks.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
/// @brief returns Kea hooks version.
|
||||||
|
int version() {
|
||||||
|
return (KEA_HOOKS_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user