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
Adam Osuchowski
Kea
Commits
0764a74e
Commit
0764a74e
authored
Oct 22, 2013
by
Marcin Siodelski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[3194] Implemented basic vendor options support.
parent
78cb0f4f
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
1370 additions
and
40 deletions
+1370
-40
src/bin/dhcp4/config_parser.cc
src/bin/dhcp4/config_parser.cc
+7
-0
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.cc
+80
-0
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/dhcp4_srv.h
+12
-0
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+84
-5
src/bin/dhcp4/tests/wireshark.cc
src/bin/dhcp4/tests/wireshark.cc
+2
-0
src/bin/dhcp6/config_parser.cc
src/bin/dhcp6/config_parser.cc
+7
-0
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
+71
-0
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/dhcp6_srv.h
+9
-0
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
+112
-0
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+206
-2
src/lib/dhcp/Makefile.am
src/lib/dhcp/Makefile.am
+1
-0
src/lib/dhcp/docsis3_option_defs.h
src/lib/dhcp/docsis3_option_defs.h
+65
-0
src/lib/dhcp/libdhcp++.cc
src/lib/dhcp/libdhcp++.cc
+309
-18
src/lib/dhcp/libdhcp++.h
src/lib/dhcp/libdhcp++.h
+26
-0
src/lib/dhcp/option_definition.h
src/lib/dhcp/option_definition.h
+4
-0
src/lib/dhcp/option_vendor.cc
src/lib/dhcp/option_vendor.cc
+68
-0
src/lib/dhcp/option_vendor.h
src/lib/dhcp/option_vendor.h
+104
-0
src/lib/dhcp/std_option_defs.h
src/lib/dhcp/std_option_defs.h
+2
-0
src/lib/dhcpsrv/cfgmgr.h
src/lib/dhcpsrv/cfgmgr.h
+1
-1
src/lib/dhcpsrv/dhcp_parsers.cc
src/lib/dhcpsrv/dhcp_parsers.cc
+64
-5
src/lib/dhcpsrv/dhcp_parsers.h
src/lib/dhcpsrv/dhcp_parsers.h
+10
-2
src/lib/dhcpsrv/option_space_container.h
src/lib/dhcpsrv/option_space_container.h
+7
-6
src/lib/dhcpsrv/subnet.cc
src/lib/dhcpsrv/subnet.cc
+32
-0
src/lib/dhcpsrv/subnet.h
src/lib/dhcpsrv/subnet.h
+17
-1
src/lib/dhcpsrv/tests/subnet_unittest.cc
src/lib/dhcpsrv/tests/subnet_unittest.cc
+70
-0
No files found.
src/bin/dhcp4/config_parser.cc
View file @
0764a74e
...
...
@@ -96,6 +96,13 @@ protected:
<<
" for DHCPv6 server"
);
}
// Check if this is a vendor-option. If it is, get vendor-specific
// definition.
uint32_t
vendor_id
=
SubnetConfigParser
::
optionSpaceToVendorId
(
option_space
);
if
(
vendor_id
)
{
def
=
LibDHCP
::
getVendorOptionDef
(
Option
::
V4
,
vendor_id
,
option_code
);
}
return
(
def
);
}
};
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
0764a74e
...
...
@@ -20,7 +20,9 @@
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_int.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_vendor.h>
#include <dhcp/pkt4.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcpsrv/addr_utilities.h>
...
...
@@ -36,6 +38,7 @@
#include <boost/algorithm/string/erase.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <iomanip>
#include <fstream>
...
...
@@ -643,6 +646,62 @@ Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
}
}
void
Dhcpv4Srv
::
appendRequestedVendorOptions
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
answer
)
{
// Get the configured subnet suitable for the incoming packet.
Subnet4Ptr
subnet
=
selectSubnet
(
question
);
// Leave if there is no subnet matching the incoming packet.
// There is no need to log the error message here because
// it will be logged in the assignLease() when it fails to
// pick the suitable subnet. We don't want to duplicate
// error messages in such case.
if
(
!
subnet
)
{
return
;
}
// Try to get the vendor option
boost
::
shared_ptr
<
OptionVendor
>
vendor_req
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
question
->
getOption
(
DHO_VIVSO_SUBOPTIONS
));
if
(
!
vendor_req
)
{
return
;
}
uint32_t
vendor_id
=
vendor_req
->
getVendorId
();
// 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.
OptionPtr
oro
=
vendor_req
->
getOption
(
DOCSIS3_V4_ORO
);
/// @todo: see OPT_UINT8_TYPE definition in OptionDefinition::optionFactory().
/// I think it should be OptionUint8Array, not OptionGeneric
// Option ORO not found. Don't do anything then.
if
(
!
oro
)
{
return
;
}
boost
::
shared_ptr
<
OptionVendor
>
vendor_rsp
(
new
OptionVendor
(
Option
::
V4
,
vendor_id
));
// Get the list of options that client requested.
bool
added
=
false
;
const
OptionBuffer
&
requested_opts
=
oro
->
getData
();
for
(
OptionBuffer
::
const_iterator
code
=
requested_opts
.
begin
();
code
!=
requested_opts
.
end
();
++
code
)
{
Subnet
::
OptionDescriptor
desc
=
subnet
->
getVendorOptionDescriptor
(
vendor_id
,
*
code
);
if
(
desc
.
option
)
{
vendor_rsp
->
addOption
(
desc
.
option
);
added
=
true
;
}
}
if
(
added
)
{
answer
->
addOption
(
vendor_rsp
);
}
}
void
Dhcpv4Srv
::
appendBasicOptions
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
msg
)
{
// Identify options that we always want to send to the
...
...
@@ -858,6 +917,7 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
copyDefaultFields
(
discover
,
offer
);
appendDefaultOptions
(
offer
,
DHCPOFFER
);
appendRequestedOptions
(
discover
,
offer
);
appendRequestedVendorOptions
(
discover
,
offer
);
assignLease
(
discover
,
offer
);
...
...
@@ -881,6 +941,7 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
copyDefaultFields
(
request
,
ack
);
appendDefaultOptions
(
ack
,
DHCPACK
);
appendRequestedOptions
(
request
,
ack
);
appendRequestedVendorOptions
(
request
,
ack
);
// Note that we treat REQUEST message uniformly, regardless if this is a
// first request (requesting for new address), renewing existing address
...
...
@@ -1226,6 +1287,25 @@ Dhcpv4Srv::unpackOptions(const OptionBuffer& buf,
<<
"-byte long buffer."
);
}
/// @todo: Not sure if this is needed. Perhaps it would be better to extend
/// DHO_VIVSO_SUBOPTIONS definitions in std_option_defs.h to cover
/// OptionVendor class?
if
(
opt_type
==
DHO_VIVSO_SUBOPTIONS
)
{
if
(
offset
+
4
>
buf
.
size
())
{
// Truncated vendor-option. There is expected at least 4 bytes
// long enterprise-id field
return
(
offset
);
}
// Parse this as vendor option
OptionPtr
vendor_opt
(
new
OptionVendor
(
Option
::
V4
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
options
.
insert
(
std
::
make_pair
(
opt_type
,
vendor_opt
));
offset
+=
opt_len
;
continue
;
}
// Get all definitions with the particular option code. Note that option code
// is non-unique within this container however at this point we expect
// to get one option definition with the particular code. If more are
...
...
src/bin/dhcp4/dhcp4_srv.h
View file @
0764a74e
...
...
@@ -227,6 +227,18 @@ protected:
/// @param msg outgoing message (options will be added here)
void
appendRequestedOptions
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
msg
);
/// @brief Appends requested vendor options as requested by client.
///
/// This method is similar to \ref appendRequestedOptions(), but uses
/// vendor options. The major difference is that vendor-options use
/// its own option spaces (there may be more than one distinct set of vendor
/// options, each with unique vendor-id). Vendor options are requested
/// using separate options within their respective vendor-option spaces.
///
/// @param question DISCOVER or REQUEST message from a client.
/// @param msg outgoing message (options will be added here)
void
appendRequestedVendorOptions
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
answer
);
/// @brief Assigns a lease and appends corresponding options
///
/// This method chooses the most appropriate lease for reqesting
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
0764a74e
...
...
@@ -25,8 +25,10 @@
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_vendor.h>
#include <dhcp/pkt_filter.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/config_parser.h>
...
...
@@ -1138,11 +1140,7 @@ TEST_F(Dhcpv4SrvTest, ServerID) {
EXPECT_EQ
(
srvid_text
,
text
);
}
// Checks if callouts installed on pkt4_receive are indeed called and the
// all necessary parameters are passed.
//
// Note that the test name does not follow test naming convention,
// but the proper hook name is "buffer4_receive".
// Checks if received relay agent info option is echoed back to the client
TEST_F
(
Dhcpv4SrvTest
,
relayAgentInfoEcho
)
{
NakedDhcpv4Srv
srv
(
0
);
...
...
@@ -1180,6 +1178,87 @@ TEST_F(Dhcpv4SrvTest, relayAgentInfoEcho) {
EXPECT_TRUE
(
rai_response
->
equal
(
rai_query
));
}
// Checks if vendor options are parsed correctly and requested vendor options
// are echoed back.
TEST_F
(
Dhcpv4SrvTest
,
vendorOptionsDocsis
)
{
NakedDhcpv4Srv
srv
(
0
);
string
config
=
"{
\"
interfaces
\"
: [
\"
*
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
tftp-servers
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
code
\"
: 2,"
"
\"
data
\"
:
\"
10.253.175.16
\"
,"
"
\"
csv-format
\"
: True"
" }],"
"
\"
subnet4
\"
: [ { "
"
\"
pool
\"
: [
\"
10.254.226.0/25
\"
],"
"
\"
subnet
\"
:
\"
10.254.226.0/24
\"
, "
"
\"
interface
\"
:
\"
"
+
valid_iface_
+
"
\"
"
" }, {"
"
\"
pool
\"
: [
\"
192.0.3.0/25
\"
],"
"
\"
subnet
\"
:
\"
192.0.3.0/24
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
;
ElementPtr
json
=
Element
::
fromJSON
(
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_
);
// Let's create a relayed DISCOVER. This particular relayed DISCOVER has
// added option 82 (relay agent info) with 3 suboptions. The server
// is supposed to echo it back in its response.
Pkt4Ptr
dis
;
ASSERT_NO_THROW
(
dis
=
captureRelayedDiscover
());
// Simulate that we have received that traffic
srv
.
fakeReceive
(
dis
);
// Server will now process to run its normal loop, but instead of calling
// IfaceMgr::receive4(), it will read all packets from the list set by
// fakeReceive()
// In particular, it should call registered buffer4_receive callback.
srv
.
run
();
// Check that the server did send a reposonse
ASSERT_EQ
(
1
,
srv
.
fake_sent_
.
size
());
// Make sure that we received a response
Pkt4Ptr
offer
=
srv
.
fake_sent_
.
front
();
ASSERT_TRUE
(
offer
);
// Get Relay Agent Info from query...
OptionPtr
vendor_opt_response
=
offer
->
getOption
(
DHO_VIVSO_SUBOPTIONS
);
ASSERT_TRUE
(
vendor_opt_response
);
// Check if it's of a correct type
boost
::
shared_ptr
<
OptionVendor
>
vendor_opt
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
vendor_opt_response
);
ASSERT_TRUE
(
vendor_opt
);
// Get Relay Agent Info from response...
OptionPtr
tftp_servers_generic
=
vendor_opt
->
getOption
(
DOCSIS3_V4_TFTP_SERVERS
);
ASSERT_TRUE
(
tftp_servers_generic
);
Option4AddrLstPtr
tftp_servers
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
tftp_servers_generic
);
ASSERT_TRUE
(
tftp_servers
);
Option4AddrLst
::
AddressContainer
addrs
=
tftp_servers
->
getAddresses
();
ASSERT_EQ
(
1
,
addrs
.
size
());
EXPECT_EQ
(
"10.253.175.16"
,
addrs
[
0
].
toText
());
}
/// @todo Implement tests for subnetSelect See tests in dhcp6_srv_unittest.cc:
/// selectSubnetAddr, selectSubnetIface, selectSubnetRelayLinkaddr,
/// selectSubnetRelayInterfaceId. Note that the concept of interface-id is not
...
...
src/bin/dhcp4/tests/wireshark.cc
View file @
0764a74e
...
...
@@ -100,6 +100,8 @@ Bootstrap Protocol
Option: (55) Parameter Request List
Option: (60) Vendor class identifier
Option: (125) V-I Vendor-specific Information
- suboption 1 (Option Request): requesting option 2
- suboption 5 (Modem Caps): 117 bytes
Option: (43) Vendor-Specific Information (CableLabs)
Option: (61) Client identifier
Option: (57) Maximum DHCP Message Size
...
...
src/bin/dhcp6/config_parser.cc
View file @
0764a74e
...
...
@@ -111,6 +111,13 @@ protected:
<<
" for DHCPv4 server"
);
}
// Check if this is a vendor-option. If it is, get vendor-specific
// definition.
uint32_t
vendor_id
=
SubnetConfigParser
::
optionSpaceToVendorId
(
option_space
);
if
(
vendor_id
)
{
def
=
LibDHCP
::
getVendorOptionDef
(
Option
::
V6
,
vendor_id
,
option_code
);
}
return
def
;
}
};
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
0764a74e
...
...
@@ -17,6 +17,7 @@
#include <asiolink/io_address.h>
#include <dhcp_ddns/ncr_msg.h>
#include <dhcp/dhcp6.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp/duid.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
...
...
@@ -26,6 +27,7 @@
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_iaprefix.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_vendor.h>
#include <dhcp/option_int_array.h>
#include <dhcp/pkt6.h>
#include <dhcp6/dhcp6_log.h>
...
...
@@ -683,6 +685,57 @@ Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
}
void
Dhcpv6Srv
::
appendRequestedVendorOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
)
{
// Get the configured subnet suitable for the incoming packet.
Subnet6Ptr
subnet
=
selectSubnet
(
question
);
// Leave if there is no subnet matching the incoming packet.
// There is no need to log the error message here because
// it will be logged in the assignLease() when it fails to
// pick the suitable subnet. We don't want to duplicate
// error messages in such case.
if
(
!
subnet
)
{
return
;
}
// Try to get the vendor option
boost
::
shared_ptr
<
OptionVendor
>
vendor_req
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
question
->
getOption
(
D6O_VENDOR_OPTS
));
if
(
!
vendor_req
)
{
return
;
}
uint32_t
vendor_id
=
vendor_req
->
getVendorId
();
// 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
));
// Option ORO not found. Don't do anything then.
if
(
!
oro
)
{
return
;
}
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
)
{
Subnet
::
OptionDescriptor
desc
=
subnet
->
getVendorOptionDescriptor
(
vendor_id
,
opt
);
if
(
desc
.
option
)
{
vendor_rsp
->
addOption
(
desc
.
option
);
added
=
true
;
}
}
if
(
added
)
{
answer
->
addOption
(
vendor_rsp
);
}
}
OptionPtr
Dhcpv6Srv
::
createStatusCode
(
uint16_t
code
,
const
std
::
string
&
text
)
{
// @todo This function uses OptionCustom class to manage contents
...
...
@@ -2114,6 +2167,7 @@ Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
copyDefaultOptions
(
solicit
,
advertise
);
appendDefaultOptions
(
solicit
,
advertise
);
appendRequestedOptions
(
solicit
,
advertise
);
appendRequestedVendorOptions
(
solicit
,
advertise
);
Option6ClientFqdnPtr
fqdn
=
processClientFqdn
(
solicit
);
assignLeases
(
solicit
,
advertise
,
fqdn
);
...
...
@@ -2135,6 +2189,7 @@ Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
copyDefaultOptions
(
request
,
reply
);
appendDefaultOptions
(
request
,
reply
);
appendRequestedOptions
(
request
,
reply
);
appendRequestedVendorOptions
(
request
,
reply
);
Option6ClientFqdnPtr
fqdn
=
processClientFqdn
(
request
);
assignLeases
(
request
,
reply
,
fqdn
);
...
...
@@ -2301,6 +2356,22 @@ Dhcpv6Srv::unpackOptions(const OptionBuffer& buf,
continue
;
}
if
(
opt_type
==
D6O_VENDOR_OPTS
)
{
if
(
offset
+
4
>
length
)
{
// Truncated vendor-option. There is expected at least 4 bytes
// long enterprise-id field
return
(
offset
);
}
// Parse this as vendor option
OptionPtr
vendor_opt
(
new
OptionVendor
(
Option
::
V6
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
options
.
insert
(
std
::
make_pair
(
opt_type
,
vendor_opt
));
offset
+=
opt_len
;
continue
;
}
// Get all definitions with the particular option code. Note that option
// code is non-unique within this container however at this point we
// expect to get one option definition with the particular code. If more
...
...
src/bin/dhcp6/dhcp6_srv.h
View file @
0764a74e
...
...
@@ -336,6 +336,15 @@ protected:
/// @param answer server's message (options will be added here)
void
appendRequestedOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
);
/// @brief Appends requested vendor options to server's answer.
///
/// This is mostly useful for Cable Labs options for now, but the method
/// is easily extensible to other vendors.
///
/// @param question client's message
/// @param answer server's message (vendor options will be added here)
void
appendRequestedVendorOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
);
/// @brief Assigns leases.
///
/// It supports addresses (IA_NA) only. It does NOT support temporary
...
...
src/bin/dhcp6/tests/config_parser_unittest.cc
View file @
0764a74e
...
...
@@ -2049,6 +2049,118 @@ TEST_F(Dhcp6ParserTest, stdOptionData) {
EXPECT_EQ
(
1516
,
optionIA
->
getT2
());
}
// This test checks if vendor options can be specified in the config file
// (in hex format), and later retrieved from configured subnet
TEST_F
(
Dhcp6ParserTest
,
vendorOptionsHex
)
{
// This configuration string is to configure two options
// sharing the code 1 and belonging to the different vendor spaces.
// (different vendor-id values).
string
config
=
"{
\"
interfaces
\"
: [
\"
*
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
option-one
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
code
\"
: 100,"
"
\"
data
\"
:
\"
AB CDEF0105
\"
,"
"
\"
csv-format
\"
: False"
" },"
" {"
"
\"
name
\"
:
\"
option-two
\"
,"
"
\"
space
\"
:
\"
vendor-1234
\"
,"
"
\"
code
\"
: 100,"
"
\"
data
\"
:
\"
1234
\"
,"
"
\"
csv-format
\"
: False"
" } ],"
"
\"
subnet6
\"
: [ { "
"
\"
pool
\"
: [
\"
2001:db8:1::/80
\"
],"
"
\"
subnet
\"
:
\"
2001:db8:1::/64
\"
"
" } ]"
"}"
;
ConstElementPtr
status
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
EXPECT_NO_THROW
(
status
=
configureDhcp6Server
(
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// Options should be now available for the subnet.
Subnet6Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet6
(
IOAddress
(
"2001:db8:1::5"
));
ASSERT_TRUE
(
subnet
);
// Try to get the option from the vendor space 4491
Subnet
::
OptionDescriptor
desc1
=
subnet
->
getVendorOptionDescriptor
(
4491
,
100
);
ASSERT_TRUE
(
desc1
.
option
);
EXPECT_EQ
(
100
,
desc1
.
option
->
getType
());
// Try to get the option from the vendor space 1234
Subnet
::
OptionDescriptor
desc2
=
subnet
->
getVendorOptionDescriptor
(
1234
,
100
);
ASSERT_TRUE
(
desc2
.
option
);
EXPECT_EQ
(
100
,
desc1
.
option
->
getType
());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
Subnet
::
OptionDescriptor
desc3
=
subnet
->
getVendorOptionDescriptor
(
5678
,
38
);
ASSERT_FALSE
(
desc3
.
option
);
}
// This test checks if vendor options can be specified in the config file,
// (in csv format), and later retrieved from configured subnet
TEST_F
(
Dhcp6ParserTest
,
vendorOptionsCsv
)
{
// This configuration string is to configure two options
// sharing the code 1 and belonging to the different vendor spaces.
// (different vendor-id values).
string
config
=
"{
\"
interfaces
\"
: [
\"
*
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
code
\"
: 100,"
"
\"
data
\"
:
\"
this is a string vendor-opt
\"
,"
"
\"
csv-format
\"
: True"
" } ],"
"
\"
option-def
\"
: [ {"
"
\"
name
\"
:
\"
foo
\"
,"
"
\"
code
\"
: 100,"
"
\"
type
\"
:
\"
string
\"
,"
"
\"
array
\"
: False,"
"
\"
record-types
\"
:
\"\"
,"
"
\"
space
\"
:
\"
vendor-4491
\"
,"
"
\"
encapsulate
\"
:
\"\"
"
" } ],"
"
\"
subnet6
\"
: [ { "
"
\"
pool
\"
: [
\"
2001:db8:1::/80
\"
],"
"
\"
subnet
\"
:
\"
2001:db8:1::/64
\"
"
" } ]"
"}"
;
ConstElementPtr
status
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
EXPECT_NO_THROW
(
status
=
configureDhcp6Server
(
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// Options should be now available for the subnet.
Subnet6Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet6
(
IOAddress
(
"2001:db8:1::5"
));
ASSERT_TRUE
(
subnet
);
// Try to get the option from the vendor space 4491
Subnet
::
OptionDescriptor
desc1
=
subnet
->
getVendorOptionDescriptor
(
4491
,
100
);
ASSERT_TRUE
(
desc1
.
option
);
EXPECT_EQ
(
100
,
desc1
.
option
->
getType
());
// Try to get the non-existing option from the non-existing
// option space and expect that option is not returned.
Subnet
::
OptionDescriptor
desc2
=
subnet
->
getVendorOptionDescriptor
(
5678
,
38
);
ASSERT_FALSE
(
desc2
.
option
);
}
// The goal of this test is to verify that the standard option can
// be configured to encapsulate multiple other options.
TEST_F
(
Dhcp6ParserTest
,
stdOptionDataEncapsulate
)
{
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
0764a74e
...
...
@@ -25,10 +25,13 @@
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option_int.h>
#include <dhcp/option_vendor.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_string.h>
#include <dhcp/iface_mgr.h>
#include <dhcp6/config_parser.h>
#include <dhcp/dhcp6.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
...
...
@@ -2014,9 +2017,210 @@ TEST_F(Dhcpv6SrvTest, docsisTraffic) {
ASSERT_FALSE
(
srv
.
fake_sent_
.
empty
());
Pkt6Ptr
adv
=
srv
.
fake_sent_
.
front
();
ASSERT_TRUE
(
adv
);
}
// Checks if server is able to handle a relayed traffic from DOCSIS3.0 modems
TEST_F
(
Dhcpv6SrvTest
,
docsisVendorOptionsParse
)
{
NakedDhcpv6Srv
srv
(
0
);
// Let's get a traffic capture from DOCSIS3.0 modem
Pkt6Ptr
sol
=
captureDocsisRelayedSolicit
();
EXPECT_NO_THROW
(
sol
->
unpack
());
// Check if the packet contain
OptionPtr
opt
=
sol
->
getOption
(
D6O_VENDOR_OPTS
);
ASSERT_TRUE
(
opt
);
boost
::
shared_ptr
<
OptionVendor
>
vendor
=
boost
::
dynamic_pointer_cast
<
OptionVendor
>
(
opt
);
ASSERT_TRUE
(
vendor
);
EXPECT_TRUE
(
vendor
->
getOption
(
1
));
EXPECT_TRUE
(
vendor
->
getOption
(
36
));
EXPECT_TRUE
(
vendor
->
getOption
(
35
));
EXPECT_TRUE
(
vendor
->
getOption
(
2
));
EXPECT_TRUE
(
vendor
->
getOption
(
3
));
EXPECT_TRUE
(
vendor
->
getOption
(
4
));
EXPECT_TRUE
(
vendor
->
getOption
(
5
));
EXPECT_TRUE
(
vendor
->
getOption
(
6
));
EXPECT_TRUE
(
vendor
->
getOption
(
7
));
EXPECT_TRUE
(
vendor
->
getOption
(
8
));
EXPECT_TRUE
(
vendor
->
getOption
(
9
));
EXPECT_TRUE
(
vendor
->
getOption
(
10
));
EXPECT_TRUE
(
vendor
->
getOption
(
15
));
EXPECT_FALSE
(
vendor
->
getOption
(
20
));
EXPECT_FALSE
(
vendor
->
getOption
(
11
));
EXPECT_FALSE
(
vendor
->
getOption
(
17
));
}
// Checks if server is able to parse incoming docsis option and extract suboption 1 (docsis ORO)
TEST_F
(
Dhcpv6SrvTest
,
docsisVendorORO
)
{
NakedDhcpv6Srv
srv
(
0
);
// Let's get a traffic capture from DOCSIS3.0 modem
Pkt6Ptr
sol
=
captureDocsisRelayedSolicit
();
EXPECT_NO_THROW
(
sol
->
unpack
());
// Check if the packet contain
OptionPtr
opt
=
sol
->
getOption
(
D6O_VENDOR_OPTS
);
ASSERT_TRUE
(
opt
);
boost
::
shared_ptr
<