Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Kea
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Sebastian Schrader
Kea
Commits
4650a922
Commit
4650a922
authored
Jul 07, 2017
by
Francis Dupont
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[5241] Added the function in DHCPv4 and 6 servers
parent
ac7850b4
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
425 additions
and
57 deletions
+425
-57
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.cc
+50
-12
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/config_parser_unittest.cc
+4
-4
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+162
-0
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
+51
-12
src/bin/dhcp6/tests/classify_unittests.cc
src/bin/dhcp6/tests/classify_unittests.cc
+69
-1
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+72
-0
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/cfg_option.h
+5
-0
src/lib/dhcpsrv/tests/cfg_option_unittest.cc
src/lib/dhcpsrv/tests/cfg_option_unittest.cc
+6
-14
src/lib/dhcpsrv/tests/subnet_unittest.cc
src/lib/dhcpsrv/tests/subnet_unittest.cc
+6
-14
No files found.
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) {
OptionContainerPersistIndex
&
idx
=
options
->
get
<
2
>
();
// Get all persistent options->
std
::
pair
<
OptionContainerPersistIndex
::
const_iterator
,
OptionContainerPersistIndex
::
const_iterator
>
range_persistent
=
idx
.
equal_range
(
true
);
// 3 out of 10 options have been flagged persistent.
OptionContainerPersistRange
range_persistent
=
idx
.
equal_range
(
true
);
// 7 out of 10 options have been flagged persistent.
ASSERT_EQ
(
7
,
distance
(
range_persistent
.
first
,
range_persistent
.
second
));
// Get all non-persistent options->
std
::
pair
<
OptionContainerPersistIndex
::
const_iterator
,
OptionContainerPersistIndex
::
const_iterator
>
range_non_persistent
=
idx
.
equal_range
(
false
);
// 7 out of 10 options have been flagged persistent.
OptionContainerPersistRange
range_non_persistent
=
idx
.
equal_range
(
false
);
// 3 out of 10 options have been flagged not persistent.
ASSERT_EQ
(
3
,
distance
(
range_non_persistent
.
first
,
range_non_persistent
.
second
));
}
...
...
src/lib/dhcpsrv/tests/subnet_unittest.cc
View file @
4650a922
...
...
@@ -944,9 +944,7 @@ TEST(Subnet6Test, addNonUniqueOptions) {
// Look for the codes 100-109.
for
(
uint16_t
code
=
100
;
code