Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Adam Osuchowski
Kea
Commits
fb4c4a30
Commit
fb4c4a30
authored
Apr 01, 2016
by
Marcin Siodelski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[4301] Host configuration parser now supports circuit-id parameter.
parent
5adcd2c0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
216 additions
and
44 deletions
+216
-44
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/config_parser_unittest.cc
+9
-6
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
+85
-30
src/lib/dhcpsrv/parsers/host_reservation_parser.h
src/lib/dhcpsrv/parsers/host_reservation_parser.h
+50
-8
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
+72
-0
No files found.
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
fb4c4a30
...
...
@@ -3454,7 +3454,7 @@ TEST_F(Dhcp4ParserTest, reservations) {
" ]"
" },"
" {"
"
\"
hw-address
\"
:
\"
06
:
05
:
04
:
03
:
02
:
01
\"
,"
"
\"
circuit-id
\"
:
\"
060504030201
\"
,"
"
\"
ip-address
\"
:
\"
192.0.4.102
\"
,"
"
\"
hostname
\"
:
\"\"
"
" }"
...
...
@@ -3528,16 +3528,19 @@ TEST_F(Dhcp4ParserTest, reservations) {
ASSERT_TRUE
(
opt_ttl
);
EXPECT_EQ
(
32
,
static_cast
<
int
>
(
opt_ttl
->
getValue
()));
// The
HW address
used for one of the reservations in the subnet 542
// The
circuit-id
used for one of the reservations in the subnet 542
// consists of numbers from 6 to 1. So, let's just reverse the order
// of the address from the previous test.
hwaddr
->
hwaddr_
.
assign
(
hwaddr_vec
.
rbegin
(),
hwaddr_vec
.
rend
());
host
=
hosts_cfg
->
get4
(
542
,
hwaddr
);
std
::
vector
<
uint8_t
>
circuit_id
(
hwaddr_vec
.
rbegin
(),
hwaddr_vec
.
rend
());
host
=
hosts_cfg
->
get4
(
542
,
Host
::
IDENT_CIRCUIT_ID
,
&
circuit_id
[
0
],
circuit_id
.
size
());
EXPECT_TRUE
(
host
);
EXPECT_EQ
(
"192.0.4.102"
,
host
->
getIPv4Reservation
().
toText
());
// This reservation must not belong to other subnets.
EXPECT_FALSE
(
hosts_cfg
->
get4
(
123
,
hwaddr
));
EXPECT_FALSE
(
hosts_cfg
->
get4
(
234
,
hwaddr
));
EXPECT_FALSE
(
hosts_cfg
->
get4
(
123
,
Host
::
IDENT_CIRCUIT_ID
,
&
circuit_id
[
0
],
circuit_id
.
size
()));
EXPECT_FALSE
(
hosts_cfg
->
get4
(
234
,
Host
::
IDENT_CIRCUIT_ID
,
&
circuit_id
[
0
],
circuit_id
.
size
()));
// Repeat the test for the DUID based reservation in this subnet.
duid
.
reset
(
new
DUID
(
std
::
vector
<
uint8_t
>
(
duid_vec
.
rbegin
(),
...
...
src/lib/dhcpsrv/parsers/host_reservation_parser.cc
View file @
fb4c4a30
...
...
@@ -12,6 +12,7 @@
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <sys/socket.h>
#include <sstream>
#include <string>
using
namespace
isc
::
asiolink
;
...
...
@@ -23,36 +24,62 @@ namespace {
///
/// This function returns the set of supported parameters for
/// host reservation in DHCPv4.
const
std
::
set
<
std
::
string
>&
getSupportedParams4
()
{
///
/// @param identifiers_only Indicates if the function should only
/// return supported host identifiers (if true) or all supported
/// parameters (if false).
const
std
::
set
<
std
::
string
>&
getSupportedParams4
(
const
bool
identifiers_only
=
false
)
{
// Holds set of host identifiers.
static
std
::
set
<
std
::
string
>
identifiers_set
;
// Holds set of all supported parameters, including identifiers.
static
std
::
set
<
std
::
string
>
params_set
;
// If this is first execution of this function, we need
// to initialize the set.
if
(
identifiers_set
.
empty
())
{
identifiers_set
.
insert
(
"duid"
);
identifiers_set
.
insert
(
"hw-address"
);
identifiers_set
.
insert
(
"circuit-id"
);
}
// Copy identifiers and add all other parameters.
if
(
params_set
.
empty
())
{
const
char
*
params
[]
=
{
"duid"
,
"hw-address"
,
"hostname"
,
"ip-address"
,
"option-data"
,
NULL
};
for
(
int
i
=
0
;
params
[
i
]
!=
NULL
;
++
i
)
{
params_set
.
insert
(
std
::
string
(
params
[
i
]));
}
params_set
=
identifiers_set
;
params_set
.
insert
(
"hostname"
);
params_set
.
insert
(
"ip-address"
);
params_set
.
insert
(
"option-data"
);
}
return
(
params_set
);
return
(
identifiers_only
?
identifiers_set
:
params_set
);
}
/// @brief Returns set of the supported parameters for DHCPv
4
.
/// @brief Returns set of the supported parameters for DHCPv
6
.
///
/// This function returns the set of supported parameters for
/// host reservation in DHCPv6.
const
std
::
set
<
std
::
string
>&
getSupportedParams6
()
{
///
/// @param identifiers_only Indicates if the function should only
/// return supported host identifiers (if true) or all supported
/// parameters (if false).
const
std
::
set
<
std
::
string
>&
getSupportedParams6
(
const
bool
identifiers_only
=
false
)
{
// Holds set of host identifiers.
static
std
::
set
<
std
::
string
>
identifiers_set
;
// Holds set of all supported parameters, including identifiers.
static
std
::
set
<
std
::
string
>
params_set
;
// If this is first execution of this function, we need
// to initialize the set.
if
(
identifiers_set
.
empty
())
{
identifiers_set
.
insert
(
"duid"
);
identifiers_set
.
insert
(
"hw-address"
);
}
// Copy identifiers and add all other parameters.
if
(
params_set
.
empty
())
{
const
char
*
params
[]
=
{
"duid"
,
"hw-address"
,
"hostname"
,
"ip-addresses"
,
"prefixes"
,
"option-data"
,
NULL
};
for
(
int
i
=
0
;
params
[
i
]
!=
NULL
;
++
i
)
{
params_set
.
insert
(
std
::
string
(
params
[
i
]));
}
params_set
=
identifiers_set
;
params_set
.
insert
(
"hostname"
);
params_set
.
insert
(
"ip-addresses"
);
params_set
.
insert
(
"prefixes"
);
params_set
.
insert
(
"option-data"
);
}
return
(
params_set
);
return
(
identifiers_only
?
identifiers_set
:
params_set
);
}
}
...
...
@@ -80,10 +107,11 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) {
" parameter '"
<<
element
.
first
<<
"'"
);
}
if
(
element
.
first
==
"hw-address"
||
element
.
first
==
"duid"
)
{
if
(
!
identifier_name
.
empty
())
{
isc_throw
(
DhcpConfigError
,
"the 'hw-address' and 'duid'"
" parameters are mutually exclusive"
);
if
(
isIdentifierParameter
(
element
.
first
))
{
if
(
!
identifier
.
empty
())
{
isc_throw
(
DhcpConfigError
,
"the '"
<<
element
.
first
<<
"' and '"
<<
identifier_name
<<
"' are mutually exclusive"
);
}
identifier
=
element
.
second
->
stringValue
();
identifier_name
=
element
.
first
;
...
...
@@ -100,10 +128,22 @@ HostReservationParser::build(isc::data::ConstElementPtr reservation_data) {
}
try
{
//
hw-address or duid
is a must.
//
Host identifier
is a must.
if
(
identifier_name
.
empty
())
{
isc_throw
(
DhcpConfigError
,
"'hw-address' or 'duid' is a required"
" parameter for host reservation"
);
// If there is no identifier specified, we have to display an
// error message and include the information what identifiers
// are supported.
std
::
ostringstream
s
;
BOOST_FOREACH
(
std
::
string
param_name
,
getSupportedParameters
(
true
))
{
if
(
s
.
tellp
()
!=
std
::
streampos
(
0
))
{
s
<<
", "
;
}
s
<<
param_name
;
}
isc_throw
(
DhcpConfigError
,
"one of the supported identifiers must"
" be specified for host reservation: "
<<
s
.
str
());
}
// Create a host object from the basic parameters we already parsed.
...
...
@@ -129,6 +169,11 @@ HostReservationParser::addHost(isc::data::ConstElementPtr reservation_data) {
}
}
bool
HostReservationParser
::
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
{
return
(
getSupportedParameters
(
false
).
count
(
param_name
)
>
0
);
}
HostReservationParser4
::
HostReservationParser4
(
const
SubnetID
&
subnet_id
)
:
HostReservationParser
(
subnet_id
)
{
}
...
...
@@ -168,8 +213,13 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) {
}
bool
HostReservationParser4
::
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
{
return
(
getSupportedParams4
().
count
(
param_name
)
>
0
);
HostReservationParser4
::
isIdentifierParameter
(
const
std
::
string
&
param_name
)
const
{
return
(
getSupportedParams4
(
true
).
count
(
param_name
)
>
0
);
}
const
std
::
set
<
std
::
string
>&
HostReservationParser4
::
getSupportedParameters
(
const
bool
identifiers_only
)
const
{
return
(
getSupportedParams4
(
identifiers_only
));
}
HostReservationParser6
::
HostReservationParser6
(
const
SubnetID
&
subnet_id
)
...
...
@@ -263,8 +313,13 @@ HostReservationParser6::build(isc::data::ConstElementPtr reservation_data) {
}
bool
HostReservationParser6
::
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
{
return
(
getSupportedParams6
().
count
(
param_name
)
>
0
);
HostReservationParser6
::
isIdentifierParameter
(
const
std
::
string
&
param_name
)
const
{
return
(
getSupportedParams6
(
true
).
count
(
param_name
)
>
0
);
}
const
std
::
set
<
std
::
string
>&
HostReservationParser6
::
getSupportedParameters
(
const
bool
identifiers_only
)
const
{
return
(
getSupportedParams6
(
identifiers_only
));
}
}
// end of namespace isc::dhcp
...
...
src/lib/dhcpsrv/parsers/host_reservation_parser.h
View file @
fb4c4a30
// Copyright (C) 2014-201
5
Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-201
6
Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
...
...
@@ -48,12 +48,30 @@ protected:
/// @throw DhcpConfigError When operation to add a configured host fails.
void
addHost
(
isc
::
data
::
ConstElementPtr
reservation_data
);
/// @brief Checks if the specified parameter is a host identifier.
///
/// @param param_name Parameter name.
///
/// @return true if the parameter specifies host identifier, false
/// otherwise.
virtual
bool
isIdentifierParameter
(
const
std
::
string
&
param_name
)
const
=
0
;
/// @brief Checks if the specified parameter is supported by the parser.
///
/// @param param_name Parameter name.
///
/// @return true if the parameter is supported, false otherwise.
virtual
bool
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
=
0
;
virtual
bool
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
;
/// @brief Returns set of the supported parameters.
///
/// @param identifiers_only Indicates if the function should only
/// return supported host identifiers (if true) or all supported
/// parameters (if false).
///
/// @return Set of supported parameter names.
virtual
const
std
::
set
<
std
::
string
>&
getSupportedParameters
(
const
bool
identifiers_only
)
const
=
0
;
/// @brief Identifier of the subnet that the host is connected to.
SubnetID
subnet_id_
;
...
...
@@ -84,12 +102,24 @@ public:
protected:
/// @brief Checks if the specified parameter is
supported by the pars
er.
/// @brief Checks if the specified parameter is
a host identifi
er.
///
/// @param param_name Parameter name.
///
/// @return true if the parameter is supported, false otherwise.
virtual
bool
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
;
/// @return true if the parameter specifies host identifier, false
/// otherwise.
virtual
bool
isIdentifierParameter
(
const
std
::
string
&
param_name
)
const
;
/// @brief Returns set of the supported parameters for DHCPv4.
///
/// @param identifiers_only Indicates if the function should only
/// return supported host identifiers (if true) or all supported
/// parameters (if false).
///
/// @return Set of supported parameter names.
virtual
const
std
::
set
<
std
::
string
>&
getSupportedParameters
(
const
bool
identifiers_only
)
const
;
};
/// @brief Parser for a single host reservation for DHCPv6.
...
...
@@ -112,12 +142,24 @@ public:
protected:
/// @brief Checks if the specified parameter is
supported by the pars
er.
/// @brief Checks if the specified parameter is
a host identifi
er.
///
/// @param param_name Parameter name.
///
/// @return true if the parameter is supported, false otherwise.
virtual
bool
isSupportedParameter
(
const
std
::
string
&
param_name
)
const
;
/// @return true if the parameter specifies host identifier, false
/// otherwise.
virtual
bool
isIdentifierParameter
(
const
std
::
string
&
param_name
)
const
;
/// @brief Returns set of the supported parameters for DHCPv6.
///
/// @param identifiers_only Indicates if the function should only
/// return supported host identifiers (if true) or all supported
/// parameters (if false).
///
/// @return Set of supported parameter names.
virtual
const
std
::
set
<
std
::
string
>&
getSupportedParameters
(
const
bool
identifiers_only
)
const
;
};
...
...
src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
View file @
fb4c4a30
...
...
@@ -21,6 +21,7 @@
#include <gtest/gtest.h>
#include <iterator>
#include <string>
#include <vector>
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
data
;
...
...
@@ -126,6 +127,40 @@ protected:
EXPECT_TRUE
(
hosts
[
0
]
->
getCfgOption6
()
->
empty
());
}
/// @brief This test verfies that the parser can parse a DHCPv4
/// reservation configuration including a specific identifier.
///
/// @param identifier_name Identifier name.
/// @param identifier_type Identifier type.
void
testIdentifier4
(
const
std
::
string
&
identifier_name
,
const
std
::
string
&
identifier_value
,
const
Host
::
IdentifierType
&
expected_identifier_type
,
const
std
::
vector
<
uint8_t
>&
expected_identifier
)
const
{
std
::
ostringstream
config
;
config
<<
"{
\"
"
<<
identifier_name
<<
"
\"
:
\"
"
<<
identifier_value
<<
"
\"
,"
<<
"
\"
ip-address
\"
:
\"
192.0.2.112
\"
,"
<<
"
\"
hostname
\"
:
\"\"
}"
;
ElementPtr
config_element
=
Element
::
fromJSON
(
config
.
str
());
HostReservationParser4
parser
(
SubnetID
(
10
));
ASSERT_NO_THROW
(
parser
.
build
(
config_element
));
CfgHostsPtr
cfg_hosts
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgHosts
();
HostCollection
hosts
;
ASSERT_NO_THROW
(
hosts
=
cfg_hosts
->
getAll
(
expected_identifier_type
,
&
expected_identifier
[
0
],
expected_identifier
.
size
()));
ASSERT_EQ
(
1
,
hosts
.
size
());
EXPECT_EQ
(
10
,
hosts
[
0
]
->
getIPv4SubnetID
());
EXPECT_EQ
(
0
,
hosts
[
0
]
->
getIPv6SubnetID
());
EXPECT_EQ
(
"192.0.2.112"
,
hosts
[
0
]
->
getIPv4Reservation
().
toText
());
EXPECT_TRUE
(
hosts
[
0
]
->
getHostname
().
empty
());
}
/// @brief This test verfies that the parser returns an error when
/// configuration is invalid.
///
...
...
@@ -144,6 +179,8 @@ protected:
/// @brief DUID object used by tests.
DuidPtr
duid_
;
/// @brief Vector holding circuit id used by tests.
std
::
vector
<
uint8_t
>
circuit_id_
;
};
void
...
...
@@ -158,6 +195,9 @@ HostReservationParserTest::SetUp() {
const
uint8_t
duid_data
[]
=
{
0x01
,
0x02
,
0x03
,
0x04
,
0x05
,
0x06
,
0x07
,
0x08
,
0x09
,
0x0A
};
duid_
=
DuidPtr
(
new
DUID
(
duid_data
,
sizeof
(
duid_data
)));
const
std
::
string
circuit_id_str
=
"howdy"
;
circuit_id_
.
assign
(
circuit_id_str
.
begin
(),
circuit_id_str
.
end
());
}
void
...
...
@@ -213,6 +253,22 @@ TEST_F(HostReservationParserTest, dhcp4DUID) {
EXPECT_TRUE
(
hosts
[
0
]
->
getHostname
().
empty
());
}
// This test verifies that the parser can parse a reservation entry for
// which circuit-id is an identifier. The circuit-id is specified as
// a string in quotes.
TEST_F
(
HostReservationParserTest
,
dhcp4CircuitIdStringInQuotes
)
{
testIdentifier4
(
"circuit-id"
,
"'howdy'"
,
Host
::
IDENT_CIRCUIT_ID
,
circuit_id_
);
}
// This test verifies that the parser can parse a reservation entry for
// which circuit-id is an identifier. The circuit-id is specified in
// hexadecimal format.
TEST_F
(
HostReservationParserTest
,
dhcp4CircuitIdHex
)
{
testIdentifier4
(
"circuit-id"
,
"686F776479"
,
Host
::
IDENT_CIRCUIT_ID
,
circuit_id_
);
}
// This test verifies that the parser can parse the reservation entry
// when IPv4 address is specified, but hostname is not.
TEST_F
(
HostReservationParserTest
,
dhcp4NoHostname
)
{
...
...
@@ -447,6 +503,22 @@ TEST_F(HostReservationParserTest, dhcp6DUID) {
ASSERT_EQ
(
0
,
std
::
distance
(
prefixes
.
first
,
prefixes
.
second
));
}
// This test verifies that host reservation parser for DHCPv6 rejects
// "circuit-id" as a host identifier.
TEST_F
(
HostReservationParserTest
,
dhcp6CircuitId
)
{
// Use DHCPv4 specific identifier 'circuit-id' with DHCPv6 parser.
std
::
string
config
=
"{
\"
circuit-id
\"
:
\"
'howdy'
\"
,"
"
\"
ip-addresses
\"
: [
\"
2001:db8:1::100
\"
,
\"
2001:db8:1::200
\"
],"
"
\"
prefixes
\"
: [ ],"
"
\"
hostname
\"
:
\"
foo.example.com
\"
}"
;
ElementPtr
config_element
=
Element
::
fromJSON
(
config
);
// The parser should throw exception.
HostReservationParser6
parser
(
SubnetID
(
12
));
EXPECT_THROW
(
parser
.
build
(
config_element
),
DhcpConfigError
);
}
// This test verfies that the parser can parse the IPv6 reservation entry
// which lacks hostname parameter.
TEST_F
(
HostReservationParserTest
,
dhcp6NoHostname
)
{
...
...
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