BIND 10 trac2417, updated. 38ebe09ee1c3ed6906f6a439e5ac9088b665420e [2417] Create basic set of stdandard DHCPv6 option definition instances.
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Nov 2 19:10:33 UTC 2012
The branch, trac2417 has been updated
via 38ebe09ee1c3ed6906f6a439e5ac9088b665420e (commit)
from e8a6aee2464c295e476eff03448e39d386747140 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 38ebe09ee1c3ed6906f6a439e5ac9088b665420e
Author: Marcin Siodelski <marcin at isc.org>
Date: Fri Nov 2 20:10:10 2012 +0100
[2417] Create basic set of stdandard DHCPv6 option definition instances.
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp6/config_parser.cc | 43 +++++++---
src/bin/dhcp6/dhcp6_srv.cc | 14 +++-
src/bin/dhcp6/dhcp6_srv.h | 2 +
src/bin/dhcp6/tests/config_parser_unittest.cc | 105 +++++++++++++++++++++----
src/lib/dhcp/libdhcp++.cc | 51 +++++++++++-
src/lib/dhcp/libdhcp++.h | 49 +++++++++++-
src/lib/dhcp/tests/libdhcp++_unittest.cc | 4 +-
7 files changed, 231 insertions(+), 37 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index 0fca770..e5a2be3 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -26,6 +26,7 @@
#include <cc/data.h>
#include <config/ccsession.h>
#include <log/logger_support.h>
+#include <dhcp/libdhcp++.h>
#include <dhcp/triplet.h>
#include <dhcp/pool.h>
#include <dhcp/subnet.h>
@@ -601,7 +602,7 @@ private:
<< " be equal to zero. Option code '0' is reserved in"
<< " DHCPv6.");
} else if (option_code > std::numeric_limits<uint16_t>::max()) {
- isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"
+ isc_throw(Dhcp6ConfigError, "Parser error: value of 'code' must not"ciwtezcowy
<< " exceed " << std::numeric_limits<uint16_t>::max());
}
// Check the option name has been specified, is non-empty and does not
@@ -625,15 +626,37 @@ private:
<< " string of hexadecimal digits: " << option_data);
}
- // Create the actual option.
- // @todo Currently we simply create dhcp::Option instance here but we will
- // need to use dedicated factory functions once the option definitions are
- // created for all options.
- OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
- binary));
-
- // If option is created succesfully, add it to the storage.
- options_->push_back(option);
+ OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
+ const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+
+ const OptionDefContainerTypeRange& range = idx.equal_range(option_code);
+ size_t num_defs = std::distance(range.first, range.second);
+ OptionPtr option;
+ if (num_defs > 1) {
+ isc_throw(Dhcp6ConfigError, "Internal error: currently it is not"
+ << " supported to initialize multiple option definitions"
+ << " for the same option code. This will be supported once"
+ << " there option spaces are implemented.");
+ } else if (num_defs == 0) {
+ // Create the actual option.
+ OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
+ binary));
+ // If option is created succesfully, add it to the storage.
+ options_->push_back(option);
+ } else {
+ const OptionDefinitionPtr& def = *(range.first);
+ // getFactory should never return NULL pointer so we skip
+ // sanity check here.
+ Option::Factory* factory = def->getFactory();
+ try {
+ OptionPtr option = factory(Option::V6, option_code, binary);
+ options_->push_back(option);
+ } catch (const isc::Exception& ex) {
+ isc_throw(Dhcp6ConfigError, "Parser error: option data does not match"
+ << " option definition (code " << option_code << "): "
+ << ex.what());
+ }
+ }
}
/// @brief Get a parameter from the strings storage.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 330873a..79b5823 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -52,10 +52,17 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
- // First call to instance() will create IfaceMgr (it's a singleton)
- // it may throw something if things go wrong
+ // Initialize objects required for DHCP server operation.
try {
+ // Initialize standard DHCPv6 option definitions. This function
+ // may throw bad_alloc if system goes out of memory during the
+ // creation if option definitions. It may also throw isc::Unexpected
+ // if definitions are wrong. This would mean error in implementation.
+ initStdOptionDefs();
+
+ // Call IfaceMgr::instance() will create instance of Interface
+ // Manager (it's a singleton). It may throw if things go wrong.
if (IfaceMgr::instance().countIfaces() == 0) {
LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
shutdown_ = true;
@@ -432,6 +439,5 @@ Dhcpv6Srv::serverReceivedPacketName(uint8_t type) {
void
Dhcpv6Srv::initStdOptionDefs() {
- OptionDefContainer options;
- LibDHCP::initStdOptionDefs6(options);
+ LibDHCP::initStdOptionDefs(Option::V6);
}
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 2a916be..c87d8f3 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -19,6 +19,7 @@
#include <dhcp/dhcp6.h>
#include <dhcp/pkt6.h>
#include <dhcp/option.h>
+#include <dhcp/option_definition.h>
#include <iostream>
namespace isc {
@@ -210,6 +211,7 @@ protected:
/// it is limited to critical options only.
void initStdOptionDefs();
+private:
/// server DUID (to be sent in server-identifier option)
boost::shared_ptr<isc::dhcp::Option> serverid_;
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index 489e3c1..4e5bfd6 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -17,6 +17,8 @@
#include <fstream>
#include <sstream>
+#include <boost/foreach.hpp>
+
#include <arpa/inet.h>
#include <gtest/gtest.h>
@@ -25,6 +27,7 @@
#include <config/ccsession.h>
#include <dhcp/subnet.h>
#include <dhcp/cfgmgr.h>
+#include <dhcp/option6_ia.h>
using namespace std;
using namespace isc;
@@ -60,6 +63,24 @@ public:
/// param value.
std::string createConfigWithOption(const std::string& param_value,
const std::string& parameter) {
+ std::map<std::string, std::string> params;
+ if (parameter == "name") {
+ params["name"] = param_value;
+ params["code"] = "80";
+ params["data"] = "AB CDEF0105";
+ } else if (parameter == "code") {
+ params["name"] = "option_foo";
+ params["code"] = param_value;
+ params["data"] = "AB CDEF0105";
+ } else if (parameter == "data") {
+ params["name"] = "option_foo";
+ params["code"] = "80";
+ params["data"] = param_value;
+ }
+ return (createConfigWithOption(params));
+ }
+
+ std::string createConfigWithOption(const std::map<std::string, std::string>& params) {
std::ostringstream stream;
stream << "{ \"interface\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
@@ -69,21 +90,21 @@ public:
" \"pool\": [ \"2001:db8:1::/80\" ],"
" \"subnet\": \"2001:db8:1::/64\", "
" \"option-data\": [ {";
- if (parameter == "name") {
- stream <<
- " \"name\": \"" << param_value << "\","
- " \"code\": 80,"
- " \"data\": \"AB CDEF0105\"";
- } else if (parameter == "code") {
- stream <<
- " \"name\": \"option_foo\","
- " \"code\": " << param_value << ","
- " \"data\": \"AB CDEF0105\"";
- } else if (parameter == "data") {
- stream <<
- " \"name\": \"option_foo\","
- " \"code\": 80,"
- " \"data\": \"" << param_value << "\"";
+ bool first = true;
+ typedef std::pair<std::string, std::string> ParamPair;
+ BOOST_FOREACH(ParamPair param, params) {
+ if (!first) {
+ stream << ", ";
+ } else {
+ first = false;
+ }
+ if (param.first == "name") {
+ stream << "\"name\": \"" << param.second << "\"";
+ } else if (param.first == "code") {
+ stream << "\"code\": " << param.second << "";
+ } else if (param.first == "data") {
+ stream << "\"data\": \"" << param.second << "\"";
+ }
}
stream <<
" } ]"
@@ -658,4 +679,58 @@ TEST_F(Dhcp6ParserTest, optionDataLowerCase) {
testOption(*range.first, 80, foo_expected, sizeof(foo_expected));
}
+// Verify that specific option object is returned for standard
+// option which has dedicated option class derived from Option.
+TEST_F(Dhcp6ParserTest, stdOptionData) {
+ ConstElementPtr x;
+ std::map<std::string, std::string> params;
+ params["name"] = "OPTION_IA_NA";
+ // Option code 3 means OPTION_IA_NA.
+ params["code"] = "3";
+ params["data"] = "ABCDEF01 02030405 06070809";
+
+ std::string config = createConfigWithOption(params);
+ ElementPtr json = Element::fromJSON(config);
+
+ EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
+ ASSERT_TRUE(x);
+ comment_ = parseAnswer(rcode_, x);
+ ASSERT_EQ(0, rcode_);
+
+ Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
+ ASSERT_TRUE(subnet);
+ const Subnet::OptionContainer& options = subnet->getOptions();
+ ASSERT_EQ(1, options.size());
+
+ // Get the search index. Index #1 is to search using option code.
+ const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+
+ // Get the options for specified index. Expecting one option to be
+ // returned but in theory we may have multiple options with the same
+ // code so we get the range.
+ std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+ Subnet::OptionContainerTypeIndex::const_iterator> range =
+ idx.equal_range(D6O_IA_NA);
+ // Expect single option with the code equal to IA_NA option code.
+ ASSERT_EQ(1, std::distance(range.first, range.second));
+ // The actual pointer to the option is held in the option field
+ // in the structure returned.
+ OptionPtr option = range.first->option;
+ ASSERT_TRUE(option);
+ // Option object returned for here is expected to be Option6IA
+ // which is derived from Option. This class is dedicated to
+ // represent standard option IA_NA.
+ boost::shared_ptr<Option6IA> optionIA =
+ boost::dynamic_pointer_cast<Option6IA>(option);
+ // If cast is unsuccessful than option returned was of a
+ // differnt type than Option6IA. This is wrong.
+ ASSERT_TRUE(optionIA);
+ // If cast was successful we may use accessors exposed by
+ // Option6IA to validate that the content of this option
+ // has been set correctly.
+ EXPECT_EQ(0xABCDEF01, optionIA->getIAID());
+ EXPECT_EQ(0x02030405, optionIA->getT1());
+ EXPECT_EQ(0x06070809, optionIA->getT2());
+}
+
};
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index f182862..30b1850 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -35,6 +35,23 @@ std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
// static array with factories for options
std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
+// Static container with DHCPv4 option definitions.
+OptionDefContainer LibDHCP::v4option_defs_;
+
+// Static container with DHCPv6 option definitions.
+OptionDefContainer LibDHCP::v6option_defs_;
+
+const OptionDefContainer&
+LibDHCP::getOptionDefs(Option::Universe u) {
+ switch (u) {
+ case Option::V4:
+ return (v4option_defs_);
+ case Option::V6:
+ return (v6option_defs_);
+ default:
+ isc_throw(isc::BadValue, "invalid universe " << u << " specified");
+ }
+}
OptionPtr
LibDHCP::optionFactory(Option::Universe u,
@@ -204,8 +221,27 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
}
void
-LibDHCP::initStdOptionDefs6(OptionDefContainer& defs) {
- defs.clear();
+LibDHCP::initStdOptionDefs(Option::Universe u) {
+ switch (u) {
+ case Option::V4:
+ initStdOptionDefs4();
+ break;
+ case Option::V6:
+ initStdOptionDefs6();
+ break;
+ default:
+ isc_throw(isc::BadValue, "invalid universe " << u << " specified");
+ }
+}
+
+void
+LibDHCP::initStdOptionDefs4() {
+ isc_throw(isc::NotImplemented, "initStdOptionDefs4 is not implemented");
+}
+
+void
+LibDHCP::initStdOptionDefs6() {
+ v6option_defs_.clear();
struct OptionParams {
std::string name;
@@ -243,11 +279,18 @@ LibDHCP::initStdOptionDefs6(OptionDefContainer& defs) {
definition->addRecordField(OptionDefinition::UINT32_TYPE);
break;
case D6O_STATUS_CODE:
- definition->addRecordField(OptionDefinition::UINT16_TYPE);
+ definotion->addRecordField(OptionDefinition::UINT16_TYPE);
definition->addRecordField(OptionDefinition::STRING_TYPE);
default:
break;
}
- defs.push_back(definition);
+ try {
+ definition->validate();
+ } catch (const Exception& ex) {
+ isc_throw(isc::Unexpected, "internal server error: invalid definition of standard"
+ << " DHCPv6 option (with code " << params[i].code << "): "
+ << ex.what());
+ }
+ v6option_defs_.push_back(definition);
}
}
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index e565a35..c057eea 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -30,6 +30,12 @@ public:
/// Map of factory functions.
typedef std::map<unsigned short, Option::Factory*> FactoryMap;
+ /// @brief Return collection of option definitions.
+ ///
+ /// @param u universe of the options (V4 or V6).
+ /// @return collection of option definitions.
+ static const OptionDefContainer& getOptionDefs(Option::Universe u);
+
/// @brief Factory function to create instance of option.
///
/// Factory method creates instance of specified option. The option
@@ -104,14 +110,53 @@ public:
uint16_t type,
Option::Factory * factory);
- static void initStdOptionDefs6(OptionDefContainer& defs);
+ /// Initialize standard DHCP options (V4 or V6).
+ ///
+ /// The method creates option definitions for all options
+ /// (DHCPv4 or DHCPv6 depending on universe specified).
+ /// Currently DHCPv4 option definitions initialization is not
+ /// implemented thus this function will throw isc::NotImplemented
+ /// if V4 universe is specified.
+ ///
+ /// @param u universe
+ /// @throw isc::Unexpected if internal error occured during option
+ /// definitions creation.
+ /// @throw std::bad_alloc if system went out of memory.
+ /// @throw isc::NotImplemented when V4 universe specified.
+ static void initStdOptionDefs(Option::Universe u);
+
+private:
+
+ /// Initialize standard DHCPv4 option definitions.
+ ///
+ /// The method creates option definitions for all DHCPv4 options.
+ /// Currently this function is not implemented.
+ ///
+ /// @todo implemend this function.
+ ///
+ /// @throw isc::NotImplemeneted
+ static void initStdOptionDefs4();
+
+ /// Initialize standard DHCPv6 option definitions.
+ ///
+ /// The method creates option definitions for all DHCPv6 options.
+ ///
+ /// @throw isc::Unexpected if internal error occured during option
+ /// definitions creation.
+ /// @throw std::bad_alloc if system went out of memory.
+ static void initStdOptionDefs6();
-protected:
/// pointers to factories that produce DHCPv6 options
static FactoryMap v4factories_;
/// pointers to factories that produce DHCPv6 options
static FactoryMap v6factories_;
+
+ /// Container with DHCPv4 option definitions.
+ static OptionDefContainer v4option_defs_;
+
+ /// Container with DHCPv6 option definitions.
+ static OptionDefContainer v6option_defs_;
};
}
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index 650a0f3..ec7f055 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -64,8 +64,8 @@ public:
static void testInitOptionDefs6(const uint16_t code,
const OptionBuffer& buf,
const std::type_info& expected_type) {
- OptionDefContainer options;
- LibDHCP::initStdOptionDefs6(options);
+ LibDHCP::initStdOptionDefs(Option::V6);
+ OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
const OptionDefContainerTypeIndex& idx = options.get<1>();
OptionDefContainerTypeRange range = idx.equal_range(code);
ASSERT_EQ(1, std::distance(range.first, range.second));
More information about the bind10-changes
mailing list