Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
38ebe09e
Commit
38ebe09e
authored
Nov 02, 2012
by
Marcin Siodelski
Browse files
[2417] Create basic set of stdandard DHCPv6 option definition instances.
parent
e8a6aee2
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp6/config_parser.cc
View file @
38ebe09e
...
...
@@ -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.
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
38ebe09e
...
...
@@ -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
);
}
src/bin/dhcp6/dhcp6_srv.h
View file @
38ebe09e
...
...
@@ -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_
;
...
...
src/bin/dhcp6/tests/config_parser_unittest.cc
View file @
38ebe09e
...
...
@@ -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
(
param
eter
==
"
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
());
}
};
src/lib/dhcp/libdhcp++.cc
View file @
38ebe09e
...
...
@@ -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
:
defin
i
tion
->
addRecordField
(
OptionDefinition
::
UINT16_TYPE
);
defin
o
tion
->
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
);
}
}
src/lib/dhcp/libdhcp++.h
View file @
38ebe09e
...
...
@@ -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_
;
};
}
...
...
src/lib/dhcp/tests/libdhcp++_unittest.cc
View file @
38ebe09e
...
...
@@ -64,8 +64,8 @@ public:
static
void
testInitOptionDefs6
(
const
uint16_t
code
,
const
OptionBuffer
&
buf
,
const
std
::
type_info
&
expected_type
)
{
OptionDefContainer
options
;
LibDHCP
::
initStd
OptionDefs
6
(
o
ption
s
);
LibDHCP
::
initStdOptionDefs
(
Option
::
V6
)
;
OptionDefContainer
options
=
LibDHCP
::
get
OptionDefs
(
O
ption
::
V6
);
const
OptionDefContainerTypeIndex
&
idx
=
options
.
get
<
1
>
();
OptionDefContainerTypeRange
range
=
idx
.
equal_range
(
code
);
ASSERT_EQ
(
1
,
std
::
distance
(
range
.
first
,
range
.
second
));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment