Commit 6a4d93f0 authored by Francis Dupont's avatar Francis Dupont
Browse files

[5073a] Code almost finished (still need tests and doc)

parent 042c0b6f
......@@ -9,6 +9,7 @@
#include <dhcp/duid.h>
#include <dhcp/hwaddr.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_int.h>
#include <dhcp/option_int_array.h>
......@@ -960,6 +961,9 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
// class information.
classifyPacket(query);
// Now it is classified the deferred unpacking can be done.
deferredUnpack(query);
// Check whether the message should be further processed or discarded.
// There is no need to log anything here. This function logs by itself.
if (!accept(query)) {
......@@ -2819,6 +2823,61 @@ void Dhcpv4Srv::classifyPacket(const Pkt4Ptr& pkt) {
}
}
void
Dhcpv4Srv::deferredUnpack(Pkt4Ptr& query)
{
// Iterate on the list of deferred option codes
BOOST_FOREACH(const uint16_t& code, query->deferredOptions()) {
OptionDefinitionPtr def;
// Iterate on client classes
const ClientClasses& classes = query->getClasses();
for (ClientClasses::const_iterator cclass = classes.begin();
cclass != classes.end(); ++cclass) {
// Get the client class definition for this class
const ClientClassDefPtr& ccdef =
CfgMgr::instance().getCurrentCfg()->
getClientClassDictionary()->findClass(*cclass);
// If not found skip it
if (!ccdef) {
continue;
}
// If there is no option definition skip it
if (!ccdef->getCfgOptionDef()) {
continue;
}
def = ccdef->getCfgOptionDef()->get(DHCP4_OPTION_SPACE, code);
// Stop at the first client class with a defition
if (def) {
break;
}
}
// If not found try the global definition
if (!def) {
def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, code);
}
if (!def) {
def = LibDHCP::getRuntimeOptionDef(DHCP4_OPTION_SPACE, code);
}
// Option 43 has a last resort definition
if ((code == DHO_VENDOR_ENCAPSULATED_OPTIONS) && !def) {
def = LibDHCP::last_resort_option43_def;
}
// If not defined go to the next option
if (!def) {
continue;
}
// Get the existing option for its content and remove all
const OptionBuffer buf = query->getOption(code)->getData();
while (query->delOption(code)) {
/* continue */
}
// Unpack the option and add it
OptionPtr opt = def->optionFactory(Option::V4, code,
buf.cbegin(), buf.cend());
query->addOption(opt);
}
}
void
Dhcpv4Srv::startD2() {
D2ClientMgr& d2_mgr = CfgMgr::instance().getD2ClientMgr();
......
......@@ -803,6 +803,14 @@ protected:
/// @param pkt packet to be classified
void classifyPacket(const Pkt4Ptr& pkt);
/// @brief Perform deferred option unpacking.
///
/// @note Options 43 and 224-254 are processed after classification.
/// If a class configures a definition it is applied, if none
/// the global (user) definition is applied. For option 43
/// a last resort definition (same than for previous Kea) is used.
void deferredUnpack(Pkt4Ptr& query);
/// @brief Allocation Engine.
/// Pointer to the allocation engine that we are currently using
/// It must be a pointer, because we will support changing engines
......
......@@ -3179,6 +3179,7 @@ TEST_F(Dhcp4ParserTest, domainSearchOption) {
" domain-search option"));
}
#if 0
// The goal of this test is to verify that the standard option can
// be configured to encapsulate multiple other options.
TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
......@@ -3429,8 +3430,7 @@ TEST_F(Dhcp4ParserTest, vendorOptionsCsv) {
CfgMgr::instance().getStagingCfg()->getCfgOption()->get(5678, 100);
ASSERT_FALSE(desc2.option_);
}
#endif
// Tests of the hooks libraries configuration. All tests have the pre-
// condition (checked in the test fixture's SetUp() method) that no hooks
......
This diff is collapsed.
......@@ -433,7 +433,8 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
const std::string& option_space,
isc::dhcp::OptionCollection& options) {
isc::dhcp::OptionCollection& options,
std::list<uint16_t>& deferred) {
size_t offset = 0;
size_t last_offset = 0;
......@@ -514,6 +515,7 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
// Check if option unpacking must be deferred
if (deferOption(option_space, opt_type)) {
num_defs = 0;
deferred.push_back(opt_type);
}
OptionPtr opt;
......
......@@ -9,6 +9,7 @@
#include <dhcp/option_definition.h>
#include <dhcp/option_space_container.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
#include <util/buffer.h>
#include <util/staged_value.h>
......@@ -223,13 +224,16 @@ public:
/// to be used to parse options in the packets.
/// @param options Reference to option container. Options will be
/// put here.
/// @param deferred Reference to an option code list. Options which
/// processing is deferred will be put here.
/// @return offset to the first byte after the last successfully
/// parsed option or the offset of the DHO_END option type.
///
/// The unpackOptions6 note applies too.
static size_t unpackOptions4(const OptionBuffer& buf,
const std::string& option_space,
isc::dhcp::OptionCollection& options);
isc::dhcp::OptionCollection& options,
std::list<uint16_t>& deferred);
/// Registers factory method that produces options of specific option types.
///
......
......@@ -12,6 +12,7 @@
#include <util/io_utilities.h>
#include <iomanip>
#include <list>
#include <sstream>
#include <arpa/inet.h>
......@@ -153,9 +154,11 @@ void Option::unpack(OptionBufferConstIter begin,
void
Option::unpackOptions(const OptionBuffer& buf) {
list<uint16_t> deferred;
switch (universe_) {
case V4:
LibDHCP::unpackOptions4(buf, getEncapsulatedSpace(), options_);
LibDHCP::unpackOptions4(buf, getEncapsulatedSpace(),
options_, deferred);
return;
case V6:
LibDHCP::unpackOptions6(buf, getEncapsulatedSpace(), options_);
......
......@@ -203,7 +203,7 @@ Pkt4::unpack() {
// a vector as an input.
buffer_in.readVector(opts_buffer, opts_len);
size_t offset = LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE, options_);
size_t offset = LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE, options_, deferred_options_);
// If offset is not equal to the size and there is no DHO_END,
// then something is wrong here. We either parsed past input
......
......@@ -20,6 +20,7 @@
#include <iostream>
#include <vector>
#include <set>
#include <list>
#include <time.h>
......@@ -363,6 +364,11 @@ public:
return (local_hwaddr_);
}
/// @brief Returns a reference to deferred option codes
std::list<uint16_t>& deferredOptions() {
return (deferred_options_);
}
/// @brief Checks if a DHCPv4 message has been relayed.
///
/// This function returns a boolean value which indicates whether a DHCPv4
......@@ -375,7 +381,7 @@ public:
/// (true) or non-relayed (false).
bool isRelayed() const;
/// @brief Checks if a DHCPv4 message has beeb transported over DHCPv6
/// @brief Checks if a DHCPv4 message has been transported over DHCPv6
///
/// @return Boolean value which indicates whether the message is
/// transported over DHCPv6 (true) or native DHCPv4 (false)
......@@ -477,9 +483,12 @@ protected:
return(HWAddrPtr());
}
/// local HW address (dst if receiving packet, src if sending packet)
/// @brief local HW address (dst if receiving packet, src if sending packet)
HWAddrPtr local_hwaddr_;
// @brief List of deferred option codes
std::list<uint16_t> deferred_options_;
/// @brief message operation code
///
/// Note: This is legacy BOOTP field. There's no need to manipulate it
......
......@@ -793,9 +793,10 @@ TEST_F(LibDhcpTest, unpackOptions4) {
vector<uint8_t> v4packed(v4_opts, v4_opts + sizeof(v4_opts));
isc::dhcp::OptionCollection options; // list of options
list<uint16_t> deferred;
ASSERT_NO_THROW(
LibDHCP::unpackOptions4(v4packed, "dhcp4", options);
LibDHCP::unpackOptions4(v4packed, "dhcp4", options, deferred);
);
isc::dhcp::OptionCollection::const_iterator x = options.find(12);
......@@ -957,8 +958,9 @@ TEST_F(LibDhcpTest, unpackEmptyOption4) {
// Parse options.
OptionCollection options;
list<uint16_t> deferred;
ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE,
options));
options, deferred));
// There should be one option.
ASSERT_EQ(1, options.size());
......@@ -1017,7 +1019,9 @@ TEST_F(LibDhcpTest, unpackSubOptions4) {
// Parse options.
OptionCollection options;
ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, "space-foobar", options));
list<uint16_t> deferred;
ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, "space-foobar",
options, deferred));
// There should be one top level option.
ASSERT_EQ(1, options.size());
......
......@@ -138,8 +138,8 @@ ClientClassDef:: toElement() const {
if (!test_.empty()) {
result->set("test", Element::create(test_));
}
// Set option-def
if (cfg_option_def_) {
// Set option-def (used only by DHCPv4)
if (cfg_option_def_ && (family == AF_INET)) {
result->set("option-def", cfg_option_def_->toElement());
}
// Set option-data
......
......@@ -113,7 +113,7 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
CfgOptionPtr options(new CfgOption());
ConstElementPtr option_data = class_def_cfg->get("option-data");
if (option_data) {
OptionDataListParser opts_parser(family);
OptionDataListParser opts_parser(family, defs);
opts_parser.parse(options, option_data);
}
......
......@@ -24,8 +24,9 @@ namespace dhcp {
// **************************** OptionDataParser *************************
OptionDataParser::OptionDataParser(const uint16_t address_family)
: address_family_(address_family) {
OptionDataParser::OptionDataParser(const uint16_t address_family,
CfgOptionDefPtr cfg_option_def)
: address_family_(address_family), cfg_option_def_(cfg_option_def) {
}
std::pair<OptionDescriptor, std::string>
......@@ -179,7 +180,16 @@ template<typename SearchKey>
OptionDefinitionPtr
OptionDataParser::findOptionDefinition(const std::string& option_space,
const SearchKey& search_key) const {
OptionDefinitionPtr def = LibDHCP::getOptionDef(option_space, search_key);
OptionDefinitionPtr def;
if (cfg_option_def_) {
// Check if the definition was given in the constructor
def = cfg_option_def_->get(option_space, search_key);
}
if (!def) {
// Check if this is a standard option.
def = LibDHCP::getOptionDef(option_space, search_key);
}
if (!def) {
// Check if this is a vendor-option. If it is, get vendor-specific
......@@ -348,14 +358,15 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
// **************************** OptionDataListParser *************************
OptionDataListParser::OptionDataListParser(//const std::string&,
//const CfgOptionPtr& cfg,
const uint16_t address_family)
: address_family_(address_family) {
const uint16_t address_family,
CfgOptionDefPtr cfg_option_def)
: address_family_(address_family), cfg_option_def_(cfg_option_def) {
}
void OptionDataListParser::parse(const CfgOptionPtr& cfg,
isc::data::ConstElementPtr option_data_list) {
OptionDataParser option_parser(address_family_);
OptionDataParser option_parser(address_family_, cfg_option_def_);
BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) {
std::pair<OptionDescriptor, std::string> option =
option_parser.parse(data);
......
......@@ -11,6 +11,7 @@
#include <cc/simple_parser.h>
#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfg_option_def.h>
#include <util/optional_value.h>
#include <cstdint>
#include <string>
......@@ -42,7 +43,9 @@ public:
/// @brief Constructor.
///
/// @param address_family Address family: @c AF_INET or @c AF_INET6.
explicit OptionDataParser(const uint16_t address_family);
/// @param cfg_option_def Config option definitions (optional)
OptionDataParser(const uint16_t address_family,
CfgOptionDefPtr cfg_option_def = 0);
/// @brief Parses ElementPtr containing option definition
///
......@@ -146,6 +149,9 @@ private:
/// @brief Address family: @c AF_INET or @c AF_INET6.
uint16_t address_family_;
/// @brief Config option definitions
CfgOptionDefPtr cfg_option_def_;
};
/// @brief Parser for option data values within a subnet.
......@@ -159,7 +165,9 @@ public:
/// @brief Constructor.
///
/// @param address_family Address family: @c AF_INET or AF_INET6
explicit OptionDataListParser(const uint16_t address_family);
/// @param cfg_option_def Config option definitions (optional)
OptionDataListParser(const uint16_t address_family,
CfgOptionDefPtr cfg_option_def = 0);
/// @brief Parses a list of options, instantiates them and stores in cfg
///
......@@ -174,6 +182,9 @@ public:
private:
/// @brief Address family: @c AF_INET or @c AF_INET6
uint16_t address_family_;
/// @brief Config option definitions
CfgOptionDefPtr cfg_option_def_;
};
......
......@@ -1343,9 +1343,16 @@ TEST_F(ParseConfigTest, emptyOptionData) {
// This test verifies an option data without suboptions is supported
TEST_F(ParseConfigTest, optionDataNoSubOption) {
// Configuration string.
// Configuration string. A global definition for option 43 is needed.
const std::string config =
"{ \"option-data\": [ {"
"{ \"option-def\": [ {"
" \"name\": \"vendor-encapsulated-options\","
" \"code\": 43,"
" \"type\": \"empty\","
" \"space\": \"dhcp4\","
" \"encapsulate\": \"vendor-encapsulated-options\""
" } ],"
" \"option-data\": [ {"
" \"name\": \"vendor-encapsulated-options\""
" } ]"
"}";
......
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