Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
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
3f1577b5
Commit
3f1577b5
authored
Jan 15, 2013
by
Marcin Siodelski
Browse files
[2314] Append sub-options to DHCPv4 options.
parent
30276d77
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/config_parser.cc
View file @
3f1577b5
...
...
@@ -860,7 +860,7 @@ private:
// definition of option value makes sense.
if
(
def
->
getName
()
!=
option_name
)
{
isc_throw
(
DhcpConfigError
,
"specified option name '"
<<
option_name
<<
" does not match the "
<<
option_name
<<
"
'
does not match the "
<<
"option definition: '"
<<
option_space
<<
"."
<<
def
->
getName
()
<<
"'"
);
}
...
...
@@ -1361,6 +1361,64 @@ private:
return
(
false
);
}
/// @brief Append sub-options to an option.
///
/// @param option_space a name of the encapsulated option space.
/// @param option option instance to append sub-options to.
void
appendSubOptions
(
const
std
::
string
&
option_space
,
OptionPtr
&
option
)
{
// If invalid pointer there is nothing to do.
if
(
!
option
)
{
return
;
}
OptionDefinitionPtr
def
;
if
(
option_space
==
"dhcp4"
&&
LibDHCP
::
isStandardOption
(
Option
::
V4
,
option
->
getType
()))
{
def
=
LibDHCP
::
getOptionDef
(
Option
::
V4
,
option
->
getType
());
// Definitions for some of the standard options hasn't been
// implemented so it is ok to leave here.
if
(
!
def
)
{
return
;
}
}
else
{
const
OptionDefContainerPtr
defs
=
option_def_intermediate
.
getItems
(
option_space
);
const
OptionDefContainerTypeIndex
&
idx
=
defs
->
get
<
1
>
();
const
OptionDefContainerTypeRange
&
range
=
idx
.
equal_range
(
option
->
getType
());
// There is no definition so we have to leave.
if
(
std
::
distance
(
range
.
first
,
range
.
second
)
==
0
)
{
return
;
}
def
=
*
range
.
first
;
// If the definition exists, it must be non-NULL.
// Otherwise it is a programming error.
assert
(
def
);
}
// We need to get option definition fo the particular option space
// and code. This definition holds the information whether our
// option encapsulates any option space.
// Get the encapsulated option space name.
std
::
string
encapsulated_space
=
def
->
getEncapsulatedSpace
();
// If option space name is empty it means that our option does not
// encapsulate any option space (does not include sub-options).
if
(
!
encapsulated_space
.
empty
())
{
// Get the sub-options that belong to the encapsulated
// option space.
const
Subnet
::
OptionContainerPtr
sub_opts
=
option_defaults
.
getItems
(
encapsulated_space
);
// Append sub-options to the option.
BOOST_FOREACH
(
Subnet
::
OptionDescriptor
desc
,
*
sub_opts
)
{
if
(
desc
.
option
)
{
option
->
addOption
(
desc
.
option
);
}
}
}
}
/// @brief Create a new subnet using a data from child parsers.
///
/// @throw isc::dhcp::DhcpConfigError if subnet configuration parsing failed.
...
...
@@ -1435,6 +1493,8 @@ private:
LOG_WARN
(
dhcp4_logger
,
DHCP4_CONFIG_OPTION_DUPLICATE
)
.
arg
(
desc
.
option
->
getType
()).
arg
(
addr
.
toText
());
}
// Add sub-options (if any).
appendSubOptions
(
option_space
,
desc
.
option
);
// In any case, we add the option to the subnet.
subnet_
->
addOption
(
desc
.
option
,
false
,
option_space
);
}
...
...
@@ -1462,6 +1522,9 @@ private:
Subnet
::
OptionDescriptor
existing_desc
=
subnet_
->
getOptionDescriptor
(
option_space
,
desc
.
option
->
getType
());
if
(
!
existing_desc
.
option
)
{
// Add sub-options (if any).
appendSubOptions
(
option_space
,
desc
.
option
);
subnet_
->
addOption
(
desc
.
option
,
false
,
option_space
);
}
}
...
...
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
3f1577b5
...
...
@@ -61,7 +61,7 @@ public:
EXPECT_EQ
(
expected_value
,
it
->
second
);
}
// Checks if
config_result (
result of DHCP server configuration
)
has
// Checks if
the
result of DHCP server configuration has
// expected code (0 for success, other for failures).
// Also stores result in rcode_ and comment_.
void
checkResult
(
ConstElementPtr
status
,
int
expected_code
)
{
...
...
@@ -1079,6 +1079,166 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
ASSERT_FALSE
(
desc3
.
option
);
}
// The goal of this test is to verify that it is possible to
// encapsulate option space containing some options with
// another option. In this test we create base option that
// encapsulates option space 'isc' that comprises two other
// options. Also, for all options their definitions are
// created.
TEST_F
(
Dhcp4ParserTest
,
optionDataEncapsulate
)
{
// @todo DHCP configurations has many dependencies between
// parameters. First of all, configuration for subnet is
// inherited from the global values. Thus subnet has to be
// configured when all global values have been configured.
// Also, an option can encapsulate another option only
// if the latter has been configured. For this reason in this
// test we created two-stage configuration where first we
// created options that belong to encapsulated option space.
// In the second stage we add the base option. Also, the Subnet
// object is configured in the second stage so it is created
// at the very end (when all other parameters are configured).
// Starting stage 1. Configure sub-options and their definitions.
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
code
\"
: 1,"
"
\"
data
\"
:
\"
1234
\"
,"
"
\"
csv-format
\"
: True"
" },"
" {"
"
\"
name
\"
:
\"
foo2
\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
code
\"
: 2,"
"
\"
data
\"
:
\"
192.168.2.1
\"
,"
"
\"
csv-format
\"
: True"
" } ],"
"
\"
option-def
\"
: [ {"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
code
\"
: 1,"
"
\"
type
\"
:
\"
uint32
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
encapsulate
\"
:
\"\"
"
" },"
" {"
"
\"
name
\"
:
\"
foo2
\"
,"
"
\"
code
\"
: 2,"
"
\"
type
\"
:
\"
ipv4-address
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
encapsulate
\"
:
\"\"
"
" } ]"
"}"
;
ConstElementPtr
status
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// Stage 2. Configure base option and a subnet. Please note that
// the configuration from the stage 2 is repeated because BIND
// configuration manager sends whole configuration for the lists
// where at least one element is being modified or added.
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
base-option
\"
,"
"
\"
space
\"
:
\"
dhcp4
\"
,"
"
\"
code
\"
: 222,"
"
\"
data
\"
:
\"
11
\"
,"
"
\"
csv-format
\"
: True"
" },"
" {"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
code
\"
: 1,"
"
\"
data
\"
:
\"
1234
\"
,"
"
\"
csv-format
\"
: True"
" },"
" {"
"
\"
name
\"
:
\"
foo2
\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
code
\"
: 2,"
"
\"
data
\"
:
\"
192.168.2.1
\"
,"
"
\"
csv-format
\"
: True"
" } ],"
"
\"
option-def
\"
: [ {"
"
\"
name
\"
:
\"
base-option
\"
,"
"
\"
code
\"
: 222,"
"
\"
type
\"
:
\"
uint8
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
dhcp4
\"
,"
"
\"
encapsulate
\"
:
\"
isc
\"
"
"},"
"{"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
code
\"
: 1,"
"
\"
type
\"
:
\"
uint32
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
encapsulate
\"
:
\"\"
"
" },"
" {"
"
\"
name
\"
:
\"
foo2
\"
,"
"
\"
code
\"
: 2,"
"
\"
type
\"
:
\"
ipv4-address
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
isc
\"
,"
"
\"
encapsulate
\"
:
\"\"
"
" } ],"
"
\"
subnet4
\"
: [ { "
"
\"
pool
\"
: [
\"
192.0.2.1 - 192.0.2.100
\"
],"
"
\"
subnet
\"
:
\"
192.0.2.0/24
\"
"
" } ]"
"}"
;
json
=
Element
::
fromJSON
(
config
);
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// Get the subnet.
Subnet4Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet4
(
IOAddress
(
"192.0.2.5"
));
ASSERT_TRUE
(
subnet
);
// We should have one option available.
Subnet
::
OptionContainerPtr
options
=
subnet
->
getOptionDescriptors
(
"dhcp4"
);
ASSERT_TRUE
(
options
);
ASSERT_EQ
(
1
,
options
->
size
());
// Get the option.
Subnet
::
OptionDescriptor
desc
=
subnet
->
getOptionDescriptor
(
"dhcp4"
,
222
);
EXPECT_TRUE
(
desc
.
option
);
EXPECT_EQ
(
222
,
desc
.
option
->
getType
());
// This opton should comprise two sub-options.
// One of them is 'foo' with code 1.
OptionPtr
option_foo
=
desc
.
option
->
getOption
(
1
);
ASSERT_TRUE
(
option_foo
);
EXPECT_EQ
(
1
,
option_foo
->
getType
());
// ...another one 'foo2' with code 2.
OptionPtr
option_foo2
=
desc
.
option
->
getOption
(
2
);
ASSERT_TRUE
(
option_foo2
);
EXPECT_EQ
(
2
,
option_foo2
->
getType
());
}
// Goal of this test is to verify options configuration
// for a single subnet. In particular this test checks
// that local options configuration overrides global
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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