Commit e8a6aee2 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2417] Creating definitions for critical standard DHCPv6 options.

parent e75c686c
......@@ -20,6 +20,7 @@
#include <dhcp6/dhcp6_srv.h>
#include <dhcp/dhcp6.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_ia.h>
......@@ -428,3 +429,9 @@ Dhcpv6Srv::serverReceivedPacketName(uint8_t type) {
}
return (UNKNOWN);
}
void
Dhcpv6Srv::initStdOptionDefs() {
OptionDefContainer options;
LibDHCP::initStdOptionDefs6(options);
}
......@@ -199,6 +199,17 @@ protected:
/// interfaces for new DUID generation are detected.
void setServerID();
/// @brief Initializes option definitions for standard options.
///
/// Each standard option's format is described by the
/// dhcp::OptionDefinition object. This function creates such objects
/// for each standard DHCPv6 option.
///
/// @todo list thrown exceptions.
/// @todo extend this function to cover all standard options. Currently
/// it is limited to critical options only.
void initStdOptionDefs();
/// server DUID (to be sent in server-identifier option)
boost::shared_ptr<isc::dhcp::Option> serverid_;
......
......@@ -23,6 +23,7 @@
#include <dhcp/option.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option_definition.h>
using namespace std;
using namespace isc::dhcp;
......@@ -201,3 +202,52 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
return;
}
void
LibDHCP::initStdOptionDefs6(OptionDefContainer& defs) {
defs.clear();
struct OptionParams {
std::string name;
uint16_t code;
OptionDefinition::DataType type;
bool array;
};
OptionParams params[] = {
{ "CLIENTID", D6O_CLIENTID, OptionDefinition::BINARY_TYPE, false },
{ "SERVERID", D6O_SERVERID, OptionDefinition::BINARY_TYPE, false },
{ "IA_NA", D6O_IA_NA, OptionDefinition::RECORD_TYPE, false },
{ "IAADDR", D6O_IAADDR, OptionDefinition::RECORD_TYPE, false },
{ "ORO", D6O_ORO, OptionDefinition::UINT16_TYPE, true },
{ "ELAPSED_TIME", D6O_ELAPSED_TIME, OptionDefinition::UINT16_TYPE, false },
{ "STATUS_CODE", D6O_STATUS_CODE, OptionDefinition::RECORD_TYPE, false },
{ "RAPID_COMMIT", D6O_RAPID_COMMIT, OptionDefinition::EMPTY_TYPE, false },
{ "DNS_SERVERS", D6O_NAME_SERVERS, OptionDefinition::IPV6_ADDRESS_TYPE, true }
};
const int params_size = sizeof(params) / sizeof(params[0]);
for (int i = 0; i < params_size; ++i) {
OptionDefinitionPtr definition(new OptionDefinition(params[i].name,
params[i].code,
params[i].type,
params[i].array));
switch(params[i].code) {
case D6O_IA_NA:
for (int j = 0; j < 3; ++j) {
definition->addRecordField(OptionDefinition::UINT32_TYPE);
}
break;
case D6O_IAADDR:
definition->addRecordField(OptionDefinition::IPV6_ADDRESS_TYPE);
definition->addRecordField(OptionDefinition::UINT32_TYPE);
definition->addRecordField(OptionDefinition::UINT32_TYPE);
break;
case D6O_STATUS_CODE:
definition->addRecordField(OptionDefinition::UINT16_TYPE);
definition->addRecordField(OptionDefinition::STRING_TYPE);
default:
break;
}
defs.push_back(definition);
}
}
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
......@@ -15,9 +15,10 @@
#ifndef LIBDHCP_H_
#define LIBDHCP_H_
#include <iostream>
#include <util/buffer.h>
#include <dhcp/option_definition.h>
#include <dhcp/pkt6.h>
#include <util/buffer.h>
#include <iostream>
namespace isc {
namespace dhcp {
......@@ -102,6 +103,9 @@ public:
static void OptionFactoryRegister(Option::Universe u,
uint16_t type,
Option::Factory * factory);
static void initStdOptionDefs6(OptionDefContainer& defs);
protected:
/// pointers to factories that produce DHCPv6 options
static FactoryMap v4factories_;
......
......@@ -29,6 +29,7 @@ namespace dhcp {
OptionDefinition::DataTypeUtil::DataTypeUtil() {
data_types_["empty"] = EMPTY_TYPE;
data_types_["binary"] = BINARY_TYPE;
data_types_["boolean"] = BOOLEAN_TYPE;
data_types_["int8"] = INT8_TYPE;
data_types_["int16"] = INT16_TYPE;
......@@ -97,11 +98,15 @@ OptionDefinition::addRecordField(const DataType data_type) {
Option::Factory*
OptionDefinition::getFactory() const {
validate();
// @todo This function must be extended to return more factory
// functions that create instances of more specialized options.
// This requires us to first implement those more specialized
// options that will be derived from Option class.
if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
if (type_ == BINARY_TYPE) {
return (factoryGeneric);
} else if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
return (factoryAddrList6);
} else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
return (factoryAddrList4);
......
......@@ -16,13 +16,42 @@
#define OPTION_DEFINITION_H_
#include <dhcp/option_data_types.h>
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/option.h>
#include <boost/shared_ptr.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
namespace isc {
namespace dhcp {
/// @brief Forward declaration to OptionDefinition.
class OptionDefinition;
/// @brief Pointer to option definition object.
typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;
/// @brief Forward declaration to Option6Int.
///
/// This forward declaration is needed to access Option6Int class
/// without having to include option6_int.h header. This is because
/// this header includes libdhcp++.h and this causes circular
/// inclusion between libdhcp++.h, option_definition.h and
/// option6_int.h.
template<typename T>
class Option6Int;
/// @brief Forward declaration to Option6IntArray.
///
/// This forward declaration is needed to access Option6IntArray class
/// without having to include option6_int_array.h header. This is because
/// this header includes libdhcp++.h and this causes circular
/// inclusion between libdhcp++.h, option_definition.h and
/// option6_int_array.h.
template<typename T>
class Option6IntArray;
/// @brief Base class representing a DHCP option definition.
///
/// This is a base class representing a DHCP option definition, which describes
......@@ -52,7 +81,7 @@ namespace dhcp {
///
/// Should the option comprise data fields of different types, the "record"
/// option type is used. In such cases the data field types within the record
/// are specified using \ref OptionDefinition::addRecordField.
/// are specified using \ref OptioDefinition::addRecordField.
///
/// When the OptionDefinition object has been sucessfully created, it can be
/// queried to return the appropriate option factory function for the specified
......@@ -84,6 +113,7 @@ public:
/// Data types of DHCP option fields.
enum DataType {
EMPTY_TYPE,
BINARY_TYPE,
BOOLEAN_TYPE,
INT8_TYPE,
INT16_TYPE,
......@@ -202,7 +232,9 @@ public:
/// @brief Return factory function for the given definition.
///
/// @return pointer to factory function.
/// @throw isc::OutOfRange if \ref validate returns it.
/// @throw isc::BadValue if \ref validate returns it.
/// @return pointer to a factory function.
Option::Factory* getFactory() const;
/// @brief Return option name.
......@@ -377,6 +409,50 @@ private:
};
/// @brief Multi index container for DHCP option definitions.
///
/// This container allows to search for DHCP option definition
/// using two indexes:
/// - sequenced: used to access elements in the oreder they have
/// been added to the container
/// - option code: used to search defintions of options
/// with a specified option code (aka option type).
///
/// @todo: need an index to search options using option space name
/// once option spaces are implemented.
typedef boost::multi_index_container<
// Container comprises elements of OptionDefinition type.
OptionDefinitionPtr,
// Here we start enumerating various indexes.
boost::multi_index::indexed_by<
// Sequenced index allows accessing elements in the same way
// as elements in std::list. Sequenced is an index #0.
boost::multi_index::sequenced<>,
// Start definition of index #1.
boost::multi_index::hashed_non_unique<
// Use option type as the index key. The type is held
// in OptionDefinition object so we have to call
// OptionDefinition::getCode to retrieve this key
// for each element.
boost::multi_index::const_mem_fun<
OptionDefinition,
uint16_t,
&OptionDefinition::getCode
>
>
>
> OptionDefContainer;
/// Type of the index #1 - option type.
typedef OptionDefContainer::nth_index<1>::type OptionDefContainerTypeIndex;
/// Pair of iterators to represent the range of options definitions
/// having the same option type value. The first element in this pair
/// represents the begining of the range, the second element
/// represents the end.
typedef std::pair<OptionDefContainerTypeIndex::const_iterator,
OptionDefContainerTypeIndex::const_iterator> OptionDefContainerTypeRange;
} // namespace isc::dhcp
} // namespace isc
......
......@@ -21,6 +21,11 @@
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/option6_addrlst.h>
#include "config.h"
using namespace std;
......@@ -46,6 +51,34 @@ public:
Option* option = new Option(u, type, buf);
return OptionPtr(option);
}
/// @brief Test option option definition.
///
/// This function tests if option definition for standard
/// option has been initialized correctly.
///
/// @param code option code.
/// @param bug buffer to be used to create option instance.
/// @param expected_type type of the option created by the
/// factory function returned by the option definition.
static void testInitOptionDefs6(const uint16_t code,
const OptionBuffer& buf,
const std::type_info& expected_type) {
OptionDefContainer options;
LibDHCP::initStdOptionDefs6(options);
const OptionDefContainerTypeIndex& idx = options.get<1>();
OptionDefContainerTypeRange range = idx.equal_range(code);
ASSERT_EQ(1, std::distance(range.first, range.second));
OptionDefinitionPtr def = *(range.first);
ASSERT_TRUE(def);
ASSERT_NO_THROW(def->validate());
Option::Factory* factory = NULL;
ASSERT_NO_THROW(factory = def->getFactory());
OptionPtr option;
ASSERT_NO_THROW(option = factory(Option::V6, code, buf));
ASSERT_TRUE(option);
EXPECT_TRUE(typeid(*option) == expected_type);
}
};
static const uint8_t packed[] = {
......@@ -311,4 +344,30 @@ TEST(LibDhcpTest, unpackOptions4) {
EXPECT_TRUE(x == options.end()); // option 2 not found
}
// Test that definitions of standard options have been initialized
// correctly.
// @todo Only limited number of option definitions are now created
// This test have to be extended once all option definitions are
// created.
TEST(LibDhcpTest, initStdOptionDefs) {
LibDhcpTest::testInitOptionDefs6(D6O_CLIENTID, OptionBuffer(14, 1),
typeid(Option));
LibDhcpTest::testInitOptionDefs6(D6O_SERVERID, OptionBuffer(14, 1),
typeid(Option));
LibDhcpTest::testInitOptionDefs6(D6O_IA_NA, OptionBuffer(12, 1),
typeid(Option6IA));
LibDhcpTest::testInitOptionDefs6(D6O_IAADDR, OptionBuffer(24, 1),
typeid(Option6IAAddr));
LibDhcpTest::testInitOptionDefs6(D6O_ORO, OptionBuffer(10, 1),
typeid(Option6IntArray<uint16_t>));
LibDhcpTest::testInitOptionDefs6(D6O_ELAPSED_TIME, OptionBuffer(2, 1),
typeid(Option6Int<uint16_t>));
LibDhcpTest::testInitOptionDefs6(D6O_STATUS_CODE, OptionBuffer(10, 1),
typeid(Option));
LibDhcpTest::testInitOptionDefs6(D6O_RAPID_COMMIT, OptionBuffer(),
typeid(Option));
LibDhcpTest::testInitOptionDefs6(D6O_NAME_SERVERS, OptionBuffer(32, 1),
typeid(Option6AddrLst));
}
}
......@@ -281,6 +281,43 @@ TEST_F(OptionDefinitionTest, factoryEmpty) {
EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
}
TEST_F(OptionDefinitionTest, factoryBinary) {
OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
Option::Factory* factory(NULL);
EXPECT_NO_THROW(factory = opt_def.getFactory());
ASSERT_TRUE(factory != NULL);
OptionBuffer buf(14);
for (int i = 0; i < 14; ++i) {
buf[i] = i;
}
OptionPtr option_v6;
ASSERT_NO_THROW(
option_v6 = factory(Option::V6, D6O_SERVERID, buf);
);
// Expect base option type returned.
ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
EXPECT_EQ(Option::V6, option_v6->getUniverse());
EXPECT_EQ(4, option_v6->getHeaderLen());
ASSERT_EQ(buf.size(), option_v6->getData().size());
EXPECT_TRUE(std::equal(option_v6->getData().begin(),
option_v6->getData().end(),
buf.begin()));
// Repeat the same test scenario for DHCPv4 option.
OptionPtr option_v4;
ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, buf));
// Expect 'empty' DHCPv4 option.
EXPECT_EQ(Option::V4, option_v4->getUniverse());
EXPECT_EQ(2, option_v4->getHeaderLen());
ASSERT_EQ(buf.size(), option_v4->getData().size());
EXPECT_TRUE(std::equal(option_v6->getData().begin(),
option_v6->getData().end(),
buf.begin()));
}
TEST_F(OptionDefinitionTest, factoryIA6) {
// This option consists of IAID, T1 and T2 fields (each 4 bytes long).
const int option6_ia_len = 12;
......
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