feature="final method"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
- [],
[class Foo {
public:
virtual ~Foo() {};
virtual void bar() final;
- };])],
+ };],[])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
continue])
[AC_MSG_RESULT([no])
continue])
+ AC_MSG_CHECKING(static_assert support)
+ feature="static_assert"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [static_assert(1 + 1 == 2, "");],
+ [])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ continue])
+
+ AC_MSG_CHECKING(template alias)
+ feature="template alias"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [template<int i>
+ class I {
+ public: int get() { return i; };
+ };
+ using Zero = I<0>;],
+ [Zero Z;
+ return Z.get();])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ continue])
+
AC_MSG_CHECKING(lambda support)
feature="lambda"
AC_COMPILE_IFELSE(
continue])
done
+# Check for std::is_base_of support
+AC_MSG_CHECKING([for std::is_base_of])
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <type_traits>
+ class A {};
+ class B : A {};]
+ [static_assert(std::is_base_of<A, B>::value, "");])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_IS_BASE_OF], [1],
+ [Define to 1 if std::is_base_of is available])],
+ [AC_MSG_RESULT(no)])
+
dnl Determine if we are using GNU sed
GNU_SED=no
$SED --version 2> /dev/null | grep GNU > /dev/null 2>&1
CPPFLAGS=$CPPFLAGS_SAVED
fi
+# Check for CreateUnifiedDiff from gtest >= 1.8.0
+if test $enable_gtest != "no"; then
+ AC_MSG_CHECKING([for CreateUnifiedDiff in $GTEST_INCLUDES/gtest.h])
+ CPPFLAGS_SAVED=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES $GTEST_INCLUDES"
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <boost/algorithm/string.hpp>
+ #include <gtest/gtest.h>
+ #include <string>
+ #include <vector>
+ std::string nodiff(std::string text) {
+ std::vector<std::string> lines;
+ boost::split(lines, text, boost::is_any_of("\n"));
+ using namespace testing::internal;
+ return (edit_distance::CreateUnifiedDiff(lines, lines));
+ }],
+ [return 0;])],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_CREATE_UNIFIED_DIFF], [1],
+ [Define to 1 if gtest defines edit_distance::CreateUnifiedDiff])],
+ [AC_MSG_RESULT(no)])
+ CPPFLAGS=$CPPFLAGS_SAVED
+fi
+
#
# ASIO: we extensively use it as the C++ event management module.
#
enable_generate_parser=$enableval, enable_generate_parser=no)
# Check if flex is avaible. Flex is not needed for building Kea sources,
-# unless you want to regenerate grammar in src/lib/eval
+# unless you want to regenerate grammars
AC_PROG_LEX
# Check if bison is available. Bison is not needed for building Kea sources,
-# unless you want to regenerate grammar in src/lib/eval
+# unless you want to regenerate grammars
AC_PROG_YACC
if test "x$enable_generate_parser" != "xno"; then
fi
# Ok, let's check if we have at least 3.0.0 version of the bison. The code used
-# to generate src/lib/eval parser is roughly based on bison 3.0 examples.
+# to generate parsers is roughly based on bison 3.0 examples.
cat > bisontest.y << EOF
%require "3.0.0"
%token X
AC_DEFINE([CONFIG_H_WAS_INCLUDED], [1], [config.h inclusion marker])
-AC_CONFIG_FILES([compatcheck/Makefile
+AC_CONFIG_FILES([Makefile
+ compatcheck/Makefile
dns++.pc
- doc/design/datasrc/Makefile
+ doc/Makefile
doc/design/Makefile
+ doc/design/datasrc/Makefile
doc/guide/Makefile
- doc/Makefile
doc/version.ent
+ ext/Makefile
ext/coroutine/Makefile
ext/gtest/Makefile
- ext/Makefile
m4macros/Makefile
- Makefile
src/Makefile
src/bin/Makefile
+ src/bin/admin/Makefile
+ src/bin/admin/kea-admin
+ src/bin/admin/tests/Makefile
+ src/bin/admin/tests/cql_tests.sh
+ src/bin/admin/tests/data/Makefile
+ src/bin/admin/tests/memfile_tests.sh
+ src/bin/admin/tests/mysql_tests.sh
+ src/bin/admin/tests/pgsql_tests.sh
src/bin/agent/Makefile
src/bin/agent/tests/Makefile
src/bin/agent/tests/ca_process_tests.sh
src/bin/perfdhcp/Makefile
src/bin/perfdhcp/tests/Makefile
src/bin/perfdhcp/tests/testdata/Makefile
- src/bin/admin/Makefile
- src/bin/admin/kea-admin
- src/bin/admin/tests/Makefile
- src/bin/admin/tests/data/Makefile
- src/bin/admin/tests/memfile_tests.sh
- src/bin/admin/tests/mysql_tests.sh
- src/bin/admin/tests/pgsql_tests.sh
- src/bin/admin/tests/cql_tests.sh
- src/bin/agent/tests/test_libraries.h
src/hooks/Makefile
src/hooks/dhcp/Makefile
src/hooks/dhcp/user_chk/Makefile
src/lib/dns/gen-rdatacode.py
src/lib/dns/tests/Makefile
src/lib/dns/tests/testdata/Makefile
+ src/lib/eval/Makefile
+ src/lib/eval/tests/Makefile
src/lib/exceptions/Makefile
src/lib/exceptions/tests/Makefile
src/lib/hooks/Makefile
src/lib/process/spec_config.h.pre
src/lib/process/tests/Makefile
src/lib/process/testutils/Makefile
- src/lib/testutils/Makefile
- src/lib/testutils/dhcp_test_lib.sh
src/lib/stats/Makefile
src/lib/stats/tests/Makefile
+ src/lib/testutils/Makefile
+ src/lib/testutils/dhcp_test_lib.sh
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/python/Makefile
src/lib/util/threads/Makefile
src/lib/util/threads/tests/Makefile
src/lib/util/unittests/Makefile
- src/lib/eval/Makefile
- src/lib/eval/tests/Makefile
src/share/Makefile
src/share/database/Makefile
src/share/database/scripts/Makefile
+ src/share/database/scripts/cql/Makefile
src/share/database/scripts/mysql/Makefile
src/share/database/scripts/mysql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/mysql/upgrade_2.0_to_3.0.sh
src/share/database/scripts/pgsql/Makefile
src/share/database/scripts/pgsql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/pgsql/upgrade_2.0_to_3.0.sh
- src/share/database/scripts/cql/Makefile
tools/Makefile
tools/path_replacer.sh
])
- AC_CONFIG_COMMANDS([permissions], [
+AC_CONFIG_COMMANDS([permissions], [
+ chmod +x src/bin/admin/kea-admin
chmod +x src/bin/dhcp4/tests/dhcp4_process_tests.sh
chmod +x src/bin/dhcp6/tests/dhcp6_process_tests.sh
chmod +x src/bin/keactrl/keactrl
chmod +x src/bin/keactrl/tests/keactrl_tests.sh
- chmod +x src/bin/admin/kea-admin
chmod +x src/lib/dns/gen-rdatacode.py
chmod +x src/lib/log/tests/console_test.sh
chmod +x src/lib/log/tests/destination_test.sh
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
}
void Dhcp4to6Ipc::open() {
- uint32_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
+ uint16_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
if (port == 0) {
Dhcp4o6IpcBase::close();
return;
}
int old_fd = socket_fd_;
- socket_fd_ = Dhcp4o6IpcBase::open(static_cast<uint16_t>(port),
- ENDPOINT_TYPE_V4);
+ socket_fd_ = Dhcp4o6IpcBase::open(port, ENDPOINT_TYPE_V4);
if ((old_fd == -1) && (socket_fd_ != old_fd)) {
IfaceMgr::instance().addExternalSocket(socket_fd_,
Dhcp4to6Ipc::handler);
cfg->setDeclinePeriod(probation_period);
// Set the DHCPv4-over-DHCPv6 interserver port.
- // @todo Change for uint16_t
- uint32_t dhcp4o6_port = getUint32(global, "dhcp4o6-port");
+ uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
cfg->setDhcp4o6Port(dhcp4o6_port);
}
-
-private:
-
- /// @brief Returns a value converted to uint32_t
- ///
- /// Instantiation of getIntType() to uint32_t
- ///
- /// @param scope specified parameter will be extracted from this scope
- /// @param name name of the parameter
- /// @return an uint32_t value
- uint32_t getUint32(isc::data::ConstElementPtr scope,
- const std::string& name) {
- return (getIntType<uint32_t>(scope, name));
- }
};
} // anonymous namespace
usage();
}
+ // This is the DHCPv4 server
+ CfgMgr::instance().setFamily(AF_INET);
+
if (check_mode) {
try {
/// for those option-data declarations.
const SimpleDefaults SimpleParser4::OPTION4_DEFAULTS = {
{ "space", Element::string, "dhcp4"},
- { "csv-format", Element::boolean, "true"},
- { "encapsulate", Element::string, "" }
+ { "csv-format", Element::boolean, "true"}
};
/// @brief This table defines default global values for DHCPv4
" } ] \n"
"} \n";
- ConstElementPtr json;
- ASSERT_NO_THROW(json = parseJSON(config));
-
- ConstElementPtr status;
- EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
- ASSERT_TRUE(status);
- checkResult(status, 1);
-
EXPECT_THROW(parseDHCP4(config), Dhcp4ParseError);
}
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
// we should have appropriate default value set. See
// SimpleParser4::OPTION4_DEFAULTS for a list of default values.
checkStringValue(option, "space", "dhcp4");
- checkStringValue(option, "encapsulate", "");
checkBoolValue(option, "csv-format", true);
}
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
}
void Dhcp6to4Ipc::open() {
- uint32_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
+ uint16_t port = CfgMgr::instance().getStagingCfg()->getDhcp4o6Port();
if (port == 0) {
Dhcp4o6IpcBase::close();
return;
}
int old_fd = socket_fd_;
- socket_fd_ = Dhcp4o6IpcBase::open(static_cast<uint16_t>(port),
- ENDPOINT_TYPE_V6);
+ socket_fd_ = Dhcp4o6IpcBase::open(port, ENDPOINT_TYPE_V6);
if ((old_fd == -1) && (socket_fd_ != old_fd)) {
IfaceMgr::instance().addExternalSocket(socket_fd_,
Dhcp6to4Ipc::handler);
private:
- /// @brief Get an uint8_t value
- ///
- /// Instantiation of getIntType() to uint8_t
- ///
- /// @param scope specified parameter will be extracted from this scope
- /// @param name name of the parameter
- /// @return uint8_t value
- /// @throw isc::dhcp::DhcpConfigError when it is not an uint8_t
- uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
- return (getIntType<uint8_t>(scope, name));
- }
-
/// Pointer to the created pool object.
isc::dhcp::Pool6Ptr pool_;
srv_config->setDeclinePeriod(probation_period);
// Set the DHCPv4-over-DHCPv6 interserver port.
- // @todo Change for uint16_t
- uint32_t dhcp4o6_port = getUint32(global, "dhcp4o6-port");
+ uint16_t dhcp4o6_port = getUint16(global, "dhcp4o6-port");
srv_config->setDhcp4o6Port(dhcp4o6_port);
}
-
-private:
-
- /// @brief Returns a value converted to uint32_t
- ///
- /// Instantiation of getIntType() to uint32_t
- ///
- /// @param scope specified parameter will be extracted from this scope
- /// @param name name of the parameter
- /// @return an uint32_t value
- uint32_t getUint32(isc::data::ConstElementPtr scope,
- const std::string& name) {
- return (getIntType<uint32_t>(scope, name));
- }
};
} // anonymous namespace
usage();
}
+ // This is the DHCPv6 server
+ CfgMgr::instance().setFamily(AF_INET6);
+
if (check_mode) {
try {
// We need to initialize logging, in case any error messages are to be printed.
/// for those option-data declarations.
const SimpleDefaults SimpleParser6::OPTION6_DEFAULTS = {
{ "space", Element::string, "dhcp6"},
- { "csv-format", Element::boolean, "true"},
- { "encapsulate", Element::string, "" }
+ { "csv-format", Element::boolean, "true"}
};
/// @brief This table defines default global values for DHCPv6
" } ] \n"
"} \n";
- ConstElementPtr json = parseJSON(config);
-
- ConstElementPtr status;
- EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
- ASSERT_TRUE(status);
- checkResult(status, 1);
-
EXPECT_THROW(parseDHCP6(config), Dhcp6ParseError);
}
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
// This test checks if the parameters in option-data are assigned default values
// if not explicitly specified.
-TEST_F(SimpleParser6Test, optionDataDefaults4) {
+TEST_F(SimpleParser6Test, optionDataDefaults6) {
ElementPtr global = parseJSON("{ \"renew-timer\": 1,"
" \"rebind-timer\": 2,"
" \"preferred-lifetime\": 3,"
// we should have appropriate default value set. See
// SimpleParser4::OPTION4_DEFAULTS for a list of default values.
checkStringValue(option, "space", "dhcp6");
- checkStringValue(option, "encapsulate", "");
checkBoolValue(option, "csv-format", true);
}
#include <cstring>
#include <cassert>
#include <climits>
+#include <list>
#include <map>
#include <cstdio>
#include <iostream>
}
}
+ElementPtr
+copy(ConstElementPtr from, int level) {
+ if (isNull(from)) {
+ isc_throw(BadValue, "copy got a null pointer");
+ }
+ int from_type = from->getType();
+ if (from_type == Element::integer) {
+ return (ElementPtr(new IntElement(from->intValue())));
+ } else if (from_type == Element::real) {
+ return (ElementPtr(new DoubleElement(from->doubleValue())));
+ } else if (from_type == Element::boolean) {
+ return (ElementPtr(new BoolElement(from->boolValue())));
+ } else if (from_type == Element::null) {
+ return (ElementPtr(new NullElement()));
+ } else if (from_type == Element::string) {
+ return (ElementPtr(new StringElement(from->stringValue())));
+ } else if (from_type == Element::list) {
+ ElementPtr result = ElementPtr(new ListElement());
+ typedef std::vector<ElementPtr> ListType;
+ const ListType& value = from->listValue();
+ for (ListType::const_iterator it = value.cbegin();
+ it != value.cend(); ++it) {
+ if (level == 0) {
+ result->add(*it);
+ } else {
+ result->add(copy(*it, level - 1));
+ }
+ }
+ return (result);
+ } else if (from_type == Element::map) {
+ ElementPtr result = ElementPtr(new MapElement());
+ typedef std::map<std::string, ConstElementPtr> MapType;
+ const MapType& value = from->mapValue();
+ for (MapType::const_iterator it = value.cbegin();
+ it != value.cend(); ++it) {
+ if (level == 0) {
+ result->set(it->first, it->second);
+ } else {
+ result->set(it->first, copy(it->second, level - 1));
+ }
+ }
+ return (result);
+ } else {
+ isc_throw(BadValue, "copy got an element of type: " << from_type);
+ }
+}
+
+namespace {
+
+// Helper function which blocks infinite recursion
+bool
+isEquivalent0(ConstElementPtr a, ConstElementPtr b, unsigned level)
+{
+ // check looping forever on cycles
+ if (!level) {
+ isc_throw(BadValue, "isEquivalent got infinite recursion: "
+ "arguments include cycles");
+ }
+ if (!a || !b) {
+ isc_throw(BadValue, "isEquivalent got a null pointer");
+ }
+ // check types
+ if (a->getType() != b->getType()) {
+ return (false);
+ }
+ if (a->getType() == Element::list) {
+ // check empty
+ if (a->empty()) {
+ return (b->empty());
+ }
+ // check size
+ if (a->size() != b->size()) {
+ return (false);
+ }
+
+ // copy b into a list
+ const size_t s = a->size();
+ typedef std::list<ConstElementPtr> ListType;
+ ListType l;
+ for (size_t i = 0; i < s; ++i) {
+ l.push_back(b->get(i));
+ }
+
+ // iterate on a
+ for (size_t i = 0; i < s; ++i) {
+ ConstElementPtr item = a->get(i);
+ // lookup this item in the list
+ bool found = false;
+ for (ListType::iterator it = l.begin();
+ it != l.end(); ++it) {
+ // if found in the list remove it
+ if (isEquivalent0(item, *it, level - 1)) {
+ found = true;
+ l.erase(it);
+ break;
+ }
+ }
+ // if not found argument differs
+ if (!found) {
+ return (false);
+ }
+ }
+
+ // sanity check: the list must be empty
+ if (!l.empty()) {
+ isc_throw(Unexpected, "isEquivalent internal error");
+ }
+ return (true);
+ } else if (a->getType() == Element::map) {
+ // iterate on the first map
+ typedef std::map<std::string, ConstElementPtr> MapType;
+ const MapType& ma = a->mapValue();
+ for (MapType::const_iterator it = ma.begin();
+ it != ma.end() ; ++it) {
+ // get the b value for the given keyword and recurse
+ ConstElementPtr item = b->get(it->first);
+ if (!item || !isEquivalent0(it->second, item, level - 1)) {
+ return (false);
+ }
+ }
+ // iterate on the second map
+ const MapType& mb = b->mapValue();
+ for (MapType::const_iterator it = mb.begin();
+ it != mb.end() ; ++it) {
+ // check if the keyword exists
+ if (!a->contains(it->first)) {
+ return (false);
+ }
+ }
+ return (true);
+ } else {
+ return (a->equals(*b));
+ }
+}
+
+}
+
+bool
+isEquivalent(ConstElementPtr a, ConstElementPtr b) {
+ return (isEquivalent0(a, b, 100));
+}
+
+void
+prettyPrint(ConstElementPtr element, std::ostream& out,
+ unsigned indent, unsigned step) {
+ if (!element) {
+ isc_throw(BadValue, "prettyPrint got a null pointer");
+ }
+ if (element->getType() == Element::list) {
+ // empty list case
+ if (element->empty()) {
+ out << "[ ]";
+ return;
+ }
+
+ // complex ? multiline : oneline
+ if (!element->get(0)) {
+ isc_throw(BadValue, "prettyPrint got a null pointer");
+ }
+ int first_type = element->get(0)->getType();
+ bool complex = false;
+ if ((first_type == Element::list) || (first_type == Element::map)) {
+ complex = true;
+ }
+ std::string separator = complex ? ",\n" : ", ";
+
+ // open the list
+ out << "[" << (complex ? "\n" : " ");
+
+ // iterate on items
+ typedef std::vector<ElementPtr> ListType;
+ const ListType& l = element->listValue();
+ for (ListType::const_iterator it = l.begin();
+ it != l.end(); ++it) {
+ // add the separator if not the first item
+ if (it != l.begin()) {
+ out << separator;
+ }
+ // add indentation
+ if (complex) {
+ out << std::string(indent + step, ' ');
+ }
+ // recursive call
+ prettyPrint(*it, out, indent + step, step);
+ }
+
+ // close the list
+ if (complex) {
+ out << "\n" << std::string(indent, ' ');
+ } else {
+ out << " ";
+ }
+ out << "]";
+ } else if (element->getType() == Element::map) {
+ // empty map case
+ if (element->size() == 0) {
+ out << "{ }";
+ return;
+ }
+
+ // open the map
+ out << "{\n";
+
+ // iterate on keyword: value
+ typedef std::map<std::string, ConstElementPtr> MapType;
+ const MapType& m = element->mapValue();
+ for (MapType::const_iterator it = m.begin();
+ it != m.end(); ++it) {
+ // add the separator if not the first item
+ if (it != m.begin()) {
+ out << ",\n";
+ }
+ // add indentation
+ out << std::string(indent + step, ' ');
+ // add keyword:
+ out << "\"" << it->first << "\": ";
+ // recusive call
+ prettyPrint(it->second, out, indent + step, step);
+ }
+
+ // close the map
+ out << "\n" << std::string(indent, ' ') << "}";
+ } else {
+ // not a list or a map
+ element->toJSON(out);
+ }
+}
+
+std::string
+prettyPrint(ConstElementPtr element, unsigned indent, unsigned step) {
+ std::stringstream ss;
+ prettyPrint(element, ss, indent, step);
+ return (ss.str());
+}
+
void Element::preprocess(std::istream& in, std::stringstream& out) {
std::string line;
/// Raises a TypeError if either ElementPtr is not a MapElement
void merge(ElementPtr element, ConstElementPtr other);
+/// \brief Copy the data up to a nesting level.
+///
+/// The copy is a deep copy so nothing is shared if it is not
+/// under the given nesting level.
+///
+/// \param from the pointer to the element to copy
+/// \param level nesting level (default is 100, 0 means shallow copy,
+/// negative means outbound and perhaps looping forever).
+/// \return a pointer to a fresh copy
+/// \throw raises a BadValue is a null pointer occurs.
+ElementPtr copy(ConstElementPtr from, int level = 100);
+
+/// \brief Compares the data with other using unordered lists
+///
+/// This comparison function handles lists (JSON arrays) as
+/// unordered multi sets (multi means an item can occurs more
+/// than once as soon as it occurs the same number of times).
+bool isEquivalent(ConstElementPtr a, ConstElementPtr b);
+
+/// \brief Pretty prints the data into stream.
+///
+/// This operator converts the \c ConstElementPtr into a string and
+/// inserts it into the output stream \c out with an initial
+/// indentation \c indent and add at each level \c step spaces.
+///
+/// \param element A \c ConstElementPtr to pretty print
+/// \param out A \c std::ostream on which the print operation is performed
+/// \param indent An initial number of spaces to add each new line
+/// \param step A number of spaces to add to indentation at a new level
+void prettyPrint(ConstElementPtr element, std::ostream& out,
+ unsigned indent = 0, unsigned step = 2);
+
+/// \brief Pretty prints the data into string
+///
+/// This operator converts the \c ConstElementPtr into a string with
+/// an initial indentation \c indent and add at each level \c step spaces.
+///
+/// \param element A \c ConstElementPtr to pretty print
+/// \param indent An initial number of spaces to add each new line
+/// \param step A number of spaces to add to indentation at a new level
+/// \return a string where element was pretty printed
+std::string prettyPrint(ConstElementPtr element,
+ unsigned indent = 0, unsigned step = 2);
+
///
/// \brief Insert Element::Position as a string into stream.
///
}
ConstElementPtr elem = parent->get(name);
if (!elem) {
- return (data::Element::ZERO_POSITION());
+ return (parent->getPosition());
}
return (elem->getPosition());
}
/// @brief Utility method that returns position of an element
///
- /// It's mostly useful for logging. When any necessary parameter is
- /// missing (either parent is null or it doesn't contain specified
- /// name) ZERO_POSITION is returned.
+ /// It's mostly useful for logging. If the element is missing
+ /// the parent position is returned or ZERO_POSITION if parent
+ /// is null.
///
/// @param name position of that element will be returned
/// @param parent parent element (optional)
<< "' (" << getPosition(name, scope) << ")");
}
}
+
+ /// @brief Returns a value converted to uint32_t
+ ///
+ /// Instantiation of getIntType() to uint32_t
+ ///
+ /// @param scope specified parameter will be extracted from this scope
+ /// @param name name of the parameter
+ /// @return an uint32_t value
+ /// @throw isc::dhcp::DhcpConfigError when it is not an uint32_t
+ uint32_t getUint32(isc::data::ConstElementPtr scope,
+ const std::string& name) {
+ return (getIntType<uint32_t>(scope, name));
+ }
+
+ /// @brief Returns a value converted to uint16_t
+ ///
+ /// Instantiation of getIntType() to uint16_t
+ ///
+ /// @param scope specified parameter will be extracted from this scope
+ /// @param name name of the parameter
+ /// @return an uint16_t value
+ /// @throw isc::dhcp::DhcpConfigError when it is not an uint16_t
+ uint16_t getUint16(isc::data::ConstElementPtr scope,
+ const std::string& name) {
+ return (getIntType<uint16_t>(scope, name));
+ }
+
+ /// @brief Get an uint8_t value
+ ///
+ /// Instantiation of getIntType() to uint8_t
+ ///
+ /// @param scope specified parameter will be extracted from this scope
+ /// @param name name of the parameter
+ /// @return uint8_t value
+ /// @throw isc::dhcp::DhcpConfigError when it is not an uint8_t
+ uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
+ return (getIntType<uint8_t>(scope, name));
+ }
};
};
-// Copyright (C) 2009-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2009-2017 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
#include <gtest/gtest.h>
#include <boost/foreach.hpp>
+#include <boost/pointer_cast.hpp>
#include <boost/assign/std/vector.hpp>
#include <climits>
#include <cc/data.h>
+#include <util/unittests/check_valgrind.h>
using namespace isc::data;
BOOST_FOREACH(const std::string& s, sv) {
// Test two types of fromJSON(): with string and istream.
- for (int i = 0; i < 2; ++i) {
+ for (unsigned i = 0; i < 2; ++i) {
// test << operator, which uses Element::str()
if (i == 0) {
el = Element::fromJSON(s);
EXPECT_NO_THROW(Element::fromJSON("\"\\\"\\\"\""));
// A whitespace test
EXPECT_NO_THROW(Element::fromJSON("\" \n \r \t \f \n \n \t\""));
+ // Escape for forward slash is optional
+ ASSERT_NO_THROW(Element::fromJSON("\"foo\\/bar\""));
+ EXPECT_EQ("foo/bar", Element::fromJSON("\"foo\\/bar\"")->stringValue());
+ // Control characters
+ StringElement bell("foo\abar");
+ EXPECT_EQ("\"foo\\u0007bar\"", bell.str());
+}
+
+// This test verifies that strings are copied.
+TEST(Element, stringCopy) {
+ // StringElement constructor copies its string argument.
+ std::string foo = "foo";
+ ElementPtr elem = ElementPtr(new StringElement(foo));
+ EXPECT_EQ(foo, elem->stringValue());
+ foo[1] = 'O';
+ EXPECT_EQ("fOo", foo);
+ EXPECT_NE(foo, elem->stringValue());
+
+ // Map keys are copied too.
+ ElementPtr map = ElementPtr(new MapElement());
+ std::string bar = "bar";
+ map->set(bar, ElementPtr(new IntElement(1)));
+ ConstElementPtr item = map->get("bar");
+ ASSERT_TRUE(item);
+ EXPECT_EQ(1, item->intValue());
+ bar[0] = 'B';
+ EXPECT_EQ("Bar", bar);
+ EXPECT_TRUE(map->get("bar"));
+ EXPECT_FALSE(map->get(bar));
}
// This test verifies that a backslash can be used in element content
el->set(long_maptag, Element::create("bar"));
EXPECT_EQ("bar", el->find(long_maptag)->stringValue());
+ // Null pointer value
+ el.reset(new MapElement());
+ ConstElementPtr null_ptr;
+ el->set("value", null_ptr);
+ EXPECT_FALSE(el->get("value"));
+ EXPECT_EQ("{ \"value\": None }", el->str());
}
TEST(Element, to_and_from_wire) {
c = Element::fromJSON("{ \"a\": 1 }");
EXPECT_EQ(*removeIdentical(a, b), *c);
- EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)),
- TypeError);
+ // removeIdentical() is overloaded so force the first argument to const
+ ConstElementPtr bad = Element::create(1);
+ EXPECT_THROW(removeIdentical(bad, Element::create(2)), TypeError);
}
TEST(Element, merge) {
}
+// This test checks copy.
+TEST(Element, copy) {
+ // Null pointer
+ ElementPtr elem;
+ EXPECT_THROW(copy(elem, 0), isc::BadValue);
+ EXPECT_THROW(copy(elem), isc::BadValue);
+ EXPECT_THROW(copy(elem, -1), isc::BadValue);
+
+ // Basic types
+ elem.reset(new IntElement(1));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("1")));
+ EXPECT_EQ("1", elem->str());
+ ElementPtr copied;
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+
+ elem.reset(new DoubleElement(1.0));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("1.0")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+
+ elem.reset(new BoolElement(true));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("true")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+
+ elem.reset(new NullElement());
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("null")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+
+ elem.reset(new StringElement("foo"));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("\"foo\"")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+ ASSERT_NO_THROW(elem->setValue(std::string("bar")));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("\"bar\"")));
+ EXPECT_FALSE(elem->equals(*copied));
+
+ elem.reset(new ListElement());
+ ElementPtr item = ElementPtr(new IntElement(1));
+ elem->add(item);
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("[ 1 ]")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+ ElementPtr deep;
+ ASSERT_NO_THROW(deep = copy(elem));
+ EXPECT_TRUE(elem->equals(*deep));
+ ASSERT_NO_THROW(item = elem->getNonConst(0));
+ ASSERT_NO_THROW(item->setValue(2));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("[ 2 ]")));
+ EXPECT_TRUE(elem->equals(*copied));
+ EXPECT_FALSE(elem->equals(*deep));
+
+ elem.reset(new MapElement());
+ item.reset(new StringElement("bar"));
+ elem->set("foo", item);
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("{ \"foo\": \"bar\" }")));
+ ASSERT_NO_THROW(copied = copy(elem, 0));
+ EXPECT_TRUE(elem->equals(*copied));
+ ASSERT_NO_THROW(deep = copy(elem));
+ EXPECT_TRUE(elem->equals(*deep));
+ ASSERT_NO_THROW(item->setValue(std::string("Bar")));
+ EXPECT_TRUE(elem->equals(*Element::fromJSON("{ \"foo\": \"Bar\" }")));
+ EXPECT_TRUE(elem->equals(*copied));
+ EXPECT_FALSE(elem->equals(*deep));
+
+ // Complex example
+ std::string input = "{ \n"
+ "\"integer\": 1,\n"
+ "\"double\": 1.0,\n"
+ "\"boolean\": true,\n"
+ "\"null\": null,\n"
+ "\"string\": \"foobar\",\n"
+ "\"list\": [ 1, 2 ],\n"
+ "\"map\": { \"foo\": \"bar\" } }\n";
+ ConstElementPtr complex;
+ ASSERT_NO_THROW(complex = Element::fromJSON(input));
+ ASSERT_NO_THROW(copied = copy(complex, 0));
+ EXPECT_TRUE(copied->equals(*complex));
+ ASSERT_NO_THROW(deep = copy(complex));
+ EXPECT_TRUE(deep->equals(*complex));
+ ElementPtr shallow;
+ ASSERT_NO_THROW(shallow = copy(complex, 1));
+ EXPECT_TRUE(shallow->equals(*complex));
+ // Try to modify copies
+ ASSERT_NO_THROW(item = deep->get("list")->getNonConst(1));
+ ASSERT_NO_THROW(item->setValue(3));
+ EXPECT_FALSE(deep->equals(*complex));
+ EXPECT_TRUE(shallow->equals(*complex));
+ ASSERT_NO_THROW(item = boost::const_pointer_cast<Element>(shallow->get("string")));
+ ASSERT_NO_THROW(item->setValue(std::string("FooBar")));
+ EXPECT_FALSE(shallow->equals(*complex));
+ EXPECT_TRUE(copied->equals(*complex));
+}
+
+// This test checks the isEquivalent function.
+TEST(Element, isEquivalent) {
+ // All are different but a is equivalent to b
+ string texta = "{ \"a\": 1, \"b\": [ ], \"c\": [ 1, 1, 2 ] }";
+ string textb = "{ \"b\": [ ], \"a\": 1, \"c\": [ 1, 2, 1 ] }";
+ string textc = "{ \"a\": 2, \"b\": [ ], \"c\": [ 1, 1, 2 ] }";
+ string textd = "{ \"a\": 1, \"c\": [ ], \"b\": [ 1, 1, 2 ] }";
+ string texte = "{ \"a\": 1, \"b\": [ ], \"c\": [ 1, 2, 2 ] }";
+
+ ElementPtr a = Element::fromJSON(texta);
+ ElementPtr b = Element::fromJSON(textb);
+ ElementPtr c = Element::fromJSON(textc);
+ ElementPtr d = Element::fromJSON(textd);
+ ElementPtr e = Element::fromJSON(texte);
+
+ EXPECT_TRUE(isEquivalent(a, b));
+ EXPECT_NE(a, b);
+ EXPECT_FALSE(isEquivalent(a, c));
+ EXPECT_FALSE(isEquivalent(a, d));
+ EXPECT_FALSE(isEquivalent(a, e));
+
+ // Verifies isEquivalent handles cycles
+ if (isc::util::unittests::runningOnValgrind()) {
+ ElementPtr l = Element::createList();
+ l->add(l);
+ EXPECT_THROW(isEquivalent(l, l), isc::BadValue);
+ }
+}
+
+
+// This test checks the pretty print function.
+TEST(Element, prettyPrint) {
+
+ // default step is 2, order is alphabetic, no \n at the end
+ string text = "{\n"
+ " \"boolean\": true,\n"
+ " \"empty-list\": [ ],\n"
+ " \"empty-map\": { },\n"
+ " \"integer\": 1,\n"
+ " \"list\": [ 1, 2, 3 ],\n"
+ " \"map\": {\n"
+ " \"item\": null\n"
+ " },\n"
+ " \"string\": \"foobar\"\n"
+ "}";
+ ElementPtr json = Element::fromJSON(text);
+ string pprinted = prettyPrint(json);
+ EXPECT_EQ(text, pprinted);
+}
+
// This test checks whether it is possible to ignore comments. It also checks
// that the comments are ignored only when told to.
TEST(Element, preprocessor) {
EXPECT_THROW(Element::fromJSON(dbl_head_comment), JSONError);
EXPECT_THROW(Element::fromJSON(dbl_mid_comment), JSONError);
EXPECT_THROW(Element::fromJSON(dbl_tail_comment), JSONError);
+
+ // For coverage
+ std::istringstream iss(no_comment);
+ EXPECT_TRUE(exp->equals(*Element::fromJSON(iss, true)));
}
TEST(Element, getPosition) {
class SimpleParserClassTest : public SimpleParser {
public:
- /// @brief Instantiation of getIntType for uint8_t
- ///
- /// @param scope specified parameter will be extracted from this scope
- /// @param name name of the parameter for error report
- /// @return an uint8_t value
- uint8_t getUint8(ConstElementPtr scope, const std::string& name) {
- return (getIntType<uint8_t>(scope, name));
- }
+
+ /// Make getUint8 public
+ using SimpleParser::getUint8;
/// @brief Instantiation of getAndConvert
///
libkea_dhcpsrv_la_SOURCES += alloc_engine_log.cc alloc_engine_log.h
libkea_dhcpsrv_la_SOURCES += base_host_data_source.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
-libkea_dhcpsrv_la_SOURCES += cfg_4o6.h
+libkea_dhcpsrv_la_SOURCES += cfg_4o6.cc cfg_4o6.h
libkea_dhcpsrv_la_SOURCES += cfg_db_access.cc cfg_db_access.h
libkea_dhcpsrv_la_SOURCES += cfg_duid.cc cfg_duid.h
libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h
-// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 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
/// @brief mask used for first/last address calculation in a IPv6 prefix
const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+/// @brief mask used for IPv6 prefix calculation
+const uint8_t revMask6[]= { 0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3, 0x1 };
+
+
/// @brief calculates the first IPv6 address in a IPv6 prefix
///
/// Note: This is a private function. Do not use it directly.
}
}
+int
+prefixLengthFromRange(const isc::asiolink::IOAddress& min,
+ const isc::asiolink::IOAddress& max) {
+ if (min.getFamily() != max.getFamily()) {
+ isc_throw(BadValue, "Both addresses have to be the same family");
+ }
+
+ if (max < min) {
+ isc_throw(BadValue, min.toText() << " must not be greater than "
+ << max.toText());
+ }
+
+ if (min.isV4()) {
+ // Get addresses as integers
+ uint32_t max_numeric = max.toUint32();
+ uint32_t min_numeric = min.toUint32();
+
+ // Get the exclusive or which must be one of the bit masks
+ uint32_t xor_numeric = max_numeric ^ min_numeric;
+ for (uint8_t prefix_len = 0; prefix_len <= 32; ++prefix_len) {
+ if (xor_numeric == bitMask4[prefix_len]) {
+ // Got it: the wanted value is also the index
+ return (static_cast<int>(prefix_len));
+ }
+ }
+
+ // If it was not found the range is not from a prefix / prefix_len
+ return (-1);
+ } else {
+ // Get addresses as 16 bytes
+ uint8_t min_packed[V6ADDRESS_LEN];
+ memcpy(min_packed, &min.toBytes()[0], 16);
+ uint8_t max_packed[V6ADDRESS_LEN];
+ memcpy(max_packed, &max.toBytes()[0], 16);
+
+ // Scan the exclusive or of addresses to find a difference
+ int candidate = 128;
+ bool zeroes = true;
+ for (uint8_t i = 0; i < 16; ++i) {
+ uint8_t xor_byte = min_packed[i] ^ max_packed[i];
+ if (zeroes) {
+ // Skipping zero bits searching for one bits
+ if (xor_byte == 0) {
+ continue;
+ }
+ // Found a one bit: note the fact
+ zeroes = false;
+ // Compare the exclusive or to masks
+ for (uint8_t j = 0; j < 8; ++j) {
+ if (xor_byte == revMask6[j]) {
+ // Got it the prefix length: note it
+ candidate = static_cast<int>((i * 8) + j);
+ }
+ }
+ if (candidate == 128) {
+ // Not found? The range is not from a prefix / prefix_len
+ return (-1);
+ }
+ } else {
+ // Checking that trailing bits are on bits
+ if (xor_byte == 0xff) {
+ continue;
+ }
+ // Not all ones is bad
+ return (-1);
+ }
+ }
+ return (candidate);
+ }
+}
+
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
if (delegated_len < pool_len) {
return (0);
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015,2017 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
uint64_t addrsInRange(const isc::asiolink::IOAddress& min,
const isc::asiolink::IOAddress& max);
+/// @brief Returns prefix length from the specified range (min - max).
+///
+/// This can be considered as log2(addrsInRange)
+///
+/// @throw BadValue if min and max do not define a prefix.
+///
+/// @param min the first address in range
+/// @param max the last address in range
+/// @return the prefix length or -1 if the range is not from a prefix
+int prefixLengthFromRange(const isc::asiolink::IOAddress& min,
+ const isc::asiolink::IOAddress& max);
+
/// @brief Returns number of available IPv6 prefixes in the specified prefix.
///
/// Note that if the answer is bigger than uint64_t can hold, it will return
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
#ifndef CFG_4OVER6_H
#define CFG_4OVER6_H
-#include <string>
#include <asiolink/io_address.h>
+#include <cc/cfg_to_element.h>
+#include <string>
namespace isc {
namespace dhcp {
///
/// DHCP4o6 is completely optional. If it is not enabled, this structure
/// does not contain any information.
-struct Cfg4o6 {
+struct Cfg4o6 : public isc::data::CfgToElement {
/// the default constructor.
///
enabled_ = true;
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// Specifies if 4o6 is enabled on this subnet.
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
#include <sstream>
+#include <vector>
+
+using namespace isc::data;
namespace isc {
namespace dhcp {
return (s.str());
}
-
+ElementPtr
+CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
+ ElementPtr result = Element::createMap();
+ // Code from DatabaseConnection::parse
+ if (dbaccess.empty()) {
+ return (result);
+ }
+ std::vector<std::string> tokens;
+ boost::split(tokens, dbaccess, boost::is_any_of(std::string("\t ")));
+ BOOST_FOREACH(std::string token, tokens) {
+ size_t pos = token.find("=");
+ if (pos != std::string::npos) {
+ std::string keyword = token.substr(0, pos);
+ std::string value = token.substr(pos + 1);
+ if ((keyword == "lfc-interval") ||
+ (keyword == "connect-timeout") ||
+ (keyword == "port")) {
+ // integer parameters
+ int64_t int_value;
+ try {
+ int_value = boost::lexical_cast<int64_t>(value);
+ result->set(keyword, Element::create(int_value));
+ } catch (...) {
+ isc_throw(ToElementError, "invalid DB access "
+ << "integer parameter: "
+ << keyword << "=" << value);
+ }
+ } else if ((keyword == "persist") ||
+ (keyword == "readonly")) {
+ if (value == "true") {
+ result->set(keyword, Element::create(true));
+ } else if (value == "false") {
+ result->set(keyword, Element::create(false));
+ } else {
+ isc_throw(ToElementError, "invalid DB access "
+ << "boolean parameter: "
+ << keyword << "=" << value);
+ }
+ } else if ((keyword == "type") ||
+ (keyword == "user") ||
+ (keyword == "password") ||
+ (keyword == "host") ||
+ (keyword == "name") ||
+ (keyword == "contact_points") ||
+ (keyword == "keyspace")) {
+ result->set(keyword, Element::create(value));
+ } else {
+ isc_throw(ToElementError, "unknown DB access parameter: "
+ << keyword << "=" << value);
+ }
+ } else {
+ isc_throw(ToElementError, "Cannot unparse " << token
+ << ", expected format is name=value");
+ }
+ }
+ return (result);
+}
} // end of isc::dhcp namespace
} // end of isc namespace
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
#ifndef CFG_DBACCESS_H
#define CFG_DBACCESS_H
+#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <string>
/// according to the configuration specified.
void createManagers() const;
-private:
+ /// @brief Unparse an access string
+ ///
+ /// @param dbaccess the database access string
+ /// @return a pointer to configuration
+ static
+ isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
+
+protected:
/// @brief Returns lease or host database access string.
///
/// @brief A pointer to the const @c CfgDbAccess.
typedef boost::shared_ptr<const CfgDbAccess> ConstCfgDbAccessPtr;
+/// @brief utility class for unparsing
+struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
+ /// @brief Constructor
+ CfgLeaseDbAccess(const CfgDbAccess& super) : CfgDbAccess(super) { }
+
+ /// @brief Unparse
+ ///
+ /// @ref CfgToElement::toElement
+ ///
+ /// @result a pointer to a configuration
+ virtual isc::data::ElementPtr toElement() const {
+ return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
+ }
+};
+
+struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
+ /// @brief Constructor
+ CfgHostDbAccess(const CfgDbAccess& super) : CfgDbAccess(super) { }
+
+ /// @brief Unparse
+ ///
+ /// @ref CfgToElement::toElement
+ ///
+ /// @result a pointer to a configuration
+ virtual isc::data::ElementPtr toElement() const {
+ return (CfgDbAccess::toElementDbAccessString(host_db_access_));
+ }
+};
+
}
}
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <util/encode/hex.h>
#include <util/strutil.h>
#include <iostream>
+#include <string>
+#include <string.h>
using namespace isc;
+using namespace isc::data;
using namespace isc::util::encode;
using namespace isc::util::str;
return (factory.get());
}
+ElementPtr
+CfgDUID::toElement() const {
+ ElementPtr result = Element::createMap();
+ // The type item is required
+ std::string duid_type = "LLT";
+ switch (type_) {
+ case DUID::DUID_LLT:
+ break;
+ case DUID::DUID_EN:
+ duid_type = "EN";
+ break;
+ case DUID::DUID_LL:
+ duid_type = "LL";
+ break;
+ default:
+ isc_throw(ToElementError, "invalid DUID type: " << getType());
+ break;
+ }
+ result->set("type", Element::create(duid_type));
+ // Set the identifier
+ result->set("identifier",
+ Element::create(util::encode::encodeHex(identifier_)));
+ // Set the hardware type
+ result->set("htype", Element::create(htype_));
+ // Set the time
+ result->set("time", Element::create(static_cast<long long>(time_)));
+ // Set the enterprise id
+ result->set("enterprise-id",
+ Element::create(static_cast<long long>(enterprise_id_)));
+ // Set the persistence flag
+ result->set("persist", Element::create(persist_));
+ return (result);
+}
}
}
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#define CFG_DUID_H
#include <dhcp/duid.h>
+#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include <vector>
/// generate. It also allows for overriding entire default DUID or parts of
/// it via configuration file. This class holds the DUID configuration
/// specified in the server configuration file.
-class CfgDUID {
+class CfgDUID : public isc::data::CfgToElement {
public:
/// @brief Constructor.
/// @return Pointer to an instance of new DUID.
DuidPtr create(const std::string& duid_file_path) const;
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief DUID type.
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <exceptions/exceptions.h>
#include <limits>
+using namespace isc::data;
+
namespace isc {
namespace dhcp {
}
}
+ElementPtr
+CfgExpiration::toElement() const {
+ ElementPtr result = Element::createMap();
+ // Set reclaim-timer-wait-time
+ result->set("reclaim-timer-wait-time",
+ Element::create(static_cast<long long>
+ (reclaim_timer_wait_time_)));
+ // Set flush-reclaimed-timer-wait-time
+ result->set("flush-reclaimed-timer-wait-time",
+ Element::create(static_cast<long long>
+ (flush_reclaimed_timer_wait_time_)));
+ // Set hold-reclaimed-time
+ result->set("hold-reclaimed-time",
+ Element::create(static_cast<long long>
+ (hold_reclaimed_time_)));
+ // Set max-reclaim-leases
+ result->set("max-reclaim-leases",
+ Element::create(static_cast<long long>
+ (max_reclaim_leases_)));
+ // Set max-reclaim-time
+ result->set("max-reclaim-time",
+ Element::create(static_cast<long long>
+ (max_reclaim_time_)));
+ // Set unwarned-reclaim-cycles
+ result->set("unwarned-reclaim-cycles",
+ Element::create(static_cast<long long>
+ (unwarned_reclaim_cycles_)));
+ return (result);
+}
+
}
}
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#define CFG_EXPIRATION_H
#include <asiolink/interval_timer.h>
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/timer_mgr.h>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
/// The @c CfgExpiration class provides a collection of accessors and
/// modifiers to manage the data. Each accessor checks if the given value
/// is in range allowed for this value.
-class CfgExpiration {
+class CfgExpiration : public isc::data::CfgToElement {
public:
/// @name Default values.
void (Instance::*delete_fun)(const uint32_t),
Instance* instance_ptr) const;
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Checks if the value being set by one of the modifiers is
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
#include <exceptions/exceptions.h>
#include <dhcpsrv/cfg_host_operations.h>
#include <algorithm>
+#include <string>
+
+using namespace isc::data;
namespace isc {
namespace dhcp {
identifier_types_.clear();
}
+ElementPtr
+CfgHostOperations::toElement() const {
+ ElementPtr result = Element::createList();
+ for (IdentifierTypes::const_iterator id = identifier_types_.begin();
+ id != identifier_types_.end(); ++id) {
+ const std::string& name = Host::getIdentifierName(*id);
+ result->add(Element::create(name));
+ }
+ return (result);
+}
+
}
}
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
#ifndef CFG_HOST_OPERATIONS_H
#define CFG_HOST_OPERATIONS_H
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/host.h>
#include <boost/shared_ptr.hpp>
#include <list>
/// An administrator selects which identifiers the server should
/// use and in which order to search for host reservations to
/// optimize performance of the server.
-class CfgHostOperations {
+class CfgHostOperations : public isc::data::CfgToElement {
public:
/// @brief Type of the container holding ordered list of identifiers.
/// @brief Removes existing identifier types.
void clearIdentifierTypes();
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Holds ordered collection of identifiers to be used by the
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <algorithm>
using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
useSocketType(family, textToSocketType(socket_type_name));
}
+ElementPtr
+CfgIface::toElement() const {
+ ElementPtr result = Element::createMap();
+
+ // Set interfaces
+ ElementPtr ifaces = Element::createList();
+ if (wildcard_used_) {
+ ifaces->add(Element::create(std::string(ALL_IFACES_KEYWORD)));
+ }
+ for (IfaceSet::const_iterator iface = iface_set_.cbegin();
+ iface != iface_set_.cend(); ++iface) {
+ ifaces->add(Element::create(*iface));
+ }
+ for (ExplicitAddressMap::const_iterator address = address_map_.cbegin();
+ address != address_map_.cend(); ++address) {
+ std::string spec = address->first + "/" + address->second.toText();
+ ifaces->add(Element::create(spec));
+ }
+ result->set("interfaces", ifaces);
+
+ // Set dhcp-socket-type (no default because it is DHCPv4 specific)
+ // @todo emit raw if and only if DHCPv4
+ if (socket_type_ != SOCKET_RAW) {
+ result->set("dhcp-socket-type", Element::create(std::string("udp")));
+ }
+
+ return (result);
+}
+
} // end of isc::dhcp namespace
} // end of isc namespace
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
+#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <map>
#include <set>
/// to which it is bound. It is allowed to select multiple addresses on the
/// particular interface explicitly, e.g. "eth0/192.168.8.1",
/// "eth0/192.168.8.2".
-class CfgIface {
+class CfgIface : public isc::data::CfgToElement {
public:
/// @brief Socket type used by the DHCPv4 server.
return (!equals(other));
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Checks if multiple IPv4 addresses has been activated on any
#include <exceptions/exceptions.h>
#include <dhcp/hwaddr.h>
+using namespace isc::data;
+
+namespace {
+
+using namespace isc::dhcp;
+
+struct {
+ const char * name;
+ uint32_t type;
+} sources[] = {
+ { "any", HWAddr::HWADDR_SOURCE_ANY },
+ { "raw", HWAddr::HWADDR_SOURCE_RAW },
+ { "duid", HWAddr::HWADDR_SOURCE_DUID },
+ { "ipv6-link-local", HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL },
+ { "client-link-addr-option", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+ { "rfc6939", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
+ { "remote-id", HWAddr::HWADDR_SOURCE_REMOTE_ID },
+ { "rfc4649", HWAddr::HWADDR_SOURCE_REMOTE_ID },
+ { "subscriber-id", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
+ { "rfc4580", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
+ { "docsis-cmts", HWAddr::HWADDR_SOURCE_DOCSIS_CMTS },
+ { "docsis-modem", HWAddr::HWADDR_SOURCE_DOCSIS_MODEM }
+};
+
+};
+
namespace isc {
namespace dhcp {
}
uint32_t CfgMACSource::MACSourceFromText(const std::string& name) {
-
- struct {
- const char * name;
- uint32_t type;
- } sources[] = {
- { "any", HWAddr::HWADDR_SOURCE_ANY },
- { "raw", HWAddr::HWADDR_SOURCE_RAW },
- { "duid", HWAddr::HWADDR_SOURCE_DUID },
- { "ipv6-link-local", HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL },
- { "client-link-addr-option", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
- { "rfc6939", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
- { "remote-id", HWAddr::HWADDR_SOURCE_REMOTE_ID },
- { "rfc4649", HWAddr::HWADDR_SOURCE_REMOTE_ID },
- { "subscriber-id", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
- { "rfc4580", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID },
- { "docsis-cmts", HWAddr::HWADDR_SOURCE_DOCSIS_CMTS },
- { "docsis-modem", HWAddr::HWADDR_SOURCE_DOCSIS_MODEM }
- };
-
- for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
+ for (unsigned i = 0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
if (name.compare(sources[i].name) == 0) {
return (sources[i].type);
}
for (CfgMACSources::const_iterator it = mac_sources_.begin();
it != mac_sources_.end(); ++it) {
if (*it == source) {
- isc_throw(InvalidParameter, "mac-source paramter " << source
+ isc_throw(InvalidParameter, "mac-source parameter " << source
<< "' specified twice.");
}
}
mac_sources_.push_back(source);
}
+ElementPtr CfgMACSource::toElement() const {
+ ElementPtr result = Element::createList();
+ for (CfgMACSources::const_iterator source = mac_sources_.cbegin();
+ source != mac_sources_.cend(); ++source) {
+ std::string name;
+ for (unsigned i = 0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
+ if (sources[i].type == *source) {
+ name = sources[i].name;
+ break;
+ }
+ }
+ if (name.empty()) {
+ isc_throw(ToElementError, "invalid MAC source: " << *source);
+ }
+ result->add(Element::create(name));
+ }
+ return (result);
+}
+
};
};
#ifndef CFG_MAC_SOURCE_H
#define CFG_MAC_SOURCE_H
+#include <cc/cfg_to_element.h>
#include <stdint.h>
#include <vector>
#include <string>
///
/// It's a simple wrapper around a vector of uint32_t, with each entry
/// holding one MAC source.
-class CfgMACSource {
+class CfgMACSource : public isc::data::CfgToElement {
public:
/// @brief Default constructor.
mac_sources_.clear();
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
protected:
/// @brief Actual MAC sources storage
CfgMACSources mac_sources_;
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcp/option_space.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcp/dhcp6.h>
+#include <util/encode/hex.h>
#include <string>
+#include <sstream>
+#include <vector>
+
+using namespace isc::data;
namespace isc {
namespace dhcp {
return (vendor_options_.getItems(vendor_id));
}
+ElementPtr
+CfgOption::toElement() const {
+ // option-data value is a list of maps
+ ElementPtr result = Element::createList();
+ // Iterate first on options using space names
+ const std::list<std::string>& names = options_.getOptionSpaceNames();
+ for (std::list<std::string>::const_iterator name = names.begin();
+ name != names.end(); ++name) {
+ OptionContainerPtr opts = getAll(*name);
+ for (OptionContainer::const_iterator opt = opts->begin();
+ opt != opts->end(); ++opt) {
+ // Get and fill the map for this option
+ ElementPtr map = Element::createMap();
+ // First set space from parent iterator
+ map->set("space", Element::create(*name));
+ // Set the code
+ uint16_t code = opt->option_->getType();
+ map->set("code", Element::create(code));
+ // Set the name (always for standard options else when asked for)
+ OptionDefinitionPtr def = LibDHCP::getOptionDef(*name, code);
+ if (!def) {
+ def = LibDHCP::getRuntimeOptionDef(*name, code);
+ }
+ if (def) {
+ map->set("name", Element::create(def->getName()));
+ }
+ // Set the data item
+ if (!opt->formatted_value_.empty()) {
+ map->set("csv-format", Element::create(true));
+ map->set("data", Element::create(opt->formatted_value_));
+ } else {
+ map->set("csv-format", Element::create(false));
+ std::vector<uint8_t> bin = opt->option_->toBinary();
+ std::string repr = util::encode::encodeHex(bin);
+ map->set("data", Element::create(repr));
+ }
+ // Push on the list
+ result->add(map);
+ }
+ }
+ // Iterate first on vendor_options using vendor ids
+ const std::list<uint32_t>& ids = vendor_options_.getOptionSpaceNames();
+ for (std::list<uint32_t>::const_iterator id = ids.begin();
+ id != ids.end(); ++id) {
+ OptionContainerPtr opts = getAll(*id);
+ for (OptionContainer::const_iterator opt = opts->begin();
+ opt != opts->end(); ++opt) {
+ // Get and fill the map for this option
+ ElementPtr map = Element::createMap();
+ // First set space from parent iterator
+ std::ostringstream oss;
+ oss << "vendor-" << *id;
+ map->set("space", Element::create(oss.str()));
+ // Set the code
+ uint16_t code = opt->option_->getType();
+ map->set("code", Element::create(code));
+ // Set the name
+ Option::Universe universe = opt->option_->getUniverse();
+ OptionDefinitionPtr def =
+ LibDHCP::getVendorOptionDef(universe, *id, code);
+ if (!def) {
+ // vendor-XXX space is in oss
+ def = LibDHCP::getRuntimeOptionDef(oss.str(), code);
+ }
+ if (def) {
+ map->set("name", Element::create(def->getName()));
+ }
+ // Set the data item
+ if (!opt->formatted_value_.empty()) {
+ map->set("csv-format", Element::create(true));
+ map->set("data", Element::create(opt->formatted_value_));
+ } else {
+ map->set("csv-format", Element::create(false));
+ std::vector<uint8_t> bin = opt->option_->toBinary();
+ std::string repr = util::encode::encodeHex(bin);
+ map->set("data", Element::create(repr));
+ }
+ // Push on the list
+ result->add(map);
+ }
+ }
+ return (result);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcp/option.h>
#include <dhcp/option_space_container.h>
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/key_from_key.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
/// options is useful when the client requests stateless configuration from
/// the DHCP server and no subnet is selected for this client. This client
/// will only receive global options.
-class CfgOption {
+class CfgOption : public isc::data::CfgToElement {
public:
/// @brief default constructor
/// @return List comprising option space names for vendor options.
std::list<std::string> getVendorIdsSpaceNames() const;
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Appends encapsulated options to the options in an option space.
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <config.h>
#include <dhcp/libdhcp++.h>
+#include <dhcp/option_data_types.h>
#include <dhcp/option_definition.h>
#include <dhcp/option_space.h>
#include <dhcpsrv/cfg_option_def.h>
+#include <sstream>
+
+using namespace isc::data;
namespace isc {
namespace dhcp {
return (OptionDefinitionPtr());
}
+ElementPtr
+CfgOptionDef::toElement() const {
+ // option-defs value is a list of maps
+ ElementPtr result = Element::createList();
+ // Iterate through the container by names and definitions
+ const std::list<std::string>& names =
+ option_definitions_.getOptionSpaceNames();
+ for (std::list<std::string>::const_iterator name = names.begin();
+ name != names.end(); ++name) {
+ OptionDefContainerPtr defs = getAll(*name);
+ for (OptionDefContainer::const_iterator def = defs->begin();
+ def != defs->end(); ++def) {
+ // Get and fill the map for this definition
+ ElementPtr map = Element::createMap();
+ // First set space from parent iterator
+ map->set("space", Element::create(*name));
+ // Set required items: name, code and type
+ map->set("name", Element::create((*def)->getName()));
+ map->set("code", Element::create((*def)->getCode()));
+ std::string data_type =
+ OptionDataTypeUtil::getDataTypeName((*def)->getType());
+ map->set("type", Element::create(data_type));
+ // Set the array type
+ bool array_type = (*def)->getArrayType();
+ map->set("array", Element::create(array_type));
+ // Set the encapsulate space
+ std::string encapsulates = (*def)->getEncapsulatedSpace();
+ map->set("encapsulate", Element::create(encapsulates));
+ // Set the record field types
+ OptionDefinition::RecordFieldsCollection fields =
+ (*def)->getRecordFields();
+ if (!fields.empty()) {
+ std::ostringstream oss;
+ for (OptionDefinition::RecordFieldsCollection::const_iterator
+ field = fields.begin();
+ field != fields.end(); ++field) {
+ if (field != fields.begin()) {
+ oss << ", ";
+ }
+ oss << OptionDataTypeUtil::getDataTypeName(*field);
+ }
+ map->set("record-types", Element::create(oss.str()));
+ } else {
+ map->set("record-types", Element::create(std::string()));
+ }
+ // Push on the list
+ result->add(map);
+ }
+ }
+ return (result);
+}
+
+
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <dhcp/option_definition.h>
#include <dhcp/option_space_container.h>
+#include <cc/cfg_to_element.h>
#include <string>
namespace isc {
/// following names: "dhcp4" and "dhcp6" are reserved, though. They are
/// names of option spaces used for standard top-level DHCPv4 and DHCPv6
/// options respectively.
-class CfgOptionDef {
+class CfgOptionDef : public isc::data::CfgToElement {
public:
/// @brief Copies this configuration to a new configuration.
return (option_definitions_);
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief A collection of option definitions.
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <dhcp/dhcp6.h>
#include <dhcpsrv/cfg_rsoo.h>
+#include <boost/lexical_cast.hpp>
+
+using namespace isc::data;
namespace isc {
namespace dhcp {
}
}
+ElementPtr
+CfgRSOO::toElement() const {
+ ElementPtr result = Element::createList();
+ // We can use LibDHCP::getOptionDef(DHCP6_OPTION_SPACE, *opt) too...
+ for (std::set<uint16_t>::const_iterator opt = rsoo_options_.cbegin();
+ opt != rsoo_options_.cend(); ++opt) {
+ const std::string& code = boost::lexical_cast<std::string>(*opt);
+ result->add(Element::create(code));
+ }
+ return (result);
+}
}
}
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#ifndef CFG_RSOO_H
#define CFG_RSOO_H
+#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include <set>
/// 65 is officially RSSO-enabled. The list may be extended in the future
/// and this class allows for specifying any future RSOO-enabled options.
/// The administrator may also use existing options as RSOO-enabled.
-class CfgRSOO {
+class CfgRSOO : public isc::data::CfgToElement {
public:
/// @brief Constructor.
/// @param code option to be enabled in RSOO
void enable(const uint16_t code);
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Contains a set of options that are allowed in RSOO option
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcpsrv/addr_utilities.h>
#include <asiolink/io_address.h>
#include <stats/stats_mgr.h>
+#include <sstream>
using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
}
}
+ElementPtr
+CfgSubnets4::toElement() const {
+ ElementPtr result = Element::createList();
+ // Iterate subnets
+ for (Subnet4Collection::const_iterator subnet = subnets_.cbegin();
+ subnet != subnets_.cend(); ++subnet) {
+ // Prepare the map
+ ElementPtr map = Element::createMap();
+ // Set subnet id
+ SubnetID id = (*subnet)->getID();
+ map->set("id", Element::create(static_cast<long long>(id)));
+ // Set relay info
+ const Subnet::RelayInfo& relay_info = (*subnet)->getRelayInfo();
+ ElementPtr relay = Element::createMap();
+ relay->set("ip-address", Element::create(relay_info.addr_.toText()));
+ map->set("relay", relay);
+ // Set subnet
+ map->set("subnet", Element::create((*subnet)->toText()));
+ // Set interface
+ const std::string& iface = (*subnet)->getIface();
+ map->set("interface", Element::create(iface));
+ // Set renew-timer
+ map->set("renew-timer",
+ Element::create(static_cast<long long>
+ ((*subnet)->getT1().get())));
+ // Set rebind-timer
+ map->set("rebind-timer",
+ Element::create(static_cast<long long>
+ ((*subnet)->getT2().get())));
+ // Set valid-lifetime
+ map->set("valid-lifetime",
+ Element::create(static_cast<long long>
+ ((*subnet)->getValid().get())));
+ // Set pools
+ const PoolCollection& pools = (*subnet)->getPools(Lease::TYPE_V4);
+ ElementPtr pool_list = Element::createList();
+ for (PoolCollection::const_iterator pool = pools.cbegin();
+ pool != pools.cend(); ++pool) {
+ // Prepare the map for a pool
+ ElementPtr pool_map = Element::createMap();
+ // Set pool
+ const IOAddress& first = (*pool)->getFirstAddress();
+ const IOAddress& last = (*pool)->getLastAddress();
+ std::string range = first.toText() + "-" + last.toText();
+ // Try to output a prefix (vs a range)
+ int prefix_len = prefixLengthFromRange(first, last);
+ if (prefix_len >= 0) {
+ std::ostringstream oss;
+ oss << first.toText() << "/" << prefix_len;
+ range = oss.str();
+ }
+ pool_map->set("pool", Element::create(range));
+ // Set user-context
+ ConstElementPtr context = (*pool)->getContext();
+ if (!isNull(context)) {
+ pool_map->set("user-context", context);
+ }
+ // Set pool options
+ ConstCfgOptionPtr opts = (*pool)->getCfgOption();
+ pool_map->set("option-data", opts->toElement());
+ // Push on the pool list
+ pool_list->add(pool_map);
+ }
+ map->set("pools", pool_list);
+ // Set host reservation-mode
+ Subnet::HRMode hrmode = (*subnet)->getHostReservationMode();
+ std::string mode;
+ switch (hrmode) {
+ case Subnet::HR_DISABLED:
+ mode = "disabled";
+ break;
+ case Subnet::HR_OUT_OF_POOL:
+ mode = "out-of-pool";
+ break;
+ case Subnet::HR_ALL:
+ mode = "all";
+ break;
+ default:
+ isc_throw(ToElementError,
+ "invalid host reservation mode: " << hrmode);
+ }
+ map->set("reservation-mode", Element::create(mode));
+ // Set match-client-id
+ map->set("match-client-id",
+ Element::create((*subnet)->getMatchClientId()));
+ // Set next-server
+ map->set("next-server",
+ Element::create((*subnet)->getSiaddr().toText()));
+ // Set DHCP4o6
+ const Cfg4o6& d4o6 = (*subnet)->get4o6();
+ merge(map, d4o6.toElement());
+ // Set client-class
+ const ClientClasses& cclasses = (*subnet)->getClientClasses();
+ if (cclasses.size() > 1) {
+ isc_throw(ToElementError, "client-classes has too many items: "
+ << cclasses.size());
+ } else if (!cclasses.empty()) {
+ map->set("client-class", Element::create(*cclasses.cbegin()));
+ }
+ // Set options
+ ConstCfgOptionPtr opts = (*subnet)->getCfgOption();
+ map->set("option-data", opts->toElement());
+ // Not supported: interface-id
+ // Not supported: rapid-commit
+ // Push on the list
+ result->add(map);
+ }
+ return (result);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#define CFG_SUBNETS4_H
#include <asiolink/io_address.h>
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_selector.h>
#include <boost/shared_ptr.hpp>
///
/// See @c CfgSubnets4::selectSubnet documentation for more details on how the
/// subnet is selected for the client.
-class CfgSubnets4 {
+class CfgSubnets4 : public isc::data::CfgToElement {
public:
/// @brief Adds new subnet to the configuration.
/// configuration and also subnet-ids may change.
void removeStatistics();
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Checks that the IPv4 subnet with the given id already exists.
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/subnet_id.h>
+#include <dhcpsrv/addr_utilities.h>
#include <stats/stats_mgr.h>
+#include <string.h>
+#include <sstream>
using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
}
}
+ElementPtr
+CfgSubnets6::toElement() const {
+ ElementPtr result = Element::createList();
+ // Iterate subnets
+ for (Subnet6Collection::const_iterator subnet = subnets_.cbegin();
+ subnet != subnets_.cend(); ++subnet) {
+ // Prepare the map
+ ElementPtr map = Element::createMap();
+ // Set subnet id
+ SubnetID id = (*subnet)->getID();
+ map->set("id", Element::create(static_cast<long long>(id)));
+ // Set relay info
+ const Subnet::RelayInfo& relay_info = (*subnet)->getRelayInfo();
+ ElementPtr relay = Element::createMap();
+ relay->set("ip-address", Element::create(relay_info.addr_.toText()));
+ map->set("relay", relay);
+ // Set subnet
+ map->set("subnet", Element::create((*subnet)->toText()));
+ // Set interface
+ const std::string& iface = (*subnet)->getIface();
+ map->set("interface", Element::create(iface));
+ // Set interface-id
+ const OptionPtr& ifaceid = (*subnet)->getInterfaceId();
+ if (ifaceid) {
+ std::vector<uint8_t> bin = ifaceid->getData();
+ std::string ifid;
+ ifid.resize(bin.size());
+ if (!bin.empty()) {
+ std::memcpy(&ifid[0], &bin[0], bin.size());
+ }
+ map->set("interface-id", Element::create(ifid));
+ } else {
+ map->set("interface-id", Element::create(std::string()));
+ }
+ // Set renew-timer
+ map->set("renew-timer",
+ Element::create(static_cast<long long>
+ ((*subnet)->getT1().get())));
+ // Set rebind-timer
+ map->set("rebind-timer",
+ Element::create(static_cast<long long>
+ ((*subnet)->getT2().get())));
+ // Set preferred-lifetime
+ map->set("preferred-lifetime",
+ Element::create(static_cast<long long>
+ ((*subnet)->getPreferred().get())));
+ // Set valid-lifetime
+ map->set("valid-lifetime",
+ Element::create(static_cast<long long>
+ ((*subnet)->getValid().get())));
+ // Set rapid-commit
+ bool rapid_commit = (*subnet)->getRapidCommit();
+ map->set("rapid-commit", Element::create(rapid_commit));
+ // Set pools
+ const PoolCollection& pools = (*subnet)->getPools(Lease::TYPE_NA);
+ ElementPtr pool_list = Element::createList();
+ for (PoolCollection::const_iterator pool = pools.cbegin();
+ pool != pools.cend(); ++pool) {
+ // Prepare the map for a pool
+ ElementPtr pool_map = Element::createMap();
+ // Set pool
+ const IOAddress& first = (*pool)->getFirstAddress();
+ const IOAddress& last = (*pool)->getLastAddress();
+ std::string range = first.toText() + "-" + last.toText();
+ // Try to output a prefix (vs a range)
+ int prefix_len = prefixLengthFromRange(first, last);
+ if (prefix_len >= 0) {
+ std::ostringstream oss;
+ oss << first.toText() << "/" << prefix_len;
+ range = oss.str();
+ }
+ pool_map->set("pool", Element::create(range));
+ // Set user-context
+ ConstElementPtr context = (*pool)->getContext();
+ if (!isNull(context)) {
+ pool_map->set("user-context", context);
+ }
+ // Set pool options
+ ConstCfgOptionPtr opts = (*pool)->getCfgOption();
+ pool_map->set("option-data", opts->toElement());
+ // Push on the pool list
+ pool_list->add(pool_map);
+ }
+ map->set("pools", pool_list);
+ // Set pd-pools
+ const PoolCollection& pdpools = (*subnet)->getPools(Lease::TYPE_PD);
+ ElementPtr pdpool_list = Element::createList();
+ for (PoolCollection::const_iterator pool = pdpools.cbegin();
+ pool != pdpools.cend(); ++pool) {
+ // Get it as a Pool6
+ const Pool6* pdpool = dynamic_cast<Pool6*>(pool->get());
+ if (!pdpool) {
+ isc_throw(ToElementError, "invalid pd-pool pointer");
+ }
+ // Prepare the map for a pd-pool
+ ElementPtr pool_map = Element::createMap();
+ // Set prefix
+ const IOAddress& prefix = pdpool->getFirstAddress();
+ pool_map->set("prefix", Element::create(prefix.toText()));
+ // Set prefix-len (get it from min - max)
+ const IOAddress& last = pdpool->getLastAddress();
+ int prefix_len = prefixLengthFromRange(prefix, last);
+ if (prefix_len < 0) {
+ // The pool is bad: give up
+ isc_throw(ToElementError, "invalid prefix range "
+ << prefix.toText() << "-" << last.toText());
+ }
+ pool_map->set("prefix-len", Element::create(prefix_len));
+ // Set delegated-len
+ uint8_t len = pdpool->getLength();
+ pool_map->set("delegated-len",
+ Element::create(static_cast<int>(len)));
+ // Set excluded prefix
+ const Option6PDExcludePtr& xopt =
+ pdpool->getPrefixExcludeOption();
+ if (xopt) {
+ const IOAddress& xprefix =
+ xopt->getExcludedPrefix(prefix, len);
+ pool_map->set("excluded-prefix",
+ Element::create(xprefix.toText()));
+ uint8_t xlen = xopt->getExcludedPrefixLength();
+ pool_map->set("excluded-prefix-len",
+ Element::create(static_cast<int>(xlen)));
+ } else {
+ pool_map->set("excluded-prefix",
+ Element::create(std::string("::")));
+ pool_map->set("excluded-prefix-len", Element::create(0));
+ }
+ // Set user-context
+ ConstElementPtr context = pdpool->getContext();
+ if (!isNull(context)) {
+ pool_map->set("user-context", context);
+ }
+ // Set pool options
+ ConstCfgOptionPtr opts = pdpool->getCfgOption();
+ pool_map->set("option-data", opts->toElement());
+ // Push on the pool list
+ pdpool_list->add(pool_map);
+ }
+ map->set("pd-pools", pdpool_list);
+ // Set host reservation-mode
+ Subnet::HRMode hrmode = (*subnet)->getHostReservationMode();
+ std::string mode;
+ switch (hrmode) {
+ case Subnet::HR_DISABLED:
+ mode = "disabled";
+ break;
+ case Subnet::HR_OUT_OF_POOL:
+ mode = "out-of-pool";
+ break;
+ case Subnet::HR_ALL:
+ mode = "all";
+ break;
+ default:
+ isc_throw(ToElementError,
+ "invalid host reservation mode: " << hrmode);
+ }
+ map->set("reservation-mode", Element::create(mode));
+ // Set client-class
+ const ClientClasses& cclasses = (*subnet)->getClientClasses();
+ if (cclasses.size() > 1) {
+ isc_throw(ToElementError, "client-classes has too many items: "
+ << cclasses.size());
+ } else if (!cclasses.empty()) {
+ map->set("client-class", Element::create(*cclasses.cbegin()));
+ }
+ // Set options
+ ConstCfgOptionPtr opts = (*subnet)->getCfgOption();
+ map->set("option-data", opts->toElement());
+ // Push on the list
+ result->add(map);
+ }
+ return (result);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_selector.h>
#include <util/optional_value.h>
///
/// See @c CfgSubnets6::selectSubnet documentation for more details on how the subnet
/// is selected for the client.
-class CfgSubnets6 {
+class CfgSubnets6 : public isc::data::CfgToElement {
public:
/// @brief Adds new subnet to the configuration.
/// configuration and also subnet-ids may change.
void removeStatistics();
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Selects a subnet using the interface name.
}
CfgMgr::CfgMgr()
- : datadir_(DHCP_DATA_DIR), d2_client_mgr_(), verbose_mode_(false) {
+ : datadir_(DHCP_DATA_DIR), d2_client_mgr_(),
+ verbose_mode_(false), family_(AF_INET) {
// DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
// Note: the definition of DHCP_DATA_DIR needs to include quotation marks
// See AM_CPPFLAGS definition in Makefile.am
return (default_logger_name_);
}
+ /// @brief Sets address family (AF_INET or AF_INET6)
+ void setFamily(uint16_t family) {
+ family_ = family == AF_INET ? AF_INET : AF_INET6;
+ }
+
+ /// @brief Returns address family.
+ uint16_t getFamily() const {
+ return (family_);
+ }
+
//@}
protected:
/// @brief Default logger name.
std::string default_logger_name_;
+
+ /// @brief Address family.
+ uint16_t family_;
};
} // namespace isc::dhcp
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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 "client_class_def.h"
+#include <dhcpsrv/client_class_def.h>
#include <boost/foreach.hpp>
+using namespace isc::data;
+
namespace isc {
namespace dhcp {
match_expr_ = match_expr;
}
+std::string
+ClientClassDef::getTest() const {
+ return (test_);
+}
+
+void
+ClientClassDef::setTest(const std::string& test) {
+ test_ = test;
+}
+
const CfgOptionPtr&
ClientClassDef::getCfgOption() const {
return (cfg_option_);
(filename_ == other.filename_));
}
+ElementPtr
+ClientClassDef:: toElement() const {
+ ElementPtr result = Element::createMap();
+ // Set name
+ result->set("name", Element::create(name_));
+ // Set original match expression
+ result->set("test", Element::create(test_));
+ // Set option-data
+ result->set("option-data", cfg_option_->toElement());
+ // Set next-server
+ result->set("next-server", Element::create(next_server_.toText()));
+ // Set server-hostname
+ result->set("server-hostname", Element::create(sname_));
+ // Set boot-file-name
+ result->set("boot-file-name", Element::create(filename_));
+ return (result);
+}
+
std::ostream& operator<<(std::ostream& os, const ClientClassDef& x) {
os << "ClientClassDef:" << x.getName();
return (os);
void
ClientClassDictionary::addClass(const std::string& name,
const ExpressionPtr& match_expr,
+ const std::string& test,
const CfgOptionPtr& cfg_option,
asiolink::IOAddress next_server,
const std::string& sname,
const std::string& filename) {
ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
+ cclass->setTest(test);
cclass->setNextServer(next_server);
cclass->setSname(sname);
cclass->setFilename(filename);
return (true);
}
+ElementPtr
+ClientClassDictionary::toElement() const {
+ ElementPtr result = Element::createList();
+ // Iterate on the map
+ for (ClientClassDefMap::iterator this_class = classes_->begin();
+ this_class != classes_->end(); ++this_class) {
+ result->add(this_class->second->toElement());
+ }
+ return (result);
+}
} // namespace isc::dhcp
} // namespace isc
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
#ifndef CLIENT_CLASS_DEF_H
#define CLIENT_CLASS_DEF_H
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/cfg_option.h>
#include <eval/token.h>
#include <exceptions/exceptions.h>
};
/// @brief Embodies a single client class definition
-class ClientClassDef {
+class ClientClassDef : public isc::data::CfgToElement {
public:
/// @brief Constructor
///
/// @param match_expr the expression to assign the class
void setMatchExpr(const ExpressionPtr& match_expr);
+ /// @brief Fetches the class's original match expression
+ std::string getTest() const;
+
+ /// @brief Sets the class's original match expression
+ ///
+ /// @param test the original expression to assign the class
+ void setTest(const std::string& test);
+
/// @brief Fetches the class's option collection
const CfgOptionPtr& getCfgOption() const;
return (filename_);
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Unique text identifier by which this class is known.
std::string name_;
/// this class.
ExpressionPtr match_expr_;
+ /// @brief The original expression which determines membership in
+ /// this class.
+ std::string test_;
+
/// @brief The option data configuration for this class
CfgOptionPtr cfg_option_;
typedef std::pair<std::string, ClientClassDefPtr> ClientClassMapPair;
/// @brief Maintains a list of ClientClassDef's
-class ClientClassDictionary {
+class ClientClassDictionary : public isc::data::CfgToElement {
public:
/// @brief Constructor
///
/// @param name Name to assign to this class
/// @param match_expr Expression the class will use to determine membership
+ /// @param test Original version of match_expr
/// @param options Collection of options members should be given
/// @param next_server next-server value for this class (optional)
/// @param sname server-name value for this class (optional)
/// dictionary. See @ref dhcp::ClientClassDef::ClientClassDef() for
/// others.
void addClass(const std::string& name, const ExpressionPtr& match_expr,
- const CfgOptionPtr& options,
+ const std::string& test, const CfgOptionPtr& options,
asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
const std::string& sname = std::string(),
const std::string& filename = std::string());
return (!equals(other));
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Map of the class definitions
-// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2017 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
#include <string>
using namespace std;
+using namespace isc::asiolink;
+using namespace isc::data;
namespace isc {
namespace dhcp {
return (stream.str());
}
+ElementPtr
+D2ClientConfig::toElement() const {
+ ElementPtr result = Element::createMap();
+ // Set enable-updates
+ result->set("enable-updates", Element::create(enable_updates_));
+ // Set qualifying-suffix
+ result->set("qualifying-suffix", Element::create(qualifying_suffix_));
+ // Set server-ip
+ result->set("server-ip", Element::create(server_ip_.toText()));
+ // Set server-port
+ result->set("server-port",
+ Element::create(static_cast<long long>(server_port_)));
+ // Set sender-ip
+ result->set("sender-ip", Element::create(sender_ip_.toText()));
+ // Set sender-port
+ result->set("sender-port",
+ Element::create(static_cast<long long>(sender_port_)));
+ // Set max-queue-size
+ result->set("max-queue-size",
+ Element::create(static_cast<long long>(max_queue_size_)));
+ // Set ncr-protocol
+ result->set("ncr-protocol",
+ Element::create(dhcp_ddns::
+ ncrProtocolToString(ncr_protocol_)));
+ // Set ncr-format
+ result->set("ncr-format",
+ Element::create(dhcp_ddns::ncrFormatToString(ncr_format_)));
+ // Set always-include-fqdn
+ result->set("always-include-fqdn", Element::create(always_include_fqdn_));
+ // Set override-no-update
+ result->set("override-no-update", Element::create(override_no_update_));
+ // Set override-client-update
+ result->set("override-client-update",
+ Element::create(override_client_update_));
+ // Set replace-client-name
+ result->set("replace-client-name",
+ Element::create(replaceClientNameModeToString
+ (replace_client_name_mode_)));
+ // Set generated-prefix
+ result->set("generated-prefix", Element::create(generated_prefix_));
+ return (result);
+}
+
std::ostream&
operator<<(std::ostream& os, const D2ClientConfig& config) {
os << config.toText();
-// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2017 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
/// This file defines the classes Kea uses to manage configuration needed to
/// act as a client of the kea-dhcp-ddns module (aka D2).
///
+
#include <asiolink/io_address.h>
+#include <cc/cfg_to_element.h>
#include <dhcp_ddns/ncr_io.h>
#include <exceptions/exceptions.h>
/// parameters associated with DHCP-DDNS and acting as a client of D2.
/// Instances of this class may be constructed through configuration parsing.
///
-class D2ClientConfig {
+class D2ClientConfig : public isc::data::CfgToElement {
public:
/// @brief Default configuration constants.
/// @todo For now these are hard-coded as configuration layer cannot
/// "unknown" if not.
static std::string replaceClientNameModeToString(const ReplaceClientNameMode& mode);
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
protected:
/// @brief Validates member values.
///
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <log/logger_name.h>
using namespace isc::log;
+using namespace isc::data;
namespace isc {
namespace dhcp {
return (spec);
}
+ElementPtr
+LoggingInfo::toElement() const {
+ ElementPtr result = Element::createMap();
+ // Set name
+ result->set("name", Element::create(name_));
+ // Set output_options
+ ElementPtr options = Element::createList();
+ for (std::vector<LoggingDestination>::const_iterator dest =
+ destinations_.cbegin();
+ dest != destinations_.cend(); ++dest) {
+ ElementPtr map = Element::createMap();
+ // Set output
+ map->set("output", Element::create(dest->output_));
+ // Set maxver
+ map->set("maxver", Element::create(dest->maxver_));
+ // Set maxsize
+ map->set("maxsize",
+ Element::create(static_cast<long long>(dest->maxsize_)));
+ // Set flush
+ map->set("flush", Element::create(dest->flush_));
+ // Push on output option list
+ options->add(map);
+ }
+ result->set("output_options", options);
+ // Set severity
+ std::string severity;
+ switch (severity_) {
+ case isc::log::DEBUG:
+ severity = "DEBUG";
+ break;
+ case isc::log::INFO:
+ severity = "INFO";
+ break;
+ case isc::log::WARN:
+ severity = "WARN";
+ break;
+ case isc::log::ERROR:
+ severity = "ERROR";
+ break;
+ case isc::log::FATAL:
+ severity = "FATAL";
+ break;
+ case isc::log::NONE:
+ severity = "NONE";
+ break;
+ default:
+ isc_throw(ToElementError, "illegal severity: " << severity_);
+ break;
+ }
+ result->set("severity", Element::create(severity));
+ // Set debug level
+ result->set("debuglevel", Element::create(debuglevel_));
+ return (result);
+}
+
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <log/logger_level.h>
#include <log/logger_specification.h>
+#include <cc/cfg_to_element.h>
#include <stdint.h>
#include <vector>
/// "severity": "WARN",
/// "debuglevel": 99
/// },
-struct LoggingInfo {
+struct LoggingInfo : public isc::data::CfgToElement {
/// @brief logging name
std::string name_;
/// @brief Converts logger configuration to a spec.
isc::log::LoggerSpecification toSpec() const;
+
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
};
/// @brief storage for logging information in log4cplus format
ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
ConstElementPtr class_def_cfg,
uint16_t family) {
+ // name is now mandatory
+ std::string name = getString(class_def_cfg, "name");
+ if (name.empty()) {
+ isc_throw(DhcpConfigError,
+ "not empty parameter 'name' is required "
+ << getPosition("name", class_def_cfg) << ")");
+ }
- try {
- std::string name;
- std::string next_server_txt = "0.0.0.0";
- std::string sname;
- std::string filename;
- ExpressionPtr match_expr;
- CfgOptionPtr options(new CfgOption());
-
- // Parse the elements that make up the client class definition.
- BOOST_FOREACH(ConfigPair param, class_def_cfg->mapValue()) {
- std::string entry(param.first);
- ConstElementPtr value(param.second);
-
- if (entry == "name") {
- name = value->stringValue();
-
- } else if (entry == "test") {
- ExpressionParser parser;
- parser.parse(match_expr, value, family);
-
- } else if (entry == "option-data") {
- OptionDataListParser opts_parser(family);
- opts_parser.parse(options, value);
-
- } else if (entry == "next-server") {
- next_server_txt = value->stringValue();
-
- } else if (entry == "server-hostname") {
- sname = value->stringValue();
-
- } else if (entry == "boot-file-name") {
- filename = value->stringValue();
-
- } else {
- isc_throw(DhcpConfigError, "invalid parameter '" << entry
- << "' (" << value->getPosition() << ")");
- }
- }
+ // Parse matching expression
+ ExpressionPtr match_expr;
+ ConstElementPtr test_cfg = class_def_cfg->get("test");
+ std::string test;
+ if (test_cfg) {
+ ExpressionParser parser;
+ parser.parse(match_expr, test_cfg, family);
+ test = test_cfg->stringValue();
+ }
- // name is now mandatory
- if (name.empty()) {
- isc_throw(DhcpConfigError,
- "not empty parameter 'name' is required");
- }
+ // Parse option data
+ CfgOptionPtr options(new CfgOption());
+ ConstElementPtr option_data = class_def_cfg->get("option-data");
+ if (option_data) {
+ OptionDataListParser opts_parser(family);
+ opts_parser.parse(options, option_data);
+ }
- // Let's parse the next-server field
- IOAddress next_server("0.0.0.0");
+ // Let's try to parse the next-server field
+ IOAddress next_server("0.0.0.0");
+ if (class_def_cfg->contains("next-server")) {
+ std::string next_server_txt = getString(class_def_cfg, "next-server");
try {
next_server = IOAddress(next_server_txt);
} catch (const IOError& ex) {
- isc_throw(DhcpConfigError, "Invalid next-server value specified: '"
- << next_server_txt);
+ isc_throw(DhcpConfigError,
+ "Invalid next-server value specified: '"
+ << next_server_txt << "' ("
+ << getPosition("next-server", class_def_cfg) << ")");
}
if (next_server.getFamily() != AF_INET) {
isc_throw(DhcpConfigError, "Invalid next-server value: '"
- << next_server_txt << "', must be IPv4 address");
+ << next_server_txt
+ << "', must be IPv4 address ("
+ << getPosition("next-server", class_def_cfg) << ")");
}
if (next_server.isV4Bcast()) {
isc_throw(DhcpConfigError, "Invalid next-server value: '"
- << next_server_txt << "', must not be a broadcast");
+ << next_server_txt
+ << "', must not be a broadcast ("
+ << getPosition("next-server", class_def_cfg) << ")");
}
+ }
+
+ // Let's try to parse server-hostname
+ std::string sname;
+ if (class_def_cfg->contains("server-hostname")) {
+ sname = getString(class_def_cfg, "server-hostname");
- // Let's try to parse server-hostname
if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
isc_throw(DhcpConfigError, "server-hostname must be at most "
<< Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
- << sname.length());
+ << sname.length() << " ("
+ << getPosition("server-hostname", class_def_cfg) << ")");
}
+ }
+
+ // Let's try to parse boot-file-name
+ std::string filename;
+ if (class_def_cfg->contains("boot-file-name")) {
+ filename = getString(class_def_cfg, "boot-file-name");
- // Let's try to parse boot-file-name
if (filename.length() > Pkt4::MAX_FILE_LEN) {
isc_throw(DhcpConfigError, "boot-file-name must be at most "
<< Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
- << filename.length());
+ << filename.length() << " ("
+ << getPosition("boot-file-name", class_def_cfg) << ")");
}
- // Add the client class definition
- class_dictionary->addClass(name, match_expr, options, next_server,
- sname, filename);
+ }
+
+ // Add the client class definition
+ try {
+ class_dictionary->addClass(name, match_expr, test, options,
+ next_server, sname, filename);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what()
<< " (" << class_def_cfg->getPosition() << ")");
/// @brief Constructor
///
/// @param db_type Specifies database type (lease or hosts)
- DbAccessParser(DBType db_type);
+ explicit DbAccessParser(DBType db_type);
/// The destructor.
virtual ~DbAccessParser()
}
} catch (std::exception& ex) {
- // Append position of the option space parameter. Note, that in the case
- // when 'space' was not specified a default value will be used and we
- // should never get here. Therefore, it is ok to call getPosition for
- // the space parameter here as this parameter will always be specified.
+ // Append position of the option space parameter.
isc_throw(DhcpConfigError, ex.what() << " ("
<< getPosition("space", parent) << ")");
}
// Option definition has been found so let's use it to create
// an instance of our option.
try {
- OptionPtr option =
- !csv_format_param.isSpecified() || csv_format_param ?
+ bool use_csv = !csv_format_param.isSpecified() || csv_format_param;
+ OptionPtr option = use_csv ?
def->optionFactory(universe, def->getCode(), data_tokens) :
def->optionFactory(universe, def->getCode(), binary);
desc.option_ = option;
desc.persistent_ = false;
+ if (use_csv) {
+ desc.formatted_value_ = data_param;
+ }
} catch (const isc::Exception& ex) {
isc_throw(DhcpConfigError, "option data does not match"
<< " option definition (space: " << space_param
BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) {
std::pair<OptionDescriptor, std::string> option =
option_parser.parse(data);
- cfg->add(option.first.option_, option.first.persistent_, option.second);
+ // Use the option description to keep the formatted value
+ cfg->add(option.first, option.second);
cfg->encapsulate();
}
}
: family_(family) {
};
+// Can't use a constructor as a function
+namespace {
+IOAddress buildIOAddress(const std::string& str) { return (IOAddress(str)); }
+};
+
+IOAddress
+RelayInfoParser::getIOAddress(ConstElementPtr scope,
+ const std::string& name) {
+ return (getAndConvert<IOAddress,
+ buildIOAddress>(scope, name, "address"));
+}
+
void
RelayInfoParser::parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg,
ConstElementPtr relay_info) {
- // Let's start with some sanity checks.
- if (!relay_info || !cfg) {
- isc_throw(DhcpConfigError, "Logic error: RelayInfoParser::parse() called "
- "with at least one NULL parameter.");
- }
-
- if (relay_info->getType() != Element::map) {
- isc_throw(DhcpConfigError, "Configuration error: RelayInfoParser::parse() "
- "called with non-map parameter");
- }
-
- // Now create the default value.
- isc::asiolink::IOAddress ip(family_ == Option::V4 ? IOAddress::IPV4_ZERO_ADDRESS()
- : IOAddress::IPV6_ZERO_ADDRESS());
-
- // Now iterate over all parameters. Currently there's only one supported
- // parameter, so it should be an easy thing to check.
- bool ip_address_specified = false;
- BOOST_FOREACH(ConfigPair param, relay_info->mapValue()) {
- if (param.first == "ip-address") {
- ip_address_specified = true;
-
- try {
- ip = asiolink::IOAddress(param.second->stringValue());
- } catch (...) {
- isc_throw(DhcpConfigError, "Failed to parse ip-address "
- "value: " << param.second
- << " (" << param.second->getPosition() << ")");
- }
-
- // Check if the address family matches.
- if ( (ip.isV4() && family_ != Option::V4) ||
- (ip.isV6() && family_ != Option::V6) ) {
- isc_throw(DhcpConfigError, "ip-address field " << ip.toText()
- << " does not have IP address of expected family type: "
- << (family_ == Option::V4 ? "IPv4" : "IPv6")
- << " (" << param.second->getPosition() << ")");
- }
- } else {
- isc_throw(NotImplemented,
- "parser error: RelayInfoParser parameter not supported: "
- << param.second);
- }
- }
-
- if (!ip_address_specified) {
- isc_throw(DhcpConfigError, "'relay' specified, but mandatory 'ip-address' "
- "paramter in it is missing");
+ // There is only one parameter which is mandatory
+ IOAddress ip = getIOAddress(relay_info, "ip-address");
+
+ // Check if the address family matches.
+ if ((ip.isV4() && family_ != Option::V4) ||
+ (ip.isV6() && family_ != Option::V6) ) {
+ isc_throw(DhcpConfigError, "ip-address field " << ip.toText()
+ << " does not have IP address of expected family type: "
+ << (family_ == Option::V4 ? "IPv4" : "IPv6")
+ << " (" << getPosition("ip-address", relay_info) << ")");
}
// Ok, we're done with parsing. Let's store the result in the structure
try {
std::string hr_mode = getString(params, "reservation-mode");
subnet_->setHostReservationMode(hrModeFromText(hr_mode));
- } catch (const BadValue& ex) {
- ConstElementPtr mode = params->get("reservation-mode");
- string pos;
- if (mode) {
- pos = mode->getPosition().str();
- } else {
- pos = params->getPosition().str();
- }
- isc_throw(DhcpConfigError, "Failed to process specified value "
+ } catch (const BadValue& ex) {
+ isc_throw(DhcpConfigError, "Failed to process specified value "
" of reservation-mode parameter: " << ex.what()
- << "(" << pos << ")");
+ << "(" << getPosition("reservation-mode", params) << ")");
}
// Try setting up client class.
//**************************** D2ClientConfigParser **********************
-uint32_t
-D2ClientConfigParser::getUint32(ConstElementPtr scope,
- const std::string& name) {
- return (getIntType<uint32_t>(scope, name));
-}
-
-// Can't use a constructor as a function
-namespace {
-IOAddress buildIOAddress(const std::string& str) { return (IOAddress(str)); }
-};
-
IOAddress
D2ClientConfigParser::getIOAddress(ConstElementPtr scope,
const std::string& name) {
/// @brief Constructor.
///
/// @param address_family Address family: @c AF_INET or @c AF_INET6.
- OptionDataParser(const uint16_t address_family);
+ explicit OptionDataParser(const uint16_t address_family);
/// @brief Parses ElementPtr containing option definition
///
/// @brief Constructor.
///
/// @param address_family Address family: @c AF_INET or AF_INET6
- OptionDataListParser(const uint16_t address_family);
+ explicit OptionDataListParser(const uint16_t address_family);
/// @brief Parses a list of options, instantiates them and stores in cfg
///
/// @brief constructor
/// @param family specifies protocol family (IPv4 or IPv6)
- RelayInfoParser(const isc::dhcp::Option::Universe& family);
+ explicit RelayInfoParser(const isc::dhcp::Option::Universe& family);
/// @brief parses the actual relay parameters
///
void parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg,
isc::data::ConstElementPtr relay_info);
-protected:
+private:
+
+ /// @brief Returns a value converted to IOAddress
+ ///
+ /// Instantiation of getAndConvert() to IOAddress
+ ///
+ /// @param scope specified parameter will be extracted from this scope
+ /// @param name name of the parameter
+ /// @return an IOAddress value
+ isc::asiolink::IOAddress
+ getIOAddress(isc::data::ConstElementPtr scope, const std::string& name);
+
/// Protocol family (IPv4 or IPv6)
Option::Universe family_;
};
/// @brief constructor
///
/// @param family address family: @c AF_INET or @c AF_INET6
- SubnetConfigParser(uint16_t family);
+ explicit SubnetConfigParser(uint16_t family);
/// @brief virtual destructor (does nothing)
virtual ~SubnetConfigParser() { }
private:
- /// @brief Returns a value converted to uint32_t
- ///
- /// Instantiation of getIntType() to uint32_t
- ///
- /// @param scope specified parameter will be extracted from this scope
- /// @param name name of the parameter
- /// @return an uint32_t value
- uint32_t
- getUint32(isc::data::ConstElementPtr scope, const std::string& name);
-
/// @brief Returns a value converted to IOAddress
///
/// Instantiation of getAndConvert() to IOAddress
namespace dhcp {
void
-DUIDConfigParser::parse(const CfgDUIDPtr& cfg, isc::data::ConstElementPtr duid_configuration) {
- if (!cfg) {
- isc_throw(DhcpConfigError, "Must provide valid pointer to cfg when parsing duid");
- }
-
- bool type_present = false;
- BOOST_FOREACH(ConfigPair element, duid_configuration->mapValue()) {
- try {
- if (element.first == "type") {
- type_present = true;
- setType(cfg, element.second->stringValue());
- } else if (element.first == "identifier") {
- setIdentifier(cfg, element.second->stringValue());
- } else if (element.first == "htype") {
- setHType(cfg, element.second->intValue());
- } else if (element.first == "time") {
- setTime(cfg, element.second->intValue());
- } else if (element.first == "enterprise-id") {
- setEnterpriseId(cfg, element.second->intValue());
- } else if (element.first == "persist") {
- setPersist(cfg, element.second->boolValue());
- } else {
- isc_throw(DhcpConfigError, "unsupported configuration "
- "parameter '" << element.first << "'");
- }
- } catch (const std::exception& ex) {
- // Append position.
- isc_throw(DhcpConfigError, ex.what() << " ("
- << element.second->getPosition() << ")");
+DUIDConfigParser::parse(const CfgDUIDPtr& cfg,
+ isc::data::ConstElementPtr duid_configuration) {
+
+ std::string param;
+ try {
+ param = "type";
+ std::string duid_type = getString(duid_configuration, "type");
+ // Map DUID type represented as text into numeric value.
+ DUID::DUIDType numeric_type = DUID::DUID_UNKNOWN;
+ if (duid_type == "LLT") {
+ numeric_type = DUID::DUID_LLT;
+ } else if (duid_type == "EN") {
+ numeric_type = DUID::DUID_EN;
+ } else if (duid_type == "LL") {
+ numeric_type = DUID::DUID_LL;
+ } else {
+ isc_throw(BadValue, "unsupported DUID type '"
+ << duid_type << "'. Expected: LLT, EN or LL");
}
- }
-
- // "type" is mandatory
- if (!type_present) {
- isc_throw(DhcpConfigError, "mandatory parameter \"type\" not specified"
- " for the DUID configuration ("
- << duid_configuration->getPosition() << ")");
- }
-
- LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_CONFIGURE_SERVERID);
-}
-void
-DUIDConfigParser::setType(const CfgDUIDPtr& cfg, const std::string& duid_type) const {
- // Map DUID type represented as text into numeric value.
- DUID::DUIDType numeric_type = DUID::DUID_UNKNOWN;
- if (duid_type == "LLT") {
- numeric_type = DUID::DUID_LLT;
- } else if (duid_type == "EN") {
- numeric_type = DUID::DUID_EN;
- } else if (duid_type == "LL") {
- numeric_type = DUID::DUID_LL;
- } else {
- isc_throw(DhcpConfigError, "unsupported DUID type '"
- << duid_type << "'. Expected: LLT, EN or LL");
- }
-
- cfg->setType(static_cast<DUID::DUIDType>(numeric_type));
-}
+ cfg->setType(static_cast<DUID::DUIDType>(numeric_type));
-void
-DUIDConfigParser::setIdentifier(const CfgDUIDPtr& cfg, const std::string& identifier) const {
- cfg->setIdentifier(identifier);
-}
-
-void
-DUIDConfigParser::setHType(const CfgDUIDPtr& cfg, const int64_t htype) const {
- checkRange<uint16_t>("htype", htype);
- cfg->setHType(static_cast<uint16_t>(htype));
-}
+ param = "identifier";
+ if (duid_configuration->contains(param)) {
+ cfg->setIdentifier(getString(duid_configuration, param));
+ }
-void
-DUIDConfigParser::setTime(const CfgDUIDPtr& cfg, const int64_t new_time) const {
- checkRange<uint32_t>("time", new_time);
- cfg->setTime(static_cast<uint32_t>(new_time));
-}
+ param = "htype";
+ if (duid_configuration->contains(param)) {
+ cfg->setHType(getUint16(duid_configuration, param));
+ }
-void
-DUIDConfigParser::setEnterpriseId(const CfgDUIDPtr& cfg, const int64_t enterprise_id) const {
- checkRange<uint32_t>("enterprise-id", enterprise_id);
- cfg->setEnterpriseId(static_cast<uint32_t>(enterprise_id));
-}
+ param = "time";
+ if (duid_configuration->contains(param)) {
+ cfg->setTime(getUint32(duid_configuration, param));
+ }
-void
-DUIDConfigParser::setPersist(const CfgDUIDPtr& cfg, const bool persist) {
- cfg->setPersist(persist);
-}
+ param = "enterprise-id";
+ if (duid_configuration->contains(param)) {
+ cfg->setEnterpriseId(getUint32(duid_configuration, param));
+ }
-template<typename NumericType>
-void
-DUIDConfigParser::checkRange(const std::string& parameter_name,
- const int64_t parameter_value) const {
- if ((parameter_value < 0) ||
- (parameter_value > std::numeric_limits<NumericType>::max())) {
- isc_throw(DhcpConfigError, "out of range value '" << parameter_value
- << "' specified for parameter '" << parameter_name
- << "'; expected value in range of [0.."
- << std::numeric_limits<NumericType>::max() << "]");
+ param = "persist";
+ if (duid_configuration->contains(param)) {
+ cfg->setPersist(getBoolean(duid_configuration, param));
+ }
+ } catch (const DhcpConfigError&) {
+ throw;
+ } catch (const std::exception& ex) {
+ // Append position.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << getPosition(param, duid_configuration) << ")");
}
-}
+ LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_CONFIGURE_SERVERID);
+}
} // end of namespace isc::dhcp
} // end of namespace isc
///
/// @throw DhcpConfigError If the configuration is invalid.
void parse(const CfgDUIDPtr& cfg, isc::data::ConstElementPtr duid_configuration);
-private:
-
- /// @brief Validate and set DUID type.
- ///
- /// @param cfg parsed information will be stored here
- /// @param duid_type DUID type in textual format.
- void setType(const CfgDUIDPtr& cfg, const std::string& duid_type) const;
-
- /// @brief Validate and set identifier.
- ///
- /// @param cfg parsed information will be stored here
- /// @param identifier Identifier.
- void setIdentifier(const CfgDUIDPtr& cfg, const std::string& identifier) const;
-
- /// @brief Validate and set hardware type.
- ///
- /// @param cfg parsed information will be stored here
- /// @param htype Hardware type.
- void setHType(const CfgDUIDPtr& cfg, const int64_t htype) const;
-
- /// @brief Validate and set time value.
- ///
- /// @param cfg parsed information will be stored here
- /// @param new_time Time value to be used for DUID.
- void setTime(const CfgDUIDPtr& cfg, const int64_t new_time) const;
-
- /// @brief Validate and set enterprise id.
- ///
- /// @param cfg parsed information will be stored here
- /// @param enterprise_id Enterprise id.
- void setEnterpriseId(const CfgDUIDPtr& cfg, const int64_t enterprise_id) const;
-
- /// @brief Set persistence flag.
- ///
- /// @param cfg parsed information will be stored here
- /// @param persist A boolean value indicating if the server
- /// identifier should be stored on the disk (if true) or
- /// not (if false).
- void setPersist(const CfgDUIDPtr& cfg, const bool persist);
-
- /// @brief Verifies if the specified parameter is in range.
- ///
- /// Each numeric value must be in range of [0 .. max_value], where
- /// max_value is a maximum value for the numeric type used for this
- /// parameter.
- ///
- /// @param parameter_name Parameter name.
- /// @tparam Numeric type of the specified parameter.
- template<typename NumericType>
- void checkRange(const std::string& parameter_name,
- const int64_t parameter_value) const;
};
}
ExpirationConfigParser::parse(ConstElementPtr expiration_config) {
CfgExpirationPtr cfg = CfgMgr::instance().getStagingCfg()->getCfgExpiration();
- BOOST_FOREACH(ConfigPair config_element, expiration_config->mapValue()) {
+ std::string param;
- // Get parameter name and value.
- std::string param_name = config_element.first;
- ConstElementPtr param_value = config_element.second;
-
- try {
- // Set configuration parameters.
- if (param_name == "reclaim-timer-wait-time") {
- cfg->setReclaimTimerWaitTime(param_value->intValue());
-
- } else if (param_name == "flush-reclaimed-timer-wait-time") {
- cfg->setFlushReclaimedTimerWaitTime(param_value->intValue());
-
- } else if (param_name == "hold-reclaimed-time") {
- cfg->setHoldReclaimedTime(param_value->intValue());
+ try {
+ param = "reclaim-timer-wait-time";
+ if (expiration_config->contains(param)) {
+ cfg->setReclaimTimerWaitTime(getInteger(expiration_config, param));
+ }
- } else if (param_name == "max-reclaim-leases") {
- cfg->setMaxReclaimLeases(param_value->intValue());
+ param = "flush-reclaimed-timer-wait-time";
+ if (expiration_config->contains(param)) {
+ cfg->setFlushReclaimedTimerWaitTime(getInteger(expiration_config,
+ param));
+ }
- } else if (param_name == "max-reclaim-time") {
- cfg->setMaxReclaimTime(param_value->intValue());
+ param = "hold-reclaimed-time";
+ if (expiration_config->contains(param)) {
+ cfg->setHoldReclaimedTime(getInteger(expiration_config, param));
+ }
- } else if (param_name == "unwarned-reclaim-cycles") {
- cfg->setUnwarnedReclaimCycles(param_value->intValue());
+ param = "max-reclaim-leases";
+ if (expiration_config->contains(param)) {
+ cfg->setMaxReclaimLeases(getInteger(expiration_config, param));
+ }
- } else {
- isc_throw(DhcpConfigError, "unsupported parameter '"
- << param_name << "'");
- }
+ param = "max-reclaim-time";
+ if (expiration_config->contains(param)) {
+ cfg->setMaxReclaimTime(getInteger(expiration_config, param));
+ }
- } catch (const std::exception& ex) {
- // Append position of the configuration parameter to the error
- // message.
- isc_throw(DhcpConfigError, ex.what() << " ("
- << param_value->getPosition() << ")");
+ param = "unwarned-reclaim-cycles";
+ if (expiration_config->contains(param)) {
+ cfg->setUnwarnedReclaimCycles(
+ getInteger(expiration_config, param));
}
+ } catch (const DhcpConfigError&) {
+ throw;
+ } catch (const std::exception& ex) {
+ // Append position of the configuration parameter to the error message.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << getPosition(param, expiration_config) << ")");
}
}
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
/// @brief Constructor
///
/// @param protocol AF_INET for DHCPv4 and AF_INET6 for DHCPv6.
- IfacesConfigParser(const uint16_t protocol);
+ explicit IfacesConfigParser(const uint16_t protocol);
/// @brief Parses content of the "interfaces-config".
///
-// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 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
/// This may be useful for "prefix/len" style definition for
/// addresses, but is mostly useful for prefix pools.
/// @return prefix length (1-128)
- uint8_t getLength() {
+ uint8_t getLength() const {
return (prefix_len_);
}
#include <sstream>
using namespace isc::log;
+using namespace isc::data;
namespace isc {
namespace dhcp {
}
}
+ElementPtr
+SrvConfig::toElement() const {
+ // Get family for the configuration manager
+ uint16_t family = CfgMgr::instance().getFamily();
+ // Toplevel map
+ ElementPtr result = Element::createMap();
+ // DhcpX global map
+ ElementPtr dhcp = Element::createMap();
+ // Set decline-probation-period
+ dhcp->set("decline-probation-period",
+ Element::create(static_cast<long long>(decline_timer_)));
+ // Set echo-client-id (DHCPv4)
+ if (family == AF_INET) {
+ dhcp->set("echo-client-id", Element::create(echo_v4_client_id_));
+ }
+ // Set dhcp4o6-port
+ dhcp->set("dhcp4o6-port",
+ Element::create(static_cast<int>(dhcp4o6_port_)));
+ // Set dhcp-ddns
+ dhcp->set("dhcp-ddns", d2_client_config_->toElement());
+ // Set interfaces-config
+ ConstElementPtr ifaces = cfg_iface_->toElement();
+ dhcp->set("interfaces-config", cfg_iface_->toElement());
+ // Set option-def
+ ConstElementPtr option_def = cfg_option_def_->toElement();
+ dhcp->set("option-def", option_def);
+ // Set option-data
+ ConstElementPtr option_data = cfg_option_->toElement();
+ dhcp->set("option-data", option_data);
+ // Set subnets
+ if (family == AF_INET) {
+ ConstElementPtr subnets = cfg_subnets4_->toElement();
+ // @todo Insert reservations
+ dhcp->set("subnet4", subnets);
+ } else {
+ ConstElementPtr subnets = cfg_subnets6_->toElement();
+ // @todo Insert reservations
+ dhcp->set("subnet6", subnets);
+ }
+ // Set relay-supplied-options (DHCPv6)
+ if (family == AF_INET6) {
+ dhcp->set("relay-supplied-options", cfg_rsoo_->toElement());
+ }
+ // Set expired-leases-processing
+ ConstElementPtr expired = cfg_expiration_->toElement();
+ dhcp->set("expired-leases-processing", expired);
+ // Set server-id (DHCPv6)
+ if (family == AF_INET6) {
+ dhcp->set("server-id", cfg_duid_->toElement());
+ }
+ // Set lease-database
+ CfgLeaseDbAccess lease_db(*cfg_db_access_);
+ dhcp->set("lease-database", lease_db.toElement());
+ // Set hosts-database
+ CfgHostDbAccess host_db(*cfg_db_access_);
+ dhcp->set("hosts-database", host_db.toElement());
+ // Set host-reservation-identifiers
+ ConstElementPtr host_ids;
+ if (family == AF_INET) {
+ host_ids = cfg_host_operations4_->toElement();
+ } else {
+ host_ids = cfg_host_operations6_->toElement();
+ }
+ dhcp->set("host-reservation-identifiers", host_ids);
+ // Set mac-sources (DHCPv6)
+ if (family == AF_INET6) {
+ dhcp->set("mac-sources", cfg_mac_source_.toElement());
+ }
+ // Set control-socket (skip if null as empty is not legal)
+ if (!isNull(control_socket_)) {
+ dhcp->set("control-socket", control_socket_);
+ }
+ // Set client-classes
+ ConstElementPtr client_classes = class_dictionary_->toElement();
+ dhcp->set("client-classes", client_classes);
+ // Set hooks-libraries
+ ConstElementPtr hooks_libs = hooks_config_.toElement();
+ dhcp->set("hooks-libraries", hooks_libs);
+ // Set DhcpX
+ result->set(family == AF_INET ? "Dhcp4" : "Dhcp6", dhcp);
+
+ // Logging global map (skip if loggers is empty)
+ ElementPtr logging = Element::createMap();
+ // Set loggers list
+ ElementPtr loggers = Element::createList();
+ for (LoggingInfoStorage::const_iterator logger = logging_info_.cbegin();
+ logger != logging_info_.cend(); ++logger) {
+ loggers->add(logger->toElement());
+ }
+ if (!loggers->empty()) {
+ logging->set("loggers", loggers);
+ result->set("Logging", logging);
+ }
+
+ return (result);
+}
+
}
}
#ifndef DHCPSRV_CONFIG_H
#define DHCPSRV_CONFIG_H
+#include <cc/cfg_to_element.h>
#include <dhcpsrv/cfg_db_access.h>
#include <dhcpsrv/cfg_duid.h>
#include <dhcpsrv/cfg_expiration.h>
/// @brief Specifies current DHCP configuration
///
/// @todo Migrate all other configuration parameters from cfgmgr.h here
-class SrvConfig {
+class SrvConfig : public isc::data::CfgToElement {
public:
/// @name Constants for selection of parameters returned by @c getConfigSummary
///
/// this socket is bound and connected to this port and port + 1
///
/// @param port port and port + 1 to use
- void setDhcp4o6Port(uint32_t port) {
+ void setDhcp4o6Port(uint16_t port) {
/// @todo: Port is supposed to be uint16_t, not uint32_t
dhcp4o6_port_ = port;
}
///
/// See @ref setDhcp4o6Port for brief discussion.
/// @return value of DHCP4o6 IPC port
- uint32_t getDhcp4o6Port() {
+ uint16_t getDhcp4o6Port() {
return (dhcp4o6_port_);
}
d2_client_config_ = d2_client_config;
}
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
private:
/// @brief Sequence number identifying the configuration.
///
/// DHCPv4-over-DHCPv6 uses a UDP socket for interserver communication,
/// this socket is bound and connected to this port and port + 1
- uint32_t dhcp4o6_port_;
+ uint16_t dhcp4o6_port_;
D2ClientConfigPtr d2_client_config_;
};
-// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 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
void
allowClientClass(const isc::dhcp::ClientClass& class_name);
+ /// @brief returns the client class white list
+ ///
+ /// @note The returned reference is only valid as long as the object
+ /// returned it is valid.
+ ///
+ /// @return client classes @ref white_list_
+ const isc::dhcp::ClientClasses& getClientClasses() const {
+ return (white_list_);
+ }
+
/// @brief Specifies what type of Host Reservations are supported.
///
/// Host reservations may be either in-pool (they reserve an address that
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/tests/libdhcptest.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015,2017 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
isc::BadValue);
}
+// Checks if IPv4 address ranges can be converted to prefix / prefix_len
+TEST(AddrUtilitiesTest, prefixLengthFromRange4) {
+ // Use a shorter name
+ const auto& plfr = prefixLengthFromRange;
+
+ // Let's start with something simple
+ EXPECT_EQ(32, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.0")));
+ EXPECT_EQ(31, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.1")));
+ EXPECT_EQ(30, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.3")));
+ EXPECT_EQ(29, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.7")));
+ EXPECT_EQ(28, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.15")));
+ EXPECT_EQ(27, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.31")));
+ EXPECT_EQ(26, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.63")));
+ EXPECT_EQ(25, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.127")));
+ EXPECT_EQ(24, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.2.255")));
+ EXPECT_EQ(23, plfr(IOAddress("192.0.2.0"), IOAddress("192.0.3.255")));
+ EXPECT_EQ(16, plfr(IOAddress("10.0.0.0"), IOAddress("10.0.255.255")));
+ EXPECT_EQ(8, plfr(IOAddress("10.0.0.0"), IOAddress("10.255.255.255")));
+ EXPECT_EQ(0, plfr(IOAddress("0.0.0.0"), IOAddress("255.255.255.255")));
+
+ // Fail if a network boundary is crossed
+ EXPECT_EQ(-1, plfr(IOAddress("10.0.0.255"), IOAddress("10.0.1.1")));
+
+ // The upper bound cannot be smaller than the lower bound
+ EXPECT_THROW(plfr(IOAddress("192.0.2.5"), IOAddress("192.0.2.4")),
+ isc::BadValue);
+}
+
+// Checks if IPv6 address ranges can be converted to prefix / prefix_len
+TEST(AddrUtilitiesTest, prefixLengthFromRange6) {
+ // Use a shorter name
+ const auto& plfr = prefixLengthFromRange;
+
+ // Let's start with something simple
+ EXPECT_EQ(128, plfr(IOAddress("::"), IOAddress("::")));
+ EXPECT_EQ(112, plfr(IOAddress("fe80::"), IOAddress("fe80::ffff")));
+ EXPECT_EQ(96, plfr(IOAddress("fe80::"), IOAddress("fe80::ffff:ffff")));
+ EXPECT_EQ(80, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::ffff:ffff:ffff")));
+ EXPECT_EQ(64, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(63, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::1:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(62, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::3:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(61, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::7:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(60, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::f:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(59, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::1f:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(58, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::3f:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(57, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::7f:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(56, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::ff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(55, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::1ff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(54, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::3ff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(53, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::7ff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(52, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::fff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(51, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::1fff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(50, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::3fff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(49, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::7fff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(48, plfr(IOAddress("fe80::"),
+ IOAddress("fe80::ffff:ffff:ffff:ffff:ffff")));
+ EXPECT_EQ(0, plfr(IOAddress("::"),
+ IOAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
+
+ // Fail if a network boundary is crossed
+ EXPECT_EQ(-1, plfr(IOAddress("2001:db8::ffff"),
+ IOAddress("2001:db8::1:1")));
+
+ // The upper bound cannot be smaller than the lower bound
+ EXPECT_THROW(plfr(IOAddress("fe80::5"), IOAddress("fe80::4")),
+ isc::BadValue);
+
+ // Address family must match
+ EXPECT_THROW(plfr(IOAddress("192.0.2.0"), IOAddress("fe80::1")),
+ isc::BadValue);
+}
+
// Checks if prefixInRange returns valid number of prefixes in specified range.
TEST(AddrUtilitiesTest, prefixesInRange) {
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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 <cc/data.h>
#include <dhcpsrv/cfg_db_access.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/host_mgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/testutils/mysql_schema.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::test;
namespace {
TEST(CfgDbAccessTest, defaults) {
CfgDbAccess cfg;
EXPECT_EQ("type=memfile", cfg.getLeaseDbAccessString());
+ std::string expected = "{ \"type\": \"memfile\" }";
+ runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
+
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
+ runToElementTest<CfgHostDbAccess>("{ }", CfgHostDbAccess(cfg));
}
// This test verifies that it is possible to set the lease database
ASSERT_NO_THROW(cfg.setLeaseDbAccessString("type=mysql"));
EXPECT_EQ("type=mysql", cfg.getLeaseDbAccessString());
+ // Check unparse
+ std::string expected = "{ \"type\": \"mysql\" }";
+ runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
+
// Append additional parameter.
ASSERT_NO_THROW(cfg.setAppendedParameters("universe=4"));
EXPECT_EQ("type=mysql universe=4", cfg.getLeaseDbAccessString());
+ // Additional parameters are not in lease_db_access_
+ runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
+
// If access string is empty, no parameters will be appended.
ASSERT_NO_THROW(cfg.setLeaseDbAccessString(""));
EXPECT_TRUE(cfg.getLeaseDbAccessString().empty());
ASSERT_NO_THROW(cfg.setHostDbAccessString("type=mysql"));
EXPECT_EQ("type=mysql", cfg.getHostDbAccessString());
+ // Check unparse
+ std::string expected = "{ \"type\": \"mysql\" }";
+ runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
+
// Append additional parameter.
ASSERT_NO_THROW(cfg.setAppendedParameters("universe=4"));
EXPECT_EQ("type=mysql universe=4", cfg.getHostDbAccessString());
+ // Additional parameters are not in host_db_access_
+ runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
+
// If access string is empty, no parameters will be appended.
ASSERT_NO_THROW(cfg.setHostDbAccessString(""));
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <dhcpsrv/cfg_duid.h>
#include <exceptions/exceptions.h>
#include <testutils/io_utils.h>
+#include <testutils/test_to_element.h>
#include <util/encode/hex.h>
#include <gtest/gtest.h>
#include <stdint.h>
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::test;
namespace {
EXPECT_EQ(0, cfg_duid.getTime());
EXPECT_EQ(0, cfg_duid.getEnterpriseId());
EXPECT_TRUE(cfg_duid.persist());
+
+ std::string expected = "{ \"type\": \"LLT\",\n"
+ "\"identifier\": \"\",\n"
+ "\"htype\": 0,\n"
+ "\"time\": 0,\n"
+ "\"enterprise-id\": 0,\n"
+ "\"persist\": true }";
+ runToElementTest<CfgDUID>(expected, cfg_duid);
}
// This test verifies that it is possible to set values for the CfgDUID.
EXPECT_EQ(32100, cfg_duid.getTime());
EXPECT_EQ(10, cfg_duid.getEnterpriseId());
EXPECT_FALSE(cfg_duid.persist());
+
+ std::string expected = "{ \"type\": \"EN\",\n"
+ " \"identifier\": \"ABCDEF\",\n"
+ " \"htype\": 100,\n"
+ " \"time\": 32100,\n"
+ " \"enterprise-id\": 10,\n"
+ " \"persist\": false }";
+ runToElementTest<CfgDUID>(expected, cfg_duid);
}
// This test checks positive scenarios for setIdentifier.
duid->toText());
// Verify that the DUID file has been created.
- EXPECT_TRUE(isc::test::fileExists(absolutePath(DUID_FILE_NAME)));
+ EXPECT_TRUE(fileExists(absolutePath(DUID_FILE_NAME)));
}
// This method checks that the DUID-EN can be created from the
EXPECT_EQ("00:02:00:00:10:10:25:0f:3e:26:a7:62", duid->toText());
// Verify that the DUID file has been created.
- EXPECT_TRUE(isc::test::fileExists(absolutePath(DUID_FILE_NAME)));
+ EXPECT_TRUE(fileExists(absolutePath(DUID_FILE_NAME)));
}
// This method checks that the DUID-LL can be created from the
EXPECT_EQ("00:03:00:02:12:41:34:a4:b3:67", duid->toText());
// Verify that the DUID file has been created.
- EXPECT_TRUE(isc::test::fileExists(absolutePath(DUID_FILE_NAME)));
+ EXPECT_TRUE(fileExists(absolutePath(DUID_FILE_NAME)));
}
// This test verifies that it is possible to disable storing
EXPECT_EQ("00:02:00:00:10:10:25:0f:3e:26:a7:62", duid->toText());
// DUID persistence is disabled so there should be no DUID file.
- EXPECT_FALSE(isc::test::fileExists(absolutePath(DUID_FILE_NAME)));
+ EXPECT_FALSE(fileExists(absolutePath(DUID_FILE_NAME)));
}
} // end of anonymous namespace
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <dhcpsrv/cfg_expiration.h>
#include <dhcpsrv/timer_mgr.h>
#include <exceptions/exceptions.h>
+#include <testutils/test_to_element.h>
#include <util/stopwatch.h>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
cfg.getUnwarnedReclaimCycles());
}
+/// @brief Tests that unparse returns an expected value
+TEST(CfgExpirationTest, unparse) {
+ CfgExpiration cfg;
+ std::string defaults = "{\n"
+ "\"reclaim-timer-wait-time\": 10,\n"
+ "\"flush-reclaimed-timer-wait-time\": 25,\n"
+ "\"hold-reclaimed-time\": 3600,\n"
+ "\"max-reclaim-leases\": 100,\n"
+ "\"max-reclaim-time\": 250,\n"
+ "\"unwarned-reclaim-cycles\": 5 }";
+ isc::test::runToElementTest<CfgExpiration>(defaults, cfg);
+}
+
// Test the {get,set}ReclaimTimerWaitTime.
TEST(CfgExpirationTest, getReclaimTimerWaitTime) {
testAccessModify<uint16_t>(CfgExpiration::LIMIT_RECLAIM_TIMER_WAIT_TIME,
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 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
#include <dhcp/dhcp6.h>
#include <dhcpsrv/cfg_host_operations.h>
#include <dhcpsrv/host.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <iterator>
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::test;
namespace {
TEST(CfgHostOperationsTest, defaults) {
CfgHostOperations cfg;
EXPECT_TRUE(cfg.getIdentifierTypes().empty());
+ runToElementTest<CfgHostOperations>("[ ]", cfg);
}
// This test verifies that identifier types can be added into an
EXPECT_TRUE(identifierAtPosition(cfg, Host::IDENT_DUID, 1));
EXPECT_TRUE(identifierAtPosition(cfg, Host::IDENT_CIRCUIT_ID, 2));
+ // Check unparse
+ std::string ids = "[ \"hw-address\", \"duid\", \"circuit-id\" ]";
+ runToElementTest<CfgHostOperations>(ids, cfg);
+
// Let's clear and make sure no identifiers are present.
ASSERT_NO_THROW(cfg.clearIdentifierTypes());
EXPECT_TRUE(cfg.getIdentifierTypes().empty());
+ runToElementTest<CfgHostOperations>("[ ]", cfg);
}
// This test verifies that the default DHCPv4 configuration is created
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <dhcp/dhcp4.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfg_iface.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::test;
namespace {
EXPECT_FALSE(cfg1 != cfg2);
}
+// This test verifies that it is possible to unparse the interface config.
+TEST_F(CfgIfaceTest, unparse) {
+ CfgIface cfg4;
+
+ // Add things in it
+ EXPECT_NO_THROW(cfg4.use(AF_INET, "*"));
+ EXPECT_NO_THROW(cfg4.use(AF_INET, "eth0"));
+ EXPECT_NO_THROW(cfg4.use(AF_INET, "eth1/192.0.2.3"));
+
+ // Check unparse
+ std::string expected =
+ "{ \"interfaces\": [ \"*\", \"eth0\", \"eth1/192.0.2.3\" ] }";
+ runToElementTest<CfgIface>(expected, cfg4);
+
+ // Now check IPv6
+ CfgIface cfg6;
+ EXPECT_NO_THROW(cfg6.use(AF_INET6, "*"));
+ EXPECT_NO_THROW(cfg6.use(AF_INET6, "eth1"));
+ EXPECT_NO_THROW(cfg6.use(AF_INET6, "eth0/2001:db8:1::1"));
+
+ expected =
+ "{ \"interfaces\": [ \"*\", \"eth1\", \"eth0/2001:db8:1::1\" ] }";
+ runToElementTest<CfgIface>(expected, cfg6);
+}
+
// This test verifies that it is possible to specify the socket
// type to be used by the DHCPv4 server.
// This test is enabled on LINUX and BSD only, because the
// For datagram sockets, the direct traffic is not supported.
ASSERT_TRUE(!IfaceMgr::instance().isDirectResponseSupported());
+ // Check unparse
+ std::string expected = "{\n"
+ " \"interfaces\": [ ],\n"
+ " \"dhcp-socket-type\": \"udp\" }";
+ runToElementTest<CfgIface>(expected, cfg);
+
// Select raw sockets.
ASSERT_NO_THROW(cfg.useSocketType(AF_INET, "raw"));
EXPECT_EQ("raw", cfg.socketTypeToText());
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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 <dhcpsrv/cfg_mac_source.h>
#include <dhcp/hwaddr.h>
#include <exceptions/exceptions.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
+#include <string>
namespace {
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::test;
// Checks whether CfgMACSource::MACSourceFromText is working correctly.
// Technically, this is a Pkt, not Pkt6 test, but since there is no separate
CfgMACSource::MACSourceFromText("docsis-modem"));
}
+// Checks whether the opposite operation is working correctly.
+TEST(CfgMACSourceTest, unparse) {
+ CfgMACSource cfg;
+ // any was added by the constructor
+ cfg.add(HWAddr::HWADDR_SOURCE_RAW);
+ cfg.add(HWAddr::HWADDR_SOURCE_DUID);
+ cfg.add(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL);
+ cfg.add(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
+ cfg.add(HWAddr::HWADDR_SOURCE_REMOTE_ID);
+ cfg.add(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID);
+ cfg.add(HWAddr::HWADDR_SOURCE_DOCSIS_CMTS);
+ cfg.add(HWAddr::HWADDR_SOURCE_DOCSIS_MODEM);
+
+ // Unparse
+ std::string expected = "["
+ "\"any\","
+ "\"raw\","
+ "\"duid\","
+ "\"ipv6-link-local\","
+ "\"client-link-addr-option\","
+ "\"remote-id\","
+ "\"subscriber-id\","
+ "\"docsis-cmts\","
+ "\"docsis-modem\""
+ "]";
+ runToElementTest<CfgMACSource>(expected, cfg);
+
+ // Add an unknown type
+ cfg.add(0x12345678);
+ ASSERT_THROW(cfg.toElement(), ToElementError);
+}
+
};
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcp/dhcp6.h>
#include <dhcp/option_space.h>
#include <dhcpsrv/cfg_option_def.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc;
EXPECT_THROW(cfg.add(def, "isc"), DuplicateOptionDefinition);
}
+// This test verifies that the funtion that unparses configuration
+// works as expected.
+TEST(CfgOptionDefTest, unparse) {
+ CfgOptionDef cfg;
+
+ // Add some options.
+ cfg.add(OptionDefinitionPtr(new
+ OptionDefinition("option-foo", 5, "uint16")), "isc");
+ cfg.add(OptionDefinitionPtr(new
+ OptionDefinition("option-bar", 5, "uint16", true)), "dns");
+ cfg.add(OptionDefinitionPtr(new
+ OptionDefinition("option-baz", 6, "uint16", "dns")), "isc");
+ OptionDefinitionPtr rec(new OptionDefinition("option-rec", 6, "record"));
+ rec->addRecordField("uint16");
+ rec->addRecordField("uint16");
+ cfg.add(rec, "dns");
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"name\": \"option-bar\",\n"
+ " \"code\": 5,\n"
+ " \"type\": \"uint16\",\n"
+ " \"array\": true,\n"
+ " \"record-types\": \"\",\n"
+ " \"encapsulate\": \"\",\n"
+ " \"space\": \"dns\"\n"
+ "},{\n"
+ " \"name\": \"option-rec\",\n"
+ " \"code\": 6,\n"
+ " \"type\": \"record\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"uint16, uint16\",\n"
+ " \"encapsulate\": \"\",\n"
+ " \"space\": \"dns\"\n"
+ "},{\n"
+ " \"name\": \"option-foo\",\n"
+ " \"code\": 5,\n"
+ " \"type\": \"uint16\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"encapsulate\": \"\",\n"
+ " \"space\": \"isc\"\n"
+ "},{\n"
+ " \"name\": \"option-baz\",\n"
+ " \"code\": 6,\n"
+ " \"type\": \"uint16\",\n"
+ " \"array\": false,\n"
+ " \"record-types\": \"\",\n"
+ " \"encapsulate\": \"dns\",\n"
+ " \"space\": \"isc\"\n"
+ "}]\n";
+ isc::test::runToElementTest<CfgOptionDef>(expected, cfg);
+}
+
}
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcp/option_int.h>
#include <dhcp/option_space.h>
#include <dhcpsrv/cfg_option.h>
+#include <testutils/test_to_element.h>
#include <boost/foreach.hpp>
#include <boost/pointer_cast.hpp>
#include <gtest/gtest.h>
}
}
+// This test verifies that the unparse function returns what is expected.
+TEST_F(CfgOptionTest, unparse) {
+ CfgOption cfg;
+
+ // Add some options.
+ OptionPtr opt1(new Option(Option::V6, 100, OptionBuffer(4, 0x12)));
+ cfg.add(opt1, false, "dns");
+ OptionPtr opt2(new Option(Option::V6, 101, OptionBuffer(4, 12)));
+ OptionDescriptor desc2(opt2, false, "12, 12, 12, 12");
+ cfg.add(desc2, "dns");
+ OptionPtr opt3(new Option(Option::V6, D6O_STATUS_CODE, OptionBuffer(2, 0)));
+ cfg.add(opt3, false, DHCP6_OPTION_SPACE);
+ OptionPtr opt4(new Option(Option::V6, 100, OptionBuffer(4, 0x21)));
+ cfg.add(opt4, false, "vendor-1234");
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"code\": 100,\n"
+ " \"space\": \"dns\",\n"
+ " \"csv-format\": false,\n"
+ " \"data\": \"12121212\"\n"
+ "},{\n"
+ " \"code\": 101,\n"
+ " \"space\": \"dns\",\n"
+ " \"csv-format\": true,\n"
+ " \"data\": \"12, 12, 12, 12\"\n"
+ "},{\n"
+ " \"code\": 13,\n"
+ " \"name\": \"status-code\",\n"
+ " \"space\": \"dhcp6\",\n"
+ " \"csv-format\": false,\n"
+ " \"data\": \"0000\"\n"
+ "},{\n"
+ " \"code\": 100,\n"
+ " \"space\": \"vendor-1234\",\n"
+ " \"csv-format\": false,\n"
+ " \"data\": \"21212121\"\n"
+ "}]\n";
+ isc::test::runToElementTest<CfgOption>(expected, cfg);
+}
} // end of anonymous namespace
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <config.h>
#include <dhcp/dhcp6.h>
#include <dhcpsrv/cfg_rsoo.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
ASSERT_FALSE(rsoo.enabled(88));
}
+// This test verifies that the unparse function returns what is expected.
+TEST(CfgRSOOTest, unparse) {
+ CfgRSOO rsoo;
+ // option codes are put in strings
+ isc::test::runToElementTest<CfgRSOO>("[ \"65\" ]", rsoo);
+ // isc::test::runToElementTest<CfgRSOO>("[ 65 ]", rsoo);
+}
+
} // end of anonymous namespace
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 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
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
#include <vector>
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::test;
namespace {
EXPECT_EQ(subnet2, cfg.selectSubnet4o6(selector));
}
+// This test check if IPv4 subnets can be unparsed in a predictable way,
+TEST(CfgSubnets4Test, unparseSubnet) {
+ CfgSubnets4 cfg;
+
+ // Add some subnets.
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3, 123));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3, 124));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3, 125));
+ subnet1->allowClientClass("foo");
+ subnet2->setIface("lo");
+ subnet2->setRelayInfo(IOAddress("10.0.0.1"));
+ subnet3->setIface("eth1");
+
+ cfg.add(subnet1);
+ cfg.add(subnet2);
+ cfg.add(subnet3);
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"id\": 123,\n"
+ " \"subnet\": \"192.0.2.0/26\",\n"
+ " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
+ " \"interface\": \"\",\n"
+ " \"match-client-id\": true,\n"
+ " \"next-server\": \"0.0.0.0\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"valid-lifetime\": 3,\n"
+ " \"client-class\": \"foo\",\n"
+ " \"4o6-interface\": \"\",\n"
+ " \"4o6-interface-id\": \"\",\n"
+ " \"4o6-subnet\": \"\",\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"option-data\": [ ],\n"
+ " \"pools\": [ ]\n"
+ "},{\n"
+ " \"id\": 124,\n"
+ " \"subnet\": \"192.0.2.64/26\",\n"
+ " \"relay\": { \"ip-address\": \"10.0.0.1\" },\n"
+ " \"interface\": \"lo\",\n"
+ " \"match-client-id\": true,\n"
+ " \"next-server\": \"0.0.0.0\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"valid-lifetime\": 3,\n"
+ " \"4o6-interface\": \"\",\n"
+ " \"4o6-interface-id\": \"\",\n"
+ " \"4o6-subnet\": \"\",\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"option-data\": [ ],\n"
+ " \"pools\": [ ]\n"
+ "},{\n"
+ " \"id\": 125,\n"
+ " \"subnet\": \"192.0.2.128/26\",\n"
+ " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
+ " \"interface\": \"eth1\",\n"
+ " \"match-client-id\": true,\n"
+ " \"next-server\": \"0.0.0.0\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"valid-lifetime\": 3,\n"
+ " \"4o6-interface\": \"\",\n"
+ " \"4o6-interface-id\": \"\",\n"
+ " \"4o6-subnet\": \"\",\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"option-data\": [ ],\n"
+ " \"pools\": [ ]\n"
+ "} ]\n";
+ runToElementTest<CfgSubnets4>(expected, cfg);
+}
+
+// This test check if IPv4 pools can be unparsed in a predictable way,
+TEST(CfgSubnets4Test, unparsePool) {
+ CfgSubnets4 cfg;
+
+ // Add a subnet with pools
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3, 123));
+ Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.1"), IOAddress("192.0.2.10")));
+ Pool4Ptr pool2(new Pool4(IOAddress("192.0.2.64"), 26));
+
+ subnet->addPool(pool1);
+ subnet->addPool(pool2);
+ cfg.add(subnet);
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"id\": 123,\n"
+ " \"subnet\": \"192.0.2.0/24\",\n"
+ " \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
+ " \"interface\": \"\",\n"
+ " \"match-client-id\": true,\n"
+ " \"next-server\": \"0.0.0.0\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"valid-lifetime\": 3,\n"
+ " \"4o6-interface\": \"\",\n"
+ " \"4o6-interface-id\": \"\",\n"
+ " \"4o6-subnet\": \"\",\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"option-data\": [],\n"
+ " \"pools\": [\n"
+ " {\n"
+ " \"pool\": \"192.0.2.1-192.0.2.10\",\n"
+ " \"option-data\": []\n"
+ " },{\n"
+ " \"pool\": \"192.0.2.64/26\",\n"
+ " \"option-data\": []\n"
+ " }\n"
+ " ]\n"
+ "} ]\n";
+ runToElementTest<CfgSubnets4>(expected, cfg);
+}
} // end of anonymous namespace
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
#include <string>
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
+using namespace isc::test;
namespace {
EXPECT_THROW(cfg.add(subnet3), isc::dhcp::DuplicateSubnetID);
}
+// This test check if IPv6 subnets can be unparsed in a predictable way,
+TEST(CfgSubnets6Test, unparseSubnet) {
+ CfgSubnets6 cfg;
+
+ // Add some subnets.
+ Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"),
+ 48, 1, 2, 3, 4, 123));
+ Subnet6Ptr subnet2(new Subnet6(IOAddress("2001:db8:2::"),
+ 48, 1, 2, 3, 4, 124));
+ Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:3::"),
+ 48, 1, 2, 3, 4, 125));
+
+ OptionPtr ifaceid = generateInterfaceId("relay.eth0");
+ subnet1->setInterfaceId(ifaceid);
+ subnet1->allowClientClass("foo");
+ subnet2->setIface("lo");
+ subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
+ subnet3->setIface("eth1");
+
+ cfg.add(subnet1);
+ cfg.add(subnet2);
+ cfg.add(subnet3);
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"id\": 123,\n"
+ " \"subnet\": \"2001:db8:1::/48\",\n"
+ " \"relay\": { \"ip-address\": \"::\" },\n"
+ " \"interface-id\": \"relay.eth0\",\n"
+ " \"interface\": \"\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"preferred-lifetime\": 3,\n"
+ " \"valid-lifetime\": 4,\n"
+ " \"rapid-commit\": false,\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"client-class\": \"foo\",\n"
+ " \"pools\": [ ],\n"
+ " \"pd-pools\": [ ],\n"
+ " \"option-data\": [ ]\n"
+ "},{\n"
+ " \"id\": 124,\n"
+ " \"subnet\": \"2001:db8:2::/48\",\n"
+ " \"relay\": { \"ip-address\": \"2001:db8:ff::2\" },\n"
+ " \"interface-id\": \"\",\n"
+ " \"interface\": \"lo\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"preferred-lifetime\": 3,\n"
+ " \"valid-lifetime\": 4,\n"
+ " \"rapid-commit\": false,\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"pools\": [ ],\n"
+ " \"pd-pools\": [ ],\n"
+ " \"option-data\": [ ]\n"
+ "},{\n"
+ " \"id\": 125,\n"
+ " \"subnet\": \"2001:db8:3::/48\",\n"
+ " \"relay\": { \"ip-address\": \"::\" },\n"
+ " \"interface-id\": \"\",\n"
+ " \"interface\": \"eth1\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"preferred-lifetime\": 3,\n"
+ " \"valid-lifetime\": 4,\n"
+ " \"rapid-commit\": false,\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"pools\": [ ],\n"
+ " \"pd-pools\": [ ],\n"
+ " \"option-data\": [ ]\n"
+ "} ]\n";
+ runToElementTest<CfgSubnets6>(expected, cfg);
+}
+
+// This test check if IPv6 pools can be unparsed in a predictable way,
+TEST(CfgSubnets6Test, unparsePool) {
+ CfgSubnets6 cfg;
+
+ // Add a subnet with pools
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"),
+ 48, 1, 2, 3, 4, 123));
+ Pool6Ptr pool1(new Pool6(Lease::TYPE_NA,
+ IOAddress("2001:db8:1::100"),
+ IOAddress("2001:db8:1::199")));
+ Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
+
+ subnet->addPool(pool1);
+ subnet->addPool(pool2);
+ cfg.add(subnet);
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"id\": 123,\n"
+ " \"subnet\": \"2001:db8:1::/48\",\n"
+ " \"relay\": { \"ip-address\": \"::\" },\n"
+ " \"interface-id\": \"\",\n"
+ " \"interface\": \"\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"preferred-lifetime\": 3,\n"
+ " \"valid-lifetime\": 4,\n"
+ " \"rapid-commit\": false,\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"pools\": [\n"
+ " {\n"
+ " \"pool\": \"2001:db8:1::100-2001:db8:1::199\",\n"
+ " \"option-data\": [ ]\n"
+ " },{\n"
+ " \"pool\": \"2001:db8:1:1::/64\",\n"
+ " \"option-data\": [ ]\n"
+ " }\n"
+ " ],\n"
+ " \"pd-pools\": [ ],\n"
+ " \"option-data\": [ ]\n"
+ "} ]\n";
+ runToElementTest<CfgSubnets6>(expected, cfg);
+}
+
+// This test check if IPv6 prefix delegation pools can be unparsed
+// in a predictable way,
+TEST(CfgSubnets6Test, unparsePdPool) {
+ CfgSubnets6 cfg;
+
+ // Add a subnet with pd-pools
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"),
+ 48, 1, 2, 3, 4, 123));
+ Pool6Ptr pdpool1(new Pool6(Lease::TYPE_PD,
+ IOAddress("2001:db8:2::"), 48, 64));
+ Pool6Ptr pdpool2(new Pool6(IOAddress("2001:db8:3::"), 48, 56,
+ IOAddress("2001:db8:3::"), 64));
+
+ subnet->addPool(pdpool1);
+ subnet->addPool(pdpool2);
+ cfg.add(subnet);
+
+ // Unparse
+ std::string expected = "[\n"
+ "{\n"
+ " \"id\": 123,\n"
+ " \"subnet\": \"2001:db8:1::/48\",\n"
+ " \"relay\": { \"ip-address\": \"::\" },\n"
+ " \"interface-id\": \"\",\n"
+ " \"interface\": \"\",\n"
+ " \"renew-timer\": 1,\n"
+ " \"rebind-timer\": 2,\n"
+ " \"preferred-lifetime\": 3,\n"
+ " \"valid-lifetime\": 4,\n"
+ " \"rapid-commit\": false,\n"
+ " \"reservation-mode\": \"all\",\n"
+ " \"pools\": [ ],\n"
+ " \"pd-pools\": [\n"
+ " {\n"
+ " \"prefix\": \"2001:db8:2::\",\n"
+ " \"prefix-len\": 48,\n"
+ " \"delegated-len\": 64,\n"
+ " \"excluded-prefix\": \"::\",\n"
+ " \"excluded-prefix-len\": 0,\n"
+ " \"option-data\": [ ]\n"
+ " },{\n"
+ " \"prefix\": \"2001:db8:3::\",\n"
+ " \"prefix-len\": 48,\n"
+ " \"delegated-len\": 56,\n"
+ " \"excluded-prefix\": \"2001:db8:3::\",\n"
+ " \"excluded-prefix-len\": 64,\n"
+ " \"option-data\": [ ]\n"
+ " }\n"
+ " ],\n"
+ " \"option-data\": [ ]\n"
+ "} ]\n";
+ runToElementTest<CfgSubnets6>(expected, cfg);
+}
+
} // end of anonymous namespace
EXPECT_FALSE(CfgMgr::instance().isVerbose());
}
+// This test verifies that the address family can be set and obtained
+// from the configuration manager.
+TEST_F(CfgMgrTest, family) {
+ ASSERT_EQ(AF_INET, CfgMgr::instance().getFamily());
+
+ CfgMgr::instance().setFamily(AF_INET6);
+ ASSERT_EQ(AF_INET6, CfgMgr::instance().getFamily());
+
+ CfgMgr::instance().setFamily(AF_INET);
+ EXPECT_EQ(AF_INET, CfgMgr::instance().getFamily());
+}
+
// This test verifies that once the configuration is committed, statistics
// are updated appropriately.
TEST_F(CfgMgrTest, commitStats4) {
// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, nameAndExpressionClass) {
+ std::string test = "option[100].text == 'works right'";
std::string cfg_text =
"{ \n"
" \"name\": \"class_one\", \n"
- " \"test\": \"option[100].text == 'works right'\" \n"
+ " \"test\": \"" + test + "\" \n"
"} \n";
ClientClassDefPtr cclass;
ExpressionPtr match_expr = cclass->getMatchExpr();
ASSERT_TRUE(match_expr);
+ // Verify the original expression was saved.
+ EXPECT_EQ(test, cclass->getTest());
+
// Build a packet that will fail evaluation.
Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 123));
EXPECT_FALSE(evaluate(*match_expr, *pkt4));
// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, basicValidClass) {
+ std::string test = "option[100].text == 'booya'";
std::string cfg_text =
"{ \n"
" \"name\": \"MICROSOFT\", \n"
- " \"test\": \"option[100].text == 'booya'\", \n"
+ " \"test\": \"" + test + "\", \n"
" \"option-data\": [ \n"
" { \n"
" \"name\": \"domain-name-servers\", \n"
ExpressionPtr match_expr = cclass->getMatchExpr();
ASSERT_TRUE(match_expr);
+ // Verify the original expression was saved.
+ EXPECT_EQ(test, cclass->getTest());
+
// Build a packet that will fail evaluation.
Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 123));
EXPECT_FALSE(evaluate(*match_expr, *pkt4));
DhcpConfigError);
}
-
-// Verifies that a class with an unknown element, fails to parse.
-TEST_F(ClientClassDefParserTest, unknownElement) {
- std::string cfg_text =
- "{ \n"
- " \"name\": \"one\", \n"
- " \"bogus\": \"bad\" \n"
- "} \n";
-
- ClientClassDefPtr cclass;
- ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET),
- DhcpConfigError);
-}
-
// Verifies that a class with an invalid expression, fails to parse.
TEST_F(ClientClassDefParserTest, invalidExpression) {
std::string cfg_text =
DhcpConfigError);
}
-// Verifies that a class list containing an invalid class entry, fails to
-// parse.
-TEST_F(ClientClassDefListParserTest, invalidClass) {
- std::string cfg_text =
- "[ \n"
- " { \n"
- " \"name\": \"one\", \n"
- " \"bogus\": \"bad\" \n"
- " } \n"
- "] \n";
-
- ClientClassDictionaryPtr dictionary;
- ASSERT_THROW(dictionary = parseClientClassDefList(cfg_text, AF_INET6),
- DhcpConfigError);
-}
-
// Test verifies that without any class specified, the fixed fields have their
// default, empty value.
// @todo same with AF_INET6
-// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2017 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
#include <config.h>
#include <dhcpsrv/client_class_def.h>
#include <dhcp/option_space.h>
+#include <testutils/test_to_element.h>
#include <exceptions/exceptions.h>
#include <boost/scoped_ptr.hpp>
#include <asiolink/io_address.h>
using namespace isc::dhcp;
using namespace isc::util;
using namespace isc::asiolink;
+using namespace isc::test;
using namespace isc;
namespace {
// Verify we get an empty collection of cfg_option
cfg_option = cclass->getCfgOption();
ASSERT_TRUE(cfg_option);
- //EXPECT_EQ(0, cfg_option->size());
+ EXPECT_TRUE(cfg_option->empty());
}
// Tests options operations. Note we just do the basics
// Verify that we can add classes with both addClass variants
// First addClass(name, expression, cfg_option)
- ASSERT_NO_THROW(dictionary->addClass("cc1", expr, cfg_option));
- ASSERT_NO_THROW(dictionary->addClass("cc2", expr, cfg_option));
+ ASSERT_NO_THROW(dictionary->addClass("cc1", expr, "", cfg_option));
+ ASSERT_NO_THROW(dictionary->addClass("cc2", expr, "", cfg_option));
// Verify duplicate add attempt throws
- ASSERT_THROW(dictionary->addClass("cc2", expr, cfg_option),
+ ASSERT_THROW(dictionary->addClass("cc2", expr, "", cfg_option),
DuplicateClientClassDef);
// Verify that you cannot add a class with no name.
- ASSERT_THROW(dictionary->addClass("", expr, cfg_option), BadValue);
+ ASSERT_THROW(dictionary->addClass("", expr, "", cfg_option), BadValue);
// Now with addClass(class pointer)
ASSERT_NO_THROW(cclass.reset(new ClientClassDef("cc3", expr, cfg_option)));
CfgOptionPtr options;
dictionary.reset(new ClientClassDictionary());
- ASSERT_NO_THROW(dictionary->addClass("one", expr, options));
- ASSERT_NO_THROW(dictionary->addClass("two", expr, options));
- ASSERT_NO_THROW(dictionary->addClass("three", expr, options));
+ ASSERT_NO_THROW(dictionary->addClass("one", expr, "", options));
+ ASSERT_NO_THROW(dictionary->addClass("two", expr, "", options));
+ ASSERT_NO_THROW(dictionary->addClass("three", expr, "", options));
// Copy constructor should succeed.
ASSERT_NO_THROW(dictionary2.reset(new ClientClassDictionary(*dictionary)));
}
+// Verifies the unparse method of option class definitions
+TEST(ClientClassDef, unparseDef) {
+ boost::scoped_ptr<ClientClassDef> cclass;
+
+ // Get a client class definition and fill it
+ std::string name = "class1";
+ ExpressionPtr expr;
+ ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
+ std::string test = "option[12].text == 'foo'";
+ cclass->setTest(test);
+ std::string next_server = "1.2.3.4";
+ cclass->setNextServer(IOAddress(next_server));
+ std::string sname = "my-server.example.com";
+ cclass->setSname(sname);
+ std::string filename = "/boot/kernel";
+ cclass->setFilename(filename);
+
+ // Unparse it
+ std::string expected = "{\n"
+ "\"name\": \"" + name + "\",\n"
+ "\"test\": \"" + test + "\",\n"
+ "\"next-server\": \"" + next_server + "\",\n"
+ "\"server-hostname\": \"" + sname + "\",\n"
+ "\"boot-file-name\": \"" + filename + "\",\n"
+ "\"option-data\": [ ] }\n";
+ runToElementTest<ClientClassDef>(expected, *cclass);
+}
+
+// Verifies the unparse method of client class dictionaries
+TEST(ClientClassDictionary, unparseDict) {
+ ClientClassDictionaryPtr dictionary;
+ ExpressionPtr expr;
+ CfgOptionPtr options;
+
+ // Get a client class dictionary and fill it
+ dictionary.reset(new ClientClassDictionary());
+ ASSERT_NO_THROW(dictionary->addClass("one", expr, "", options));
+ ASSERT_NO_THROW(dictionary->addClass("two", expr, "", options));
+ ASSERT_NO_THROW(dictionary->addClass("three", expr, "", options));
+
+ // Unparse it
+ auto add_defaults =
+ [](std::string name) {
+ return ("{\n"
+ "\"name\": \"" + name + "\",\n"
+ "\"test\": \"\",\n"
+ "\"next-server\": \"0.0.0.0\",\n"
+ "\"server-hostname\": \"\",\n"
+ "\"boot-file-name\": \"\",\n"
+ "\"option-data\": [ ] }");
+ };
+
+ std::string expected = "[\n" +
+ add_defaults("one") + ",\n" +
+ add_defaults("two") + ",\n" +
+ add_defaults("three") + "]\n";
+
+ runToElementTest<ClientClassDictionary>(expected, *dictionary);
+}
+
} // end of anonymous namespace
-// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2017 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
#include <dhcp/option4_client_fqdn.h>
#include <dhcp/option6_client_fqdn.h>
#include <dhcpsrv/d2_client_mgr.h>
+#include <testutils/test_to_element.h>
#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::util;
+using namespace isc::test;
using namespace isc;
namespace {
ASSERT_NO_THROW(std::cout << "toText test:" << std::endl <<
*d2_client_config << std::endl);
+ // Verify what toElement returns.
+ std::string expected = "{\n"
+ "\"enable-updates\": true,\n"
+ "\"server-ip\": \"127.0.0.1\",\n"
+ "\"server-port\": 477,\n"
+ "\"sender-ip\": \"127.0.0.1\",\n"
+ "\"sender-port\": 478,\n"
+ "\"max-queue-size\": 2048,\n"
+ "\"ncr-protocol\": \"UDP\",\n"
+ "\"ncr-format\": \"JSON\",\n"
+ "\"always-include-fqdn\": true,\n"
+ "\"override-no-update\": true,\n"
+ "\"override-client-update\": true,\n"
+ "\"replace-client-name\": \"when-present\",\n"
+ "\"generated-prefix\": \"the_prefix\",\n"
+ "\"qualifying-suffix\": \"the.suffix.\"\n"
+ "}\n";
+ runToElementTest<D2ClientConfig>(expected, *d2_client_config);
+
// Verify that constructor does not allow use of NCR_TCP.
/// @todo obviously this becomes invalid once TCP is supported.
ASSERT_THROW(d2_client_config.reset(new
#include <exceptions/exceptions.h>
#include <hooks/hooks_parser.h>
#include <hooks/hooks_manager.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
#include <boost/foreach.hpp>
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::hooks;
+using namespace isc::test;
namespace {
return (cnt);
}
+ /// This table defines default values for option definitions in DHCPv6
+ static const SimpleDefaults OPTION6_DEF_DEFAULTS;
+
+ /// This table defines default values for option definitions in DHCPv4
+ static const SimpleDefaults OPTION4_DEF_DEFAULTS;
+
+ /// This table defines default values for options in DHCPv6
+ static const SimpleDefaults OPTION6_DEFAULTS;
+
+ /// This table defines default values for options in DHCPv4
+ static const SimpleDefaults OPTION4_DEFAULTS;
+
+ /// This table defines default values for both DHCPv4 and DHCPv6
+ static const SimpleDefaults GLOBAL6_DEFAULTS;
+
/// @brief sets all default values for DHCPv4 and DHCPv6
///
/// This function largely duplicates what SimpleParser4 and SimpleParser6 classes
/// @param config configuration structure to be filled with default values
/// @param v6 true = DHCPv6, false = DHCPv4
void setAllDefaults(ElementPtr config, bool v6) {
- /// This table defines default values for option definitions in DHCPv6
- const SimpleDefaults OPTION6_DEF_DEFAULTS = {
- { "record-types", Element::string, ""},
- { "space", Element::string, "dhcp6"},
- { "array", Element::boolean, "false"},
- { "encapsulate", Element::string, "" }
- };
-
- /// This table defines default values for option definitions in DHCPv4
- const SimpleDefaults OPTION4_DEF_DEFAULTS = {
- { "record-types", Element::string, ""},
- { "space", Element::string, "dhcp4"},
- { "array", Element::boolean, "false"},
- { "encapsulate", Element::string, "" }
- };
-
- /// This table defines default values for options in DHCPv6
- const SimpleDefaults OPTION6_DEFAULTS = {
- { "space", Element::string, "dhcp6"},
- { "csv-format", Element::boolean, "true"},
- { "encapsulate", Element::string, "" }
- };
-
- /// This table defines default values for options in DHCPv4
- const SimpleDefaults OPTION4_DEFAULTS = {
- { "space", Element::string, "dhcp4"},
- { "csv-format", Element::boolean, "true"},
- { "encapsulate", Element::string, "" }
- };
-
- /// This table defines default values for both DHCPv4 and DHCPv6
- const SimpleDefaults GLOBAL6_DEFAULTS = {
- { "renew-timer", Element::integer, "900" },
- { "rebind-timer", Element::integer, "1800" },
- { "preferred-lifetime", Element::integer, "3600" },
- { "valid-lifetime", Element::integer, "7200" }
- };
-
if (v6) {
setAllDefaults(config, GLOBAL6_DEFAULTS, OPTION6_DEFAULTS,
OPTION6_DEF_DEFAULTS);
std::string error_text_;
};
+/// This table defines default values for option definitions in DHCPv6
+const SimpleDefaults ParseConfigTest::OPTION6_DEF_DEFAULTS = {
+ { "record-types", Element::string, ""},
+ { "space", Element::string, "dhcp6"},
+ { "array", Element::boolean, "false"},
+ { "encapsulate", Element::string, "" }
+};
+
+/// This table defines default values for option definitions in DHCPv4
+const SimpleDefaults ParseConfigTest::OPTION4_DEF_DEFAULTS = {
+ { "record-types", Element::string, ""},
+ { "space", Element::string, "dhcp4"},
+ { "array", Element::boolean, "false"},
+ { "encapsulate", Element::string, "" }
+};
+
+/// This table defines default values for options in DHCPv6
+const SimpleDefaults ParseConfigTest::OPTION6_DEFAULTS = {
+ { "space", Element::string, "dhcp6"},
+ { "csv-format", Element::boolean, "true"}
+};
+
+/// This table defines default values for options in DHCPv4
+const SimpleDefaults ParseConfigTest::OPTION4_DEFAULTS = {
+ { "space", Element::string, "dhcp4"},
+ { "csv-format", Element::boolean, "true"}
+};
+
+/// This table defines default values for both DHCPv4 and DHCPv6
+const SimpleDefaults ParseConfigTest::GLOBAL6_DEFAULTS = {
+ { "renew-timer", Element::integer, "900" },
+ { "rebind-timer", Element::integer, "1800" },
+ { "preferred-lifetime", Element::integer, "3600" },
+ { "valid-lifetime", Element::integer, "7200" }
+};
+
+/// @brief Option configuration class
+///
+/// This class handles option-def and option-data which can be recovered
+/// using the toElement() method
+class CfgOptionsTest : public CfgToElement {
+public:
+ /// @brief Constructor
+ ///
+ /// @param cfg the server configuration where to get option-{def,data}
+ CfgOptionsTest(SrvConfigPtr cfg) :
+ cfg_option_def_(cfg->getCfgOptionDef()),
+ cfg_option_(cfg->getCfgOption()) { }
+
+ /// @brief Unparse a configuration objet
+ ///
+ /// @return a pointer to unparsed configuration (a map with
+ /// not empty option-def and option-data lists)
+ ElementPtr toElement() const {
+ ElementPtr result = Element::createMap();
+ // Set option-def
+ ConstElementPtr option_def = cfg_option_def_->toElement();
+ if (!option_def->empty()) {
+ result->set("option-def", option_def);
+ }
+ // Set option-data
+ ConstElementPtr option_data = cfg_option_->toElement();
+ if (!option_data->empty()) {
+ result->set("option-data", option_data);
+ }
+ return (result);
+ }
+
+ /// @brief Run a toElement test (Element version)
+ ///
+ /// Use the runToElementTest template but add defaults to the config
+ ///
+ /// @param family the address family
+ /// @param config the expected result without defaults
+ void runCfgOptionsTest(uint16_t family, ConstElementPtr expected) {
+ ConstElementPtr option_def = expected->get("option-def");
+ if (option_def) {
+ SimpleParser::setListDefaults(option_def,
+ family == AF_INET ?
+ ParseConfigTest::OPTION4_DEF_DEFAULTS :
+ ParseConfigTest::OPTION6_DEF_DEFAULTS);
+ }
+ ConstElementPtr option_data = expected->get("option-data");
+ if (option_data) {
+ SimpleParser::setListDefaults(option_data,
+ family == AF_INET ?
+ ParseConfigTest::OPTION4_DEFAULTS :
+ ParseConfigTest::OPTION6_DEFAULTS);
+ }
+ runToElementTest<CfgOptionsTest>(expected, *this);
+ }
+
+ /// @brief Run a toElement test
+ ///
+ /// Use the runToElementTest template but add defaults to the config
+ ///
+ /// @param family the address family
+ /// @param expected the expected result without defaults
+ void runCfgOptionsTest(uint16_t family, std::string config) {
+ ConstElementPtr json;
+ ASSERT_NO_THROW(json = Element::fromJSON(config)) << config;
+ ConstElementPtr option_def = json->get("option-def");
+ if (option_def) {
+ SimpleParser::setListDefaults(option_def,
+ family == AF_INET ?
+ ParseConfigTest::OPTION4_DEF_DEFAULTS :
+ ParseConfigTest::OPTION6_DEF_DEFAULTS);
+ }
+ ConstElementPtr option_data = json->get("option-data");
+ if (option_data) {
+ SimpleParser::setListDefaults(option_data,
+ family == AF_INET ?
+ ParseConfigTest::OPTION4_DEFAULTS :
+ ParseConfigTest::OPTION6_DEFAULTS);
+ }
+ runToElementTest<CfgOptionsTest>(json, *this);
+ }
+
+private:
+ /// @brief Pointer to option definitions configuration.
+ CfgOptionDefPtr cfg_option_def_;
+
+ /// @brief Reference to options (data) configuration.
+ CfgOptionPtr cfg_option_;
+};
+
/// @brief Check basic parsing of option definitions.
///
/// Note that this tests basic operation of the OptionDefinitionListParser and
// but the values should be equal.
EXPECT_TRUE(def_libdhcp != def);
EXPECT_TRUE(*def_libdhcp == *def);
+
+ // Check if it can be unparsed.
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, config);
}
/// @brief Check minimal parsing of option definitions.
EXPECT_FALSE(def->getArrayType());
EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def->getType());
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
+
+ // Check if it can be unparsed.
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, config);
}
/// @brief Check parsing of option definitions using default dhcp6 space.
EXPECT_FALSE(def->getArrayType());
EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, def->getType());
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
+
+ // Check if it can be unparsed.
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, config);
}
/// @brief Check basic parsing of options.
std::string val = "type=00100, len=00004: 192.0.2.0 (ipv4-address)";
EXPECT_EQ(val, opt_ptr->toText());
+
+ // Check if it can be unparsed.
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, config);
}
/// @brief Check minimal parsing of options.
std::string val = "type=00100, len=00004: 192.0.2.0 (ipv4-address)";
EXPECT_EQ(val, opt_ptr->toText());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(100));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
/// @brief Check parsing of options with escape characters.
EXPECT_EQ(Option::OPTION4_HDR_LEN + 23, buf.getLength());
EXPECT_TRUE(0 == memcmp(buf.getData(), exp, 25));
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(DHO_BOOT_FILE_NAME));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This test checks behavior of the configuration parser for option data
ASSERT_TRUE(addr_opt);
EXPECT_EQ("192.0.2.0", addr_opt->readAddress().toText());
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, config);
+
// Explicitly enable csv-format.
CfgMgr::instance().clear();
config =
ASSERT_TRUE(addr_opt);
EXPECT_EQ("192.0.2.0", addr_opt->readAddress().toText());
+ // To make runToElementTest to work the csv-format must be removed...
+
// Explicitly disable csv-format and use hex instead.
CfgMgr::instance().clear();
config =
OptionCustom>(getOptionPtr(DHCP4_OPTION_SPACE, 16));
ASSERT_TRUE(addr_opt);
EXPECT_EQ("192.0.2.0", addr_opt->readAddress().toText());
+
+ CfgOptionsTest cfg2(CfgMgr::instance().getStagingCfg());
+ cfg2.runCfgOptionsTest(family_, config);
}
// This test verifies that definitions of standard encapsulated
EXPECT_EQ("192.0.2.0", ipv4_prefix.toText());
EXPECT_EQ(64, ipv6_prefix.first.asUnsigned());
EXPECT_EQ("2001:db8:1::", ipv6_prefix.second.toText());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(D6O_S46_RULE));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This test checks behavior of the configuration parser for option data
ASSERT_EQ(1, opt->getData().size());
EXPECT_EQ(0, opt->getData()[0]);
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->remove("name");
+ opt_data->set("data", Element::create(std::string("00")));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
+
CfgMgr::instance().clear();
// When csv-format is not specified, the parser will check if the definition
// exists or not. Since there is no definition, the parser will accept the
EXPECT_EQ(0x12, opt->getData()[0]);
EXPECT_EQ(0x34, opt->getData()[1]);
EXPECT_EQ(0x56, opt->getData()[2]);
+
+ expected = Element::fromJSON(config);
+ opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->remove("name");
+ CfgOptionsTest cfg2(CfgMgr::instance().getStagingCfg());
+ cfg2.runCfgOptionsTest(family_, expected);
}
// This test verifies that the option name is not mandatory, if the option
ASSERT_TRUE(opt);
ASSERT_EQ(1, opt->getAddresses().size());
EXPECT_EQ( "2001:db8:1::1", opt->getAddresses()[0].toText());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("name", Element::create(std::string("dns-servers")));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This test verifies that the option code is not mandatory, if the option
ASSERT_TRUE(opt);
ASSERT_EQ(1, opt->getAddresses().size());
EXPECT_EQ( "2001:db8:1::1", opt->getAddresses()[0].toText());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(D6O_NAME_SERVERS));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This test verifies that the option data configuration with a minimal
ASSERT_EQ(1, opt->getAddresses().size());
EXPECT_EQ( "2001:db8:1::10", opt->getAddresses()[0].toText());
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(D6O_NAME_SERVERS));
+ opt_data->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
+
CfgMgr::instance().clear();
// This time using an option code.
config =
ASSERT_TRUE(opt);
ASSERT_EQ(1, opt->getAddresses().size());
EXPECT_EQ( "2001:db8:1::20", opt->getAddresses()[0].toText());
+
+ expected = Element::fromJSON(config);
+ opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("name", Element::create(std::string("dns-servers")));
+ opt_data->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
+ CfgOptionsTest cfg2(CfgMgr::instance().getStagingCfg());
+ cfg2.runCfgOptionsTest(family_, expected);
}
// This test verifies that the option data configuration with a minimal
EXPECT_EQ("2001:db8:1::10", opt->getAddresses()[0].toText());
EXPECT_EQ("2001:db8:1::123", opt->getAddresses()[1].toText());
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(2345));
+ opt_data->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
+
CfgMgr::instance().clear();
// Do the same test but now use an option code.
config =
EXPECT_EQ("2001:db8:1::10", opt->getAddresses()[0].toText());
EXPECT_EQ("2001:db8:1::123", opt->getAddresses()[1].toText());
+ expected = Element::fromJSON(config);
+ opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("name", Element::create(std::string("foo-name")));
+ opt_data->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
+ CfgOptionsTest cfg2(CfgMgr::instance().getStagingCfg());
+ cfg2.runCfgOptionsTest(family_, expected);
}
// This test verifies an empty option data configuration is supported.
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, D6O_DHCPV4_O_DHCPV6_SERVER));
ASSERT_TRUE(opt);
ASSERT_EQ(0, opt->getAddresses().size());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(D6O_DHCPV4_O_DHCPV6_SERVER));
+ opt_data->set("space", Element::create(std::string(DHCP6_OPTION_SPACE)));
+ opt_data->set("csv-format", Element::create(false));
+ opt_data->set("data", Element::create(std::string("")));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This test verifies an option data without suboptions is supported
const OptionPtr opt = getOptionPtr(DHCP4_OPTION_SPACE, DHO_VENDOR_ENCAPSULATED_OPTIONS);
ASSERT_TRUE(opt);
ASSERT_EQ(0, opt->getOptions().size());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->set("code", Element::create(DHO_VENDOR_ENCAPSULATED_OPTIONS));
+ opt_data->set("space", Element::create(std::string(DHCP4_OPTION_SPACE)));
+ opt_data->set("csv-format", Element::create(false));
+ opt_data->set("data", Element::create(std::string("")));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
// This tests option-data in CSV format and embedded commas.
// Verify that the option data is correct.
string val = "EST5EDT4,M3.2.0/02:00,M11.1.0/02:00";
EXPECT_EQ(val, opt_str->getValue());
+
+ ElementPtr expected = Element::fromJSON(config);
+ ElementPtr opt_data = expected->get("option-data")->getNonConst(0);
+ opt_data->remove("csv-format");
+ opt_data->set("name", Element::create(std::string("new-posix-timezone")));
+ CfgOptionsTest cfg(CfgMgr::instance().getStagingCfg());
+ cfg.runCfgOptionsTest(family_, expected);
}
/// The next set of tests check basic operation of the HooksLibrariesParser.
const int rcode = parseConfiguration(config);
ASSERT_TRUE(rcode == 0) << error_text_;
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// Check that the parser recorded nothing.
isc::hooks::HookLibsCollection libraries = getLibraries();
EXPECT_TRUE(libraries.empty());
const int rcode = parseConfiguration(config);
ASSERT_TRUE(rcode == 0) << error_text_;
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// Check that the parser recorded a single library.
isc::hooks::HookLibsCollection libraries = getLibraries();
ASSERT_EQ(1, libraries.size());
const int rcode = parseConfiguration(config);
ASSERT_TRUE(rcode == 0) << error_text_;
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// Check that the parser recorded two libraries in the expected order.
isc::hooks::HookLibsCollection libraries = getLibraries();
ASSERT_EQ(2, libraries.size());
int rcode = parseConfiguration(config);
ASSERT_TRUE(rcode == 0) << error_text_;
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// The previous test shows that the parser correctly recorded the two
// libraries and that they loaded correctly.
// The list has not changed between the two parse operations. However,
// the paramters (or the files they could point to) could have
// changed, so the libraries are reloaded anyway.
+ const HooksConfig& cfg2 =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg2);
isc::hooks::HookLibsCollection libraries = getLibraries();
ASSERT_EQ(2, libraries.size());
EXPECT_EQ(CALLOUT_LIBRARY_1, libraries[0].first);
rcode = parseConfiguration(config);
ASSERT_TRUE(rcode == 0) << error_text_;
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// The list has changed, and this is what we should see.
isc::hooks::HookLibsCollection libraries = getLibraries();
EXPECT_TRUE(libraries.empty());
const int rcode = parseConfiguration(config);
ASSERT_EQ(0, rcode);
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected =
+ Element::fromJSON(config)->get("hooks-libraries"));
+ ASSERT_TRUE(expected);
+ const HooksConfig& cfg =
+ CfgMgr::instance().getStagingCfg()->getHooksConfig();
+ runToElementTest<HooksConfig>(expected, cfg);
+
// Check that the parser recorded the names.
isc::hooks::HookLibsCollection libraries = getLibraries();
ASSERT_EQ(3, libraries.size());
EXPECT_EQ("test.prefix", d2_client_config->getGeneratedPrefix());
EXPECT_EQ("test.suffix.", d2_client_config->getQualifyingSuffix());
+ // Verify that the configuration object unparses.
+ ConstElementPtr expected;
+ ASSERT_NO_THROW(expected = Element::fromJSON(config_str)->get("dhcp-ddns"));
+ ASSERT_TRUE(expected);
+ runToElementTest<D2ClientConfig>(expected, *d2_client_config);
+
// Another valid Configuration string.
// This one is disabled, has IPV6 server ip, control flags false,
// empty prefix/suffix
EXPECT_EQ(D2ClientConfig::RCM_NEVER, d2_client_config->getReplaceClientNameMode());
EXPECT_EQ("", d2_client_config->getGeneratedPrefix());
EXPECT_EQ("", d2_client_config->getQualifyingSuffix());
+
+ ASSERT_NO_THROW(expected = Element::fromJSON(config_str2)->get("dhcp-ddns"));
+ ASSERT_TRUE(expected);
+ runToElementTest<D2ClientConfig>(expected, *d2_client_config);
}
/// @brief Checks that D2 client can be configured with enable flag of
#include <dhcpsrv/parsers/duid_config_parser.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/testutils/config_result_check.h>
+#include <testutils/test_to_element.h>
#include <util/encode/hex.h>
#include <gtest/gtest.h>
#include <limits>
// This test verifies that all parameters can be set.
TEST_F(DUIDConfigParserTest, allParameters) {
// Set all parameters.
- ASSERT_NO_THROW(build("{ \"type\": \"EN\","
- " \"identifier\": \"ABCDEF\","
- " \"time\": 100,"
- " \"htype\": 8,"
- " \"enterprise-id\": 2024,"
- " \"persist\": false"
- "}"));
+ std::string config = "{"
+ " \"type\": \"EN\","
+ " \"identifier\": \"ABCDEF\","
+ " \"time\": 100,"
+ " \"htype\": 8,"
+ " \"enterprise-id\": 2024,"
+ " \"persist\": false"
+ "}";
+ ASSERT_NO_THROW(build(config));
// Verify that parameters have been set correctly.
ASSERT_TRUE(cfg_duid_);
EXPECT_EQ(100, cfg_duid_->getTime());
EXPECT_EQ(2024, cfg_duid_->getEnterpriseId());
EXPECT_FALSE(cfg_duid_->persist());
+
+ // Check the config can be got back.
+ isc::test::runToElementTest<CfgDUID>(config, *cfg_duid_);
}
// Test out of range values for time.
EXPECT_EQ(20, cfg->getUnwarnedReclaimCycles());
}
-// This test verifies that the exception is thrown if unsupported
-// parameter is specified.
-TEST_F(ExpirationConfigParserTest, invalidParameter) {
- addParam("reclaim-timer-wait-time", 20);
- addParam("invalid-parameter", 20);
-
- EXPECT_THROW(renderConfig(), DhcpConfigError);
-}
-
// This test verifies that negative parameter values are not allowed.
TEST_F(ExpirationConfigParserTest, outOfRangeValues) {
testOutOfRange("reclaim-timer-wait-time",
-// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015,2017 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
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/parsers/ifaces_config_parser.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
+using namespace isc::test;
namespace {
CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
+ // Check it can be unparsed.
+ runToElementTest<CfgIface>(config, *cfg_iface);
+
// Open sockets according to the parsed configuration.
SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
ASSERT_TRUE(cfg);
cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
+ runToElementTest<CfgIface>(config, *cfg_iface);
+
cfg = CfgMgr::instance().getStagingCfg();
ASSERT_NO_THROW(cfg->getCfgIface()->openSockets(AF_INET, 10000));
CfgIface cfg_ref;
// Configuration with a datagram socket selected.
- std::string config = "{ ""\"interfaces\": [ ],"
+ std::string config = "{ \"interfaces\": [ ],"
" \"dhcp-socket-type\": \"udp\" }";
ElementPtr config_element = Element::fromJSON(config);
CfgIfacePtr cfg_iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
ASSERT_NO_THROW(parser.parse(cfg_iface, config_element));
+ // Check it can be unparsed.
+ runToElementTest<CfgIface>(config, *cfg_iface);
+
// Compare the resulting configuration with a reference
// configuration using the raw socket.
SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg();
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015,2017 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
#include <config.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/logging_info.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc::dhcp;
+using namespace isc::test;
namespace {
ASSERT_EQ(1, info_non_verbose.destinations_.size());
EXPECT_EQ("stdout", info_non_verbose.destinations_[0].output_);
+ std::string header = "{\n"
+ "\"name\": \"kea\",\n"
+ "\"output_options\": [ {\n"
+ " \"output\": \"stdout\",\n \"maxsize\": 204800,\n"
+ " \"maxver\": 1,\n \"flush\": true } ],\n"
+ "\"severity\": \"";
+ std::string dbglvl = "\",\n\"debuglevel\": ";
+ std::string trailer = "\n}\n";
+ std::string expected = header + "INFO" + dbglvl + "0" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_non_verbose);
+
CfgMgr::instance().setVerbose(true);
LoggingInfo info_verbose;
EXPECT_EQ("kea", info_verbose.name_);
ASSERT_EQ(1, info_verbose.destinations_.size());
EXPECT_EQ("stdout", info_verbose.destinations_[0].output_);
+
+ expected = header + "DEBUG" + dbglvl + "99" + trailer;
+ runToElementTest<LoggingInfo>(expected, info_verbose);
}
// Checks if (in)equality operators work for LoggingInfo.
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/srv_config.h>
#include <dhcpsrv/subnet.h>
+#include <testutils/test_to_element.h>
#include <gtest/gtest.h>
using namespace isc::asiolink;
}
// Build our reference dictionary of client classes
- ref_dictionary_->addClass("cc1", ExpressionPtr(), CfgOptionPtr());
- ref_dictionary_->addClass("cc2", ExpressionPtr(), CfgOptionPtr());
- ref_dictionary_->addClass("cc3", ExpressionPtr(), CfgOptionPtr());
+ ref_dictionary_->addClass("cc1", ExpressionPtr(), "", CfgOptionPtr());
+ ref_dictionary_->addClass("cc2", ExpressionPtr(), "", CfgOptionPtr());
+ ref_dictionary_->addClass("cc3", ExpressionPtr(), "", CfgOptionPtr());
}
EXPECT_TRUE(copied.getHooksConfig().equal(conf.getHooksConfig()));
}
+// Verifies that the toElement method works well (tests limited to
+// direct parameters)
+TEST_F(SrvConfigTest, unparse) {
+ SrvConfig conf(32);
+ std::string header4 = "{\n\"Dhcp4\": {\n";
+ std::string header6 = "{\n\"Dhcp6\": {\n";
+
+ std::string defaults = "\"decline-probation-period\": 0,\n";
+ defaults += "\"dhcp4o6-port\": 0,\n";
+ defaults += "\"interfaces-config\": { \"interfaces\": [ ] },\n";
+ defaults += "\"option-def\": [ ],\n";
+ defaults += "\"option-data\": [ ],\n";
+ defaults += "\"expired-leases-processing\": ";
+ defaults += conf.getCfgExpiration()->toElement()->str() + ",\n";
+ defaults += "\"lease-database\": { \"type\": \"memfile\" },\n";
+ defaults += "\"hosts-database\": { },\n";
+ defaults += "\"client-classes\": [ ],\n";
+ defaults += "\"hooks-libraries\": [ ],\n";
+ defaults += "\"dhcp-ddns\": \n";
+ defaults += conf.getD2ClientConfig()->toElement()->str() + ",\n";
+
+ std::string defaults4 = "\"echo-client-id\": true,\n";
+ defaults4 += "\"subnet4\": [ ],\n";
+ defaults4 += "\"host-reservation-identifiers\": ";
+ defaults4 += "[ \"hw-address\", \"duid\", \"circuit-id\" ],\n";
+
+ std::string defaults6 = "\"relay-supplied-options\": [ \"65\" ],\n";
+ defaults6 += "\"subnet6\": [ ],\n";
+ defaults6 += "\"server-id\": ";
+ defaults6 += conf.getCfgDUID()->toElement()->str() + ",\n";
+ defaults6 += "\"host-reservation-identifiers\": ";
+ defaults6 += "[ \"hw-address\", \"duid\" ],\n";
+ defaults6 += "\"dhcp4o6-port\": 0,\n";
+ defaults6 += "\"mac-sources\": [ \"any\" ]\n";
+
+ std::string params = "\"echo-client-id\": true,\n";
+ params += "\"dhcp4o6-port\": 0\n";
+ std::string trailer = "}\n}\n";
+
+ // Verify DHCPv4
+ CfgMgr::instance().setFamily(AF_INET);
+ isc::test::runToElementTest<SrvConfig>
+ (header4 + defaults + defaults4 + params + trailer, conf);
+
+ // Verify DHCPv6
+ CfgMgr::instance().setFamily(AF_INET6);
+ isc::test::runToElementTest<SrvConfig>
+ (header6 + defaults + defaults6 + trailer, conf);
+
+ // Verify direct non-default parameters
+ CfgMgr::instance().setFamily(AF_INET);
+ conf.setEchoClientId(false);
+ conf.setDhcp4o6Port(6767);
+ params = "\"echo-client-id\": false,\n";
+ params += "\"dhcp4o6-port\": 6767\n";
+ isc::test::runToElementTest<SrvConfig>
+ (header4 + defaults + defaults4 + params + trailer, conf);
+}
+
} // end of anonymous namespace
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015,2017 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
three_classes.insert("baz");
// No class restrictions defined, any client should be supported
+ EXPECT_EQ(0, subnet->getClientClasses().size());
EXPECT_TRUE(subnet->clientSupported(no_class));
EXPECT_TRUE(subnet->clientSupported(foo_class));
EXPECT_TRUE(subnet->clientSupported(bar_class));
// Let's allow only clients belonging to "bar" class.
subnet->allowClientClass("bar");
+ EXPECT_EQ(1, subnet->getClientClasses().size());
EXPECT_FALSE(subnet->clientSupported(no_class));
EXPECT_FALSE(subnet->clientSupported(foo_class));
bar_class.insert("bar");
// No class restrictions defined, any client should be supported
+ EXPECT_EQ(0, subnet->getClientClasses().size());
EXPECT_TRUE(subnet->clientSupported(no_class));
EXPECT_TRUE(subnet->clientSupported(foo_class));
EXPECT_TRUE(subnet->clientSupported(bar_class));
// Let's allow clients belonging to "bar" or "foo" class.
subnet->allowClientClass("bar");
subnet->allowClientClass("foo");
+ EXPECT_EQ(2, subnet->getClientClasses().size());
// Class-less clients are to be rejected.
EXPECT_FALSE(subnet->clientSupported(no_class));
three_classes.insert("baz");
// No class restrictions defined, any client should be supported
+ EXPECT_EQ(0, subnet->getClientClasses().size());
EXPECT_TRUE(subnet->clientSupported(no_class));
EXPECT_TRUE(subnet->clientSupported(foo_class));
EXPECT_TRUE(subnet->clientSupported(bar_class));
// Let's allow only clients belonging to "bar" class.
subnet->allowClientClass("bar");
+ EXPECT_EQ(1, subnet->getClientClasses().size());
EXPECT_FALSE(subnet->clientSupported(no_class));
EXPECT_FALSE(subnet->clientSupported(foo_class));
bar_class.insert("bar");
// No class restrictions defined, any client should be supported
+ EXPECT_EQ(0, subnet->getClientClasses().size());
EXPECT_TRUE(subnet->clientSupported(no_class));
EXPECT_TRUE(subnet->clientSupported(foo_class));
EXPECT_TRUE(subnet->clientSupported(bar_class));
// Let's allow only clients belonging to "foo" or "bar" class.
subnet->allowClientClass("foo");
subnet->allowClientClass("bar");
+ EXPECT_EQ(2, subnet->getClientClasses().size());
// Class-less clients are to be rejected.
EXPECT_FALSE(subnet->clientSupported(no_class));
ElementPtr map = Element::createMap();
// Set the library name
map->set("library", Element::create(hl->first));
- // Set parameters
+ // Set parameters (not set vs set empty map)
if (!isNull(hl->second)) {
map->set("parameters", hl->second);
- } else {
- map->set("parameters", Element::createMap());
}
// Push to the list
result->add(map);
libkea_testutils_la_SOURCES = io_utils.cc io_utils.h
libkea_testutils_la_SOURCES += log_utils.cc log_utils.h
+libkea_testutils_la_SOURCES += test_to_element.cc test_to_element.h
libkea_testutils_la_SOURCES += unix_control_client.h unix_control_client.cc
libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libkea_testutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la