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
4650a922
Commit
4650a922
authored
Jul 07, 2017
by
Francis Dupont
Browse files
[5241] Added the function in DHCPv4 and 6 servers
parent
ac7850b4
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
4650a922
...
...
@@ -1226,21 +1226,37 @@ Dhcpv4Srv::appendRequestedOptions(Dhcpv4Exchange& ex) {
}
Pkt4Ptr
query
=
ex
.
getQuery
();
Pkt4Ptr
resp
=
ex
.
getResponse
();
std
::
vector
<
uint8_t
>
requested_opts
;
// try to get the 'Parameter Request List' option which holds the
// codes of requested options.
OptionUint8ArrayPtr
option_prl
=
boost
::
dynamic_pointer_cast
<
OptionUint8Array
>
(
query
->
getOption
(
DHO_DHCP_PARAMETER_REQUEST_LIST
));
// If there is no PRL option in the message from the client then
// there is nothing to do.
if
(
!
option_prl
)
{
return
;
// Get the codes of requested options.
if
(
option_prl
)
{
requested_opts
=
option_prl
->
getValues
();
}
// Iterate on the configured option list to add persistent options
for
(
CfgOptionList
::
const_iterator
copts
=
co_list
.
begin
();
copts
!=
co_list
.
end
();
++
copts
)
{
const
OptionContainerPtr
&
opts
=
(
*
copts
)
->
getAll
(
DHCP4_OPTION_SPACE
);
if
(
!
opts
)
{
continue
;
}
// Get persistent options
const
OptionContainerPersistIndex
&
idx
=
opts
->
get
<
2
>
();
const
OptionContainerPersistRange
&
range
=
idx
.
equal_range
(
true
);
for
(
OptionContainerPersistIndex
::
const_iterator
desc
=
range
.
first
;
desc
!=
range
.
second
;
++
desc
)
{
// Add the persistent option code to requested options
if
(
desc
->
option_
)
{
uint8_t
code
=
static_cast
<
uint8_t
>
(
desc
->
option_
->
getType
());
requested_opts
.
push_back
(
code
);
}
}
}
Pkt4Ptr
resp
=
ex
.
getResponse
();
// Get the codes of requested options.
const
std
::
vector
<
uint8_t
>&
requested_opts
=
option_prl
->
getValues
();
// For each requested option code get the instance of the option
// to be returned to the client.
for
(
std
::
vector
<
uint8_t
>::
const_iterator
opt
=
requested_opts
.
begin
();
...
...
@@ -1288,15 +1304,39 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
}
uint32_t
vendor_id
=
vendor_req
->
getVendorId
();
std
::
vector
<
uint8_t
>
requested_opts
;
// Let's try to get ORO within that vendor-option
/// @todo This is very specific to vendor-id=4491 (Cable Labs). Other
/// vendors may have different policies.
OptionUint8ArrayPtr
oro
=
boost
::
dynamic_pointer_cast
<
OptionUint8Array
>
(
vendor_req
->
getOption
(
DOCSIS3_V4_ORO
));
// Get the list of options that client requested.
if
(
oro
)
{
requested_opts
=
oro
->
getValues
();
}
// Iterate on the configured option list to add persistent options
for
(
CfgOptionList
::
const_iterator
copts
=
co_list
.
begin
();
copts
!=
co_list
.
end
();
++
copts
)
{
const
OptionContainerPtr
&
opts
=
(
*
copts
)
->
getAll
(
vendor_id
);
if
(
!
opts
)
{
continue
;
}
// Get persistent options
const
OptionContainerPersistIndex
&
idx
=
opts
->
get
<
2
>
();
const
OptionContainerPersistRange
&
range
=
idx
.
equal_range
(
true
);
for
(
OptionContainerPersistIndex
::
const_iterator
desc
=
range
.
first
;
desc
!=
range
.
second
;
++
desc
)
{
// Add the persistent option code to requested options
if
(
desc
->
option_
)
{
uint8_t
code
=
static_cast
<
uint8_t
>
(
desc
->
option_
->
getType
());
requested_opts
.
push_back
(
code
);
}
}
}
//
Option ORO not found. D
on't do anything then.
if
(
!
oro
)
{
//
If there is nothing to add d
on't do anything then.
if
(
requested_opts
.
empty
()
)
{
return
;
}
...
...
@@ -1304,8 +1344,6 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
// Get the list of options that client requested.
bool
added
=
false
;
const
std
::
vector
<
uint8_t
>&
requested_opts
=
oro
->
getValues
();
for
(
std
::
vector
<
uint8_t
>::
const_iterator
code
=
requested_opts
.
begin
();
code
!=
requested_opts
.
end
();
++
code
)
{
if
(
!
vendor_rsp
->
getOption
(
*
code
))
{
...
...
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
4650a922
...
...
@@ -2820,7 +2820,7 @@ TEST_F(Dhcp4ParserTest, optionDataSinglePool) {
// Expect a single option with the code equal to 100.
ASSERT_EQ
(
1
,
std
::
distance
(
range
.
first
,
range
.
second
));
const
uint8_t
foo_expected
[]
=
{
0xAB
,
0xCD
,
0xEF
,
0x01
,
0x05
0xAB
,
0xCD
,
0xEF
,
0x01
,
0x05
};
// Check if option is valid in terms of code and carried data.
testOption
(
*
range
.
first
,
56
,
foo_expected
,
sizeof
(
foo_expected
));
...
...
@@ -2893,7 +2893,7 @@ TEST_F(Dhcp4ParserTest, optionDataMultiplePools) {
// Expect a single option with the code equal to 100.
ASSERT_EQ
(
1
,
std
::
distance
(
range1
.
first
,
range1
.
second
));
const
uint8_t
foo_expected
[]
=
{
0xAB
,
0xCD
,
0xEF
,
0x01
,
0x05
0xAB
,
0xCD
,
0xEF
,
0x01
,
0x05
};
// Check if option is valid in terms of code and carried data.
testOption
(
*
range1
.
first
,
56
,
foo_expected
,
sizeof
(
foo_expected
));
...
...
@@ -2909,8 +2909,8 @@ TEST_F(Dhcp4ParserTest, optionDataMultiplePools) {
const
OptionContainerTypeIndex
&
idx2
=
options2
->
get
<
1
>
();
std
::
pair
<
OptionContainerTypeIndex
::
const_iterator
,
OptionContainerTypeIndex
::
const_iterator
>
range2
=
idx2
.
equal_range
(
23
);
OptionContainerTypeIndex
::
const_iterator
>
range2
=
idx2
.
equal_range
(
23
);
ASSERT_EQ
(
1
,
std
::
distance
(
range2
.
first
,
range2
.
second
));
const
uint8_t
foo2_expected
[]
=
{
0x01
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
4650a922
...
...
@@ -1451,6 +1451,89 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsORO) {
EXPECT_EQ
(
"192.0.2.2"
,
addrs
[
1
].
toText
());
}
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
// vendor options is parsed correctly and persistent options are actually assigned.
TEST_F
(
Dhcpv4SrvTest
,
vendorPersistentOptions
)
{
IfaceMgrTestConfig
test_config
(
true
);
IfaceMgr
::
instance
().
openSockets4
();
NakedDhcpv4Srv
srv
(
0
);
ConstElementPtr
x
;
string
config
=
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
]"
"},"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
tftp-servers
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
code
\"
: 2,"
"
\"
data
\"
:
\"
192.0.2.1, 192.0.2.2
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
persistent
\"
: true"
" }],"
"
\"
subnet4
\"
: [ { "
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
192.0.2.0/25
\"
} ],"
"
\"
subnet
\"
:
\"
192.0.2.0/24
\"
, "
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000,"
"
\"
interface
\"
:
\"
eth0
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
;
ConstElementPtr
json
;
ASSERT_NO_THROW
(
json
=
parseDHCP4
(
config
));
EXPECT_NO_THROW
(
x
=
configureDhcp4Server
(
srv
,
json
));
ASSERT_TRUE
(
x
);
comment_
=
isc
::
config
::
parseAnswer
(
rcode_
,
x
);
ASSERT_EQ
(
0
,
rcode_
);
CfgMgr
::
instance
().
commit
();
boost
::
shared_ptr
<
Pkt4
>
dis
(
new
Pkt4
(
DHCPDISCOVER
,
1234
));
// Set the giaddr and hops to non-zero address as if it was relayed.
dis
->
setGiaddr
(
IOAddress
(
"192.0.2.1"
));
dis
->
setHops
(
1
);
OptionPtr
clientid
=
generateClientId
();
dis
->
addOption
(
clientid
);
// Set interface. It is required by the server to generate server id.
dis
->
setIface
(
"eth0"
);
// Let's add a vendor-option (vendor-id=4491).
OptionPtr
vendor
(
new
OptionVendor
(
Option
::
V4
,
4491
));
dis
->
addOption
(
vendor
);
// Pass it to the server and get an advertise
Pkt4Ptr
offer
=
srv
.
processDiscover
(
dis
);
// check if we get response at all
ASSERT_TRUE
(
offer
);
// Check if there is a vendor option response
OptionPtr
tmp
=
offer
->
getOption
(
DHO_VIVSO_SUBOPTIONS
);
ASSERT_TRUE
(
tmp
);
// The response should be OptionVendor object
boost
::
shared_ptr
<
OptionVendor
>
vendor_resp
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
tmp
);
ASSERT_TRUE
(
vendor_resp
);
OptionPtr
docsis2
=
vendor_resp
->
getOption
(
DOCSIS3_V4_TFTP_SERVERS
);
ASSERT_TRUE
(
docsis2
);
Option4AddrLstPtr
tftp_srvs
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
docsis2
);
ASSERT_TRUE
(
tftp_srvs
);
Option4AddrLst
::
AddressContainer
addrs
=
tftp_srvs
->
getAddresses
();
ASSERT_EQ
(
2
,
addrs
.
size
());
EXPECT_EQ
(
"192.0.2.1"
,
addrs
[
0
].
toText
());
EXPECT_EQ
(
"192.0.2.2"
,
addrs
[
1
].
toText
());
}
// Test checks whether it is possible to use option definitions defined in
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F
(
Dhcpv4SrvTest
,
vendorOptionsDocsisDefinitions
)
{
...
...
@@ -1952,6 +2035,85 @@ TEST_F(Dhcpv4SrvTest, classGlobalPriority) {
EXPECT_NE
(
0
,
opt
->
getUint8
());
}
// Checks class options have the priority over global persistent options
TEST_F
(
Dhcpv4SrvTest
,
classGlobalPersistency
)
{
IfaceMgrTestConfig
test_config
(
true
);
IfaceMgr
::
instance
().
openSockets4
();
NakedDhcpv4Srv
srv
(
0
);
// A global ip-forwarding option is set in the response.
// The router class matches incoming packets with foo in a host-name
// option (code 12) and sets an ip-forwarding option in the response.
// Note the persistency flag follows a "OR" semantic so to set
// it to false (or to leave the default) has no effect.
string
config
=
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
] }, "
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000, "
"
\"
subnet4
\"
: [ "
"{
\"
pools
\"
: [ {
\"
pool
\"
:
\"
192.0.2.1 - 192.0.2.100
\"
} ], "
"
\"
subnet
\"
:
\"
192.0.2.0/24
\"
} ], "
"
\"
option-data
\"
: ["
" {
\"
name
\"
:
\"
ip-forwarding
\"
, "
"
\"
data
\"
:
\"
false
\"
, "
"
\"
persistent
\"
: true } ], "
"
\"
client-classes
\"
: [ "
"{
\"
name
\"
:
\"
router
\"
,"
"
\"
option-data
\"
: ["
" {
\"
name
\"
:
\"
ip-forwarding
\"
, "
"
\"
data
\"
:
\"
true
\"
, "
"
\"
persistent
\"
: false } ], "
"
\"
test
\"
:
\"
option[12].text == 'foo'
\"
} ] }"
;
ConstElementPtr
json
;
ASSERT_NO_THROW
(
json
=
parseDHCP4
(
config
));
ConstElementPtr
status
;
// Configure the server and make sure the config is accepted
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
srv
,
json
));
ASSERT_TRUE
(
status
);
comment_
=
config
::
parseAnswer
(
rcode_
,
status
);
ASSERT_EQ
(
0
,
rcode_
);
CfgMgr
::
instance
().
commit
();
// Create a packet with enough to select the subnet and go through
// the DISCOVER processing
Pkt4Ptr
query
(
new
Pkt4
(
DHCPDISCOVER
,
1234
));
query
->
setRemoteAddr
(
IOAddress
(
"192.0.2.1"
));
OptionPtr
clientid
=
generateClientId
();
query
->
addOption
(
clientid
);
query
->
setIface
(
"eth1"
);
// Do not add a PRL
OptionPtr
prl
=
query
->
getOption
(
DHO_DHCP_PARAMETER_REQUEST_LIST
);
EXPECT_FALSE
(
prl
);
// Create and add a host-name option to the query
OptionStringPtr
hostname
(
new
OptionString
(
Option
::
V4
,
12
,
"foo"
));
ASSERT_TRUE
(
hostname
);
query
->
addOption
(
hostname
);
// Classify the packet
srv
.
classifyPacket
(
query
);
// The packet should be in the router class
EXPECT_TRUE
(
query
->
inClass
(
"router"
));
// Process the query
Pkt4Ptr
response
=
srv
.
processDiscover
(
query
);
// Processing should add an ip-forwarding option
OptionPtr
opt
=
response
->
getOption
(
DHO_IP_FORWARDING
);
ASSERT_TRUE
(
opt
);
ASSERT_GT
(
opt
->
len
(),
opt
->
getHeaderLen
());
// Classification sets the value to true/1, global to false/0
// Here class has the priority
EXPECT_NE
(
0
,
opt
->
getUint8
());
}
// Checks if the client-class field is indeed used for subnet selection.
// Note that packet classification is already checked in Dhcpv4SrvTest
// .*Classification above.
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
4650a922
...
...
@@ -918,20 +918,39 @@ void
Dhcpv6Srv
::
appendRequestedOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
,
const
CfgOptionList
&
co_list
)
{
// Unlikely short cut
if
(
co_list
.
empty
())
{
return
;
}
std
::
vector
<
uint16_t
>
requested_opts
;
// Client requests some options using ORO option. Try to
// get this option from client's message.
boost
::
shared_ptr
<
OptionIntArray
<
uint16_t
>
>
option_oro
=
boost
::
dynamic_pointer_cast
<
OptionIntArray
<
uint16_t
>
>
(
question
->
getOption
(
D6O_ORO
));
// If there is no ORO option, there is nothing more to do.
if
(
!
option_oro
)
{
return
;
}
// Get the list of options that client requested.
const
std
::
vector
<
uint16_t
>&
requested_opts
=
option_oro
->
getValues
();
if
(
option_oro
)
{
requested_opts
=
option_oro
->
getValues
();
}
// Iterate on the configured option list to add persistent options
for
(
CfgOptionList
::
const_iterator
copts
=
co_list
.
begin
();
copts
!=
co_list
.
end
();
++
copts
)
{
const
OptionContainerPtr
&
opts
=
(
*
copts
)
->
getAll
(
DHCP6_OPTION_SPACE
);
if
(
!
opts
)
{
continue
;
}
// Get persistent options
const
OptionContainerPersistIndex
&
idx
=
opts
->
get
<
2
>
();
const
OptionContainerPersistRange
&
range
=
idx
.
equal_range
(
true
);
for
(
OptionContainerPersistIndex
::
const_iterator
desc
=
range
.
first
;
desc
!=
range
.
second
;
++
desc
)
{
// Add the persistent option code to requested options
requested_opts
.
push_back
(
desc
->
option_
->
getType
());
}
}
BOOST_FOREACH
(
uint16_t
opt
,
requested_opts
)
{
// Iterate on the configured option list
...
...
@@ -969,24 +988,44 @@ Dhcpv6Srv::appendRequestedVendorOptions(const Pkt6Ptr& question,
return
;
}
uint32_t
vendor_id
=
vendor_req
->
getVendorId
();
std
::
vector
<
uint16_t
>
requested_opts
;
// Let's try to get ORO within that vendor-option
/// @todo This is very specific to vendor-id=4491 (Cable Labs). Other vendors
/// may have different policies.
boost
::
shared_ptr
<
OptionUint16Array
>
oro
=
boost
::
dynamic_pointer_cast
<
OptionUint16Array
>
(
vendor_req
->
getOption
(
DOCSIS3_V6_ORO
));
if
(
oro
)
{
requested_opts
=
oro
->
getValues
();
}
// Iterate on the configured option list to add persistent options
for
(
CfgOptionList
::
const_iterator
copts
=
co_list
.
begin
();
copts
!=
co_list
.
end
();
++
copts
)
{
const
OptionContainerPtr
&
opts
=
(
*
copts
)
->
getAll
(
vendor_id
);
if
(
!
opts
)
{
continue
;
}
// Get persistent options
const
OptionContainerPersistIndex
&
idx
=
opts
->
get
<
2
>
();
const
OptionContainerPersistRange
&
range
=
idx
.
equal_range
(
true
);
for
(
OptionContainerPersistIndex
::
const_iterator
desc
=
range
.
first
;
desc
!=
range
.
second
;
++
desc
)
{
// Add the persistent option code to requested options
requested_opts
.
push_back
(
desc
->
option_
->
getType
());
}
}
//
Option ORO not found. D
on't do anything then.
if
(
!
oro
)
{
//
If there is nothing to add d
on't do anything then.
if
(
requested_opts
.
empty
()
)
{
return
;
}
uint32_t
vendor_id
=
vendor_req
->
getVendorId
();
boost
::
shared_ptr
<
OptionVendor
>
vendor_rsp
(
new
OptionVendor
(
Option
::
V6
,
vendor_id
));
// Get the list of options that client requested.
bool
added
=
false
;
const
std
::
vector
<
uint16_t
>&
requested_opts
=
oro
->
getValues
();
BOOST_FOREACH
(
uint16_t
opt
,
requested_opts
)
{
for
(
CfgOptionList
::
const_iterator
copts
=
co_list
.
begin
();
copts
!=
co_list
.
end
();
++
copts
)
{
...
...
src/bin/dhcp6/tests/classify_unittests.cc
View file @
4650a922
// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016
-2017
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
...
...
@@ -518,6 +518,74 @@ TEST_F(ClassifyTest, classGlobalPriority) {
EXPECT_NE
(
0
,
opt
->
getUint8
());
}
// Checks class options have the priority over global persistent options
TEST_F
(
ClassifyTest
,
classGlobalPersistency
)
{
IfaceMgrTestConfig
test_config
(
true
);
NakedDhcpv6Srv
srv
(
0
);
// Subnet sets an ipv6-forwarding option in the response.
// The router class matches incoming packets with foo in a host-name
// option (code 1234) and sets an ipv6-forwarding option in the response.
// Note the persistency flag follows a "OR" semantic so to set
// it to false (or to leave the default) has no effect.
std
::
string
config
=
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
] }, "
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000, "
"
\"
option-def
\"
: [ "
"{
\"
name
\"
:
\"
host-name
\"
,"
"
\"
code
\"
: 1234,"
"
\"
type
\"
:
\"
string
\"
},"
"{
\"
name
\"
:
\"
ipv6-forwarding
\"
,"
"
\"
code
\"
: 2345,"
"
\"
type
\"
:
\"
boolean
\"
}],"
"
\"
option-data
\"
: ["
" {
\"
name
\"
:
\"
ipv6-forwarding
\"
, "
"
\"
data
\"
:
\"
false
\"
, "
"
\"
persistent
\"
: true } ], "
"
\"
subnet6
\"
: [ "
"{
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8:1::/64
\"
} ], "
"
\"
subnet
\"
:
\"
2001:db8:1::/48
\"
, "
"
\"
interface
\"
:
\"
eth1
\"
, "
"
\"
option-data
\"
: ["
" {
\"
name
\"
:
\"
ipv6-forwarding
\"
, "
"
\"
data
\"
:
\"
false
\"
, "
"
\"
persistent
\"
: false } ] } ] }"
;
ASSERT_NO_THROW
(
configure
(
config
));
// Create a packet with enough to select the subnet and go through
// the SOLICIT processing
Pkt6Ptr
query
(
new
Pkt6
(
DHCPV6_SOLICIT
,
1234
));
query
->
setRemoteAddr
(
IOAddress
(
"fe80::abcd"
));
OptionPtr
clientid
=
generateClientId
();
query
->
addOption
(
clientid
);
query
->
setIface
(
"eth1"
);
query
->
addOption
(
generateIA
(
D6O_IA_NA
,
123
,
1500
,
3000
));
// Do not add an ORO.
OptionPtr
oro
=
query
->
getOption
(
D6O_ORO
);
EXPECT_FALSE
(
oro
);
// Create and add a host-name option to the query
OptionStringPtr
hostname
(
new
OptionString
(
Option
::
V6
,
1234
,
"foo"
));
ASSERT_TRUE
(
hostname
);
query
->
addOption
(
hostname
);
// Process the query
Pkt6Ptr
response
=
srv
.
processSolicit
(
query
);
// Processing should add an ip-forwarding option
OptionPtr
opt
=
response
->
getOption
(
2345
);
ASSERT_TRUE
(
opt
);
ASSERT_GT
(
opt
->
len
(),
opt
->
getHeaderLen
());
// Global sets the value to true/1, subnet to false/0
// Here subnet has the priority
EXPECT_EQ
(
0
,
opt
->
getUint8
());
}
// Checks if the client-class field is indeed used for subnet selection.
// Note that packet classification is already checked in ClassifyTest
// .*Classification above.
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
4650a922
...
...
@@ -1666,6 +1666,78 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) {
EXPECT_EQ
(
"normal_erouter_v6.cm"
,
config_file
->
getValue
());
}
// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
// vendor options is parsed correctly and the persistent options are actually assigned.
TEST_F
(
Dhcpv6SrvTest
,
vendorPersistentOptions
)
{
IfaceMgrTestConfig
test_config
(
true
);
string
config
=
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
]"
"},"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
option-def
\"
: [ {"
"
\"
name
\"
:
\"
config-file
\"
,"
"
\"
code
\"
: 33,"
"
\"
type
\"
:
\"
string
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
"
" } ],"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
config-file
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
data
\"
:
\"
normal_erouter_v6.cm
\"
,"
"
\"
persistent
\"
: true"
" }],"
"
\"
subnet6
\"
: [ { "
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8:1::/64
\"
} ],"
"
\"
subnet
\"
:
\"
2001:db8:1::/48
\"
, "
"
\"
renew-timer
\"
: 1000, "
"
\"
rebind-timer
\"
: 1000, "
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
valid-lifetime
\"
: 4000,"
"
\"
interface-id
\"
:
\"\"
,"
"
\"
interface
\"
:
\"
eth0
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
;
ASSERT_NO_THROW
(
configure
(
config
));
Pkt6Ptr
sol
=
Pkt6Ptr
(
new
Pkt6
(
DHCPV6_SOLICIT
,
1234
));
sol
->
setRemoteAddr
(
IOAddress
(
"fe80::abcd"
));
sol
->
setIface
(
"eth0"
);
sol
->
addOption
(
generateIA
(
D6O_IA_NA
,
234
,
1500
,
3000
));
OptionPtr
clientid
=
generateClientId
();
sol
->
addOption
(
clientid
);
// Let's add a vendor-option (vendor-id=4491).
OptionPtr
vendor
(
new
OptionVendor
(
Option
::
V6
,
4491
));
sol
->
addOption
(
vendor
);
// Pass it to the server and get an advertise
Pkt6Ptr
adv
=
srv_
.
processSolicit
(
sol
);
// check if we get response at all
ASSERT_TRUE
(
adv
);
// Check if there is vendor option response
OptionPtr
tmp
=
adv
->
getOption
(
D6O_VENDOR_OPTS
);
ASSERT_TRUE
(
tmp
);
// The response should be OptionVendor object
boost
::
shared_ptr
<
OptionVendor
>
vendor_resp
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
tmp
);
ASSERT_TRUE
(
vendor_resp
);
OptionPtr
docsis33
=
vendor_resp
->
getOption
(
33
);
ASSERT_TRUE
(
docsis33
);
OptionStringPtr
config_file
=
boost
::
dynamic_pointer_cast
<
OptionString
>
(
docsis33
);
ASSERT_TRUE
(
config_file
);
EXPECT_EQ
(
"normal_erouter_v6.cm"
,
config_file
->
getValue
());
}
// Test checks whether it is possible to use option definitions defined in
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F
(
Dhcpv6SrvTest
,
vendorOptionsDocsisDefinitions
)
{
...
...
src/lib/dhcpsrv/cfg_option.h
View file @
4650a922
...
...
@@ -184,6 +184,11 @@ typedef std::pair<OptionContainerTypeIndex::const_iterator,
OptionContainerTypeIndex
::
const_iterator
>
OptionContainerTypeRange
;
/// Type of the index #2 - option persistency flag.
typedef
OptionContainer
::
nth_index
<
2
>::
type
OptionContainerPersistIndex
;
/// Pair of iterators to represent the range of options having the
/// same persistency flag. The first element in this pair represents
/// the beginning of the range, the second element represents the end.
typedef
std
::
pair
<
OptionContainerPersistIndex
::
const_iterator
,
OptionContainerPersistIndex
::
const_iterator
>
OptionContainerPersistRange
;
/// @brief Represents option data configuration for the DHCP server.
///
...
...
src/lib/dhcpsrv/tests/cfg_option_unittest.cc
View file @
4650a922
...
...
@@ -449,9 +449,7 @@ TEST_F(CfgOptionTest, addNonUniqueOptions) {
// Look for the codes 100-109.
for
(
uint16_t
code
=
100
;
code
<
110
;
++
code
)
{
// For each code we should get two instances of options->
std
::
pair
<
OptionContainerTypeIndex
::
const_iterator
,
OptionContainerTypeIndex
::
const_iterator
>
range
=
idx
.
equal_range
(
code
);
OptionContainerTypeRange
range
=
idx
.
equal_range
(
code
);
// Distance between iterators indicates how many options
// have been returned for the particular code.
ASSERT_EQ
(
2
,
distance
(
range
.
first
,
range
.
second
));
...
...
@@ -465,9 +463,7 @@ TEST_F(CfgOptionTest, addNonUniqueOptions) {
// Let's try to find some non-exiting option.
const
uint16_t
non_existing_code
=
150
;
std
::
pair
<
OptionContainerTypeIndex
::
const_iterator
,
OptionContainerTypeIndex
::
const_iterator
>
range
=
idx
.
equal_range
(
non_existing_code
);
OptionContainerTypeRange
range
=
idx
.
equal_range
(
non_existing_code
);
// Empty set is expected.
EXPECT_EQ
(
0
,
distance
(
range
.
first
,
range
.
second
));
}
...
...
@@ -501,17 +497,13 @@ TEST(Subnet6Test, addPersistentOption) {