Commit 08e5c7f5 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2318] Parsing and setting option data.

parent 683f4b74
...@@ -60,6 +60,7 @@ b10_dhcp6_CXXFLAGS = -Wno-unused-parameter ...@@ -60,6 +60,7 @@ b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
endif endif
b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <util/encode/hex.h>
#include <asiolink/io_address.h> #include <asiolink/io_address.h>
#include <cc/data.h> #include <cc/data.h>
#include <config/ccsession.h> #include <config/ccsession.h>
...@@ -557,12 +558,22 @@ private: ...@@ -557,12 +558,22 @@ private:
isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain" isc_throw(Dhcp6ConfigError, "Parser error: option name must not contain"
<< " spaces"); << " spaces");
} }
std::string option_data = getStringParam("data");
std::vector<uint8_t> binary;
try {
util::encode::decodeHex(option_data, binary);
} catch (...) {
isc_throw(Dhcp6ConfigError, "Parser error: option data is not a valid"
<< " string of hexadecimal digits: " << option_data);
}
// Create the actual option. // Create the actual option.
// @todo Currently we simply create dhcp::Option instance here but we will // @todo Currently we simply create dhcp::Option instance here but we will
// need to use dedicated factory functions once the option definitions are // need to use dedicated factory functions once the option definitions are
// created for all options. // created for all options.
OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code), OptionPtr option(new Option(Option::V6, static_cast<uint16_t>(option_code),
OptionBuffer())); binary));
// If option is created succesfully, add it to the storage. // If option is created succesfully, add it to the storage.
options_->push_back(option); options_->push_back(option);
} }
...@@ -647,7 +658,7 @@ public: ...@@ -647,7 +658,7 @@ public:
void commit() { } void commit() { }
/// @brief Create DhcpDataListParser object /// @brief Create DhcpDataListParser object
/// ///
/// @param param_name param name. /// @param param_name param name.
/// ///
/// @return DhcpConfigParser object. /// @return DhcpConfigParser object.
...@@ -762,6 +773,7 @@ public: ...@@ -762,6 +773,7 @@ public:
subnet->addOption(option); subnet->addOption(option);
} }
std::cout << "ADDING SUBNET" << std::endl;
CfgMgr::instance().addSubnet6(subnet); CfgMgr::instance().addSubnet6(subnet);
} }
...@@ -927,7 +939,6 @@ public: ...@@ -927,7 +939,6 @@ public:
DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) { DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
FactoryMap factories; FactoryMap factories;
//
factories.insert(pair<string, ParserFactory*>( factories.insert(pair<string, ParserFactory*>(
"preferred-lifetime", Uint32Parser::Factory)); "preferred-lifetime", Uint32Parser::Factory));
factories.insert(pair<string, ParserFactory*>( factories.insert(pair<string, ParserFactory*>(
......
...@@ -63,6 +63,7 @@ dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) ...@@ -63,6 +63,7 @@ dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
dhcp6_unittests_LDADD = $(GTEST_LDADD) dhcp6_unittests_LDADD = $(GTEST_LDADD)
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
......
...@@ -272,7 +272,7 @@ TEST_F(Dhcp6ParserTest, pool_prefix_len) { ...@@ -272,7 +272,7 @@ TEST_F(Dhcp6ParserTest, pool_prefix_len) {
EXPECT_EQ(4000, subnet->getValid()); EXPECT_EQ(4000, subnet->getValid());
} }
TEST_F(Dhcp6ParserTest, multipleOptionValues) { TEST_F(Dhcp6ParserTest, optionValuesInSingleSubnet) {
ConstElementPtr x; ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ]," string config = "{ \"interface\": [ \"all\" ],"
"\"preferred-lifetime\": 3000," "\"preferred-lifetime\": 3000,"
...@@ -284,23 +284,22 @@ TEST_F(Dhcp6ParserTest, multipleOptionValues) { ...@@ -284,23 +284,22 @@ TEST_F(Dhcp6ParserTest, multipleOptionValues) {
" \"option-data\": [ {" " \"option-data\": [ {"
" \"name\": \"option_foo\"," " \"name\": \"option_foo\","
" \"code\": 100," " \"code\": 100,"
" \"data\": \"ABCDEF 01 05\"" " \"data\": \"AB CDEF0105\""
" }," " },"
" {" " {"
" \"name\": \"option_foo2\"," " \"name\": \"option_foo2\","
" \"code\": 101," " \"code\": 101,"
" \"data\": \"1\"" " \"data\": \"01\""
" } ]" " } ]"
" } ]," " } ],"
"\"valid-lifetime\": 4000 }"; "\"valid-lifetime\": 4000 }";
cout << config << endl;
ElementPtr json = Element::fromJSON(config); ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json)); EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
ASSERT_TRUE(x); ASSERT_TRUE(x);
comment_ = parseAnswer(rcode_, x); comment_ = parseAnswer(rcode_, x);
EXPECT_EQ(0, rcode_); ASSERT_EQ(0, rcode_);
Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5")); Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet); ASSERT_TRUE(subnet);
...@@ -333,4 +332,84 @@ TEST_F(Dhcp6ParserTest, multipleOptionValues) { ...@@ -333,4 +332,84 @@ TEST_F(Dhcp6ParserTest, multipleOptionValues) {
testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected)); testOption(*range.first, 101, foo2_expected, sizeof(foo2_expected));
} }
TEST_F(Dhcp6ParserTest, optionValuesInMultipleSubnets) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:1::/80\" ],"
" \"subnet\": \"2001:db8:1::/64\", "
" \"option-data\": [ {"
" \"name\": \"option_foo\","
" \"code\": 100,"
" \"data\": \"0102030405060708090A\""
" } ]"
" },"
" {"
" \"pool\": [ \"2001:db8:2::/80\" ],"
" \"subnet\": \"2001:db8:2::/64\", "
" \"option-data\": [ {"
" \"name\": \"option_foo2\","
" \"code\": 101,"
" \"data\": \"FFFEFDFCFB\""
" } ]"
" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
ASSERT_TRUE(x);
comment_ = parseAnswer(rcode_, x);
ASSERT_EQ(0, rcode_);
Subnet6Ptr subnet1 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
ASSERT_TRUE(subnet1);
const Subnet::OptionContainer& options1 = subnet1->getOptions();
ASSERT_EQ(1, options1.size());
for (Subnet::OptionContainer::iterator it = options1.begin();
it != options1.end(); ++it) {
std::cout << it->option->getType() << std::endl;
}
// Get the search index. Index #1 is to search using option code.
const Subnet::OptionContainerTypeIndex& idx1 = options1.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> range1 =
idx1.equal_range(100);
// Expect single option with the code equal to 100.
ASSERT_EQ(1, std::distance(range1.first, range1.second));
const uint8_t foo_expected[] = {
0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A
};
// Check if option is valid in terms of code and carried data.
testOption(*range1.first, 100, foo_expected, sizeof(foo_expected));
// Test another subnet in the same way.
Subnet6Ptr subnet2 = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:2::4"));
ASSERT_TRUE(subnet2);
const Subnet::OptionContainer& options2 = subnet2->getOptions();
ASSERT_EQ(1, options2.size());
const Subnet::OptionContainerTypeIndex& idx2 = options2.get<1>();
std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
Subnet::OptionContainerTypeIndex::const_iterator> range2 =
idx2.equal_range(101);
ASSERT_EQ(1, std::distance(range2.first, range2.second));
const uint8_t foo2_expected[] = {
0xFF, 0xFE, 0xFD, 0xFC, 0xFB
};
testOption(*range2.first, 101, foo2_expected, sizeof(foo2_expected));
}
}; };
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment