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
a5abebaa
Commit
a5abebaa
authored
Sep 13, 2017
by
Tomek Mrugalski
🛰
Browse files
[5357] Parser for shared-networks in DHCPv6 implemented.
parent
b9c54a65
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/json_config_parser.cc
View file @
a5abebaa
...
...
@@ -89,7 +89,6 @@ public:
cfg
->
setDhcp4o6Port
(
dhcp4o6_port
);
}
/// @brief Copies subnets from shared networks to regular subnets container
///
/// @param from pointer to shared networks container (copy from here)
...
...
@@ -156,6 +155,13 @@ public:
sharedNetworksSanityChecks
(
const
SharedNetwork4Collection
&
networks
,
ConstElementPtr
json
)
{
/// @todo: in case of errors, use json to extract line numbers.
if
(
!
json
)
{
// No json? That means that the shared-networks was never specified
// in the config.
return
;
}
// Used for names uniqueness checks.
std
::
set
<
string
>
names
;
...
...
@@ -315,6 +321,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
parser
.
parse
(
cfg_option_def
,
option_defs
);
}
// This parser is used in several places, so it should be available
// early.
Dhcp4ConfigParser
global_parser
;
// Make parsers grouping.
...
...
@@ -427,9 +435,10 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
/// as well.
SharedNetworks4ListParser
parser
;
CfgSharedNetworks4Ptr
cfg
=
srv_cfg
->
getCfgSharedNetworks4
();
parser
.
parse
(
cfg
,
config_pair
.
second
);
// We also need to put the subnets it contains into normal
// subnets list.
global_parser
.
copySubnets4
(
srv_cfg
->
getCfgSubnets4
(),
cfg
);
continue
;
}
...
...
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
a5abebaa
...
...
@@ -604,6 +604,13 @@ public:
return
(
ReturnType
());
}
/// @brief Checks if specified subnet is part of the collection
///
/// @param col collection of subnets to be inspected
/// @param subnet text notation (e.g. 192.0.2.0/24)
/// @param t1 expected renew-timer value
/// @param t2 expected rebind-timer value
/// @param valid expected valid-lifetime value
void
checkSubnet
(
const
Subnet4Collection
&
col
,
std
::
string
subnet
,
uint32_t
t1
,
uint32_t
t2
,
uint32_t
valid
)
{
...
...
@@ -5066,17 +5073,15 @@ TEST_F(Dhcp4ParserTest, sharedNetworksName) {
// Now verify that the shared network was indeed configured.
CfgSharedNetworks4Ptr
cfg_net
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSharedNetworks4
();
ASSERT_TRUE
(
cfg_net
);
const
SharedNetwork4Collection
*
nets
=
cfg_net
->
getAll
();
ASSERT_TRUE
(
nets
);
ASSERT_EQ
(
1
,
nets
->
size
());
SharedNetwork4Ptr
net
=
*
(
nets
->
begin
());
ASSERT_TRUE
(
net
);
EXPECT_EQ
(
"foo"
,
net
->
getName
());
// Verify that there are no subnets in this shared-network
const
Subnet4Collection
*
subs
=
net
->
getAllSubnets
();
ASSERT_TRUE
(
subs
);
EXPECT_EQ
(
0
,
subs
->
size
());
...
...
src/bin/dhcp6/json_config_parser.cc
View file @
a5abebaa
...
...
@@ -31,6 +31,7 @@
#include <dhcpsrv/parsers/ifaces_config_parser.h>
#include <dhcpsrv/parsers/option_data_parser.h>
#include <dhcpsrv/parsers/simple_parser6.h>
#include <dhcpsrv/parsers/shared_networks_list_parser.h>
#include <hooks/hooks_parser.h>
#include <log/logger_support.h>
#include <util/encode/hex.h>
...
...
@@ -129,7 +130,12 @@ public:
}
};
/// @brief Parser that takes care of global DHCPv6 parameters.
/// @brief Parser that takes care of global DHCPv6 parameters and utility
/// functions that work on global level.
///
/// This class is a collection of utility method that either handle
/// global parameters (see @ref parse), or conducts operations on
/// global level (see @ref sanityChecks and @ref copySubnets6).
///
/// See @ref parse method for a list of supported parameters.
class
Dhcp6ConfigParser
:
public
isc
::
data
::
SimpleParser
{
...
...
@@ -158,6 +164,134 @@ public:
uint16_t
dhcp4o6_port
=
getUint16
(
global
,
"dhcp4o6-port"
);
srv_config
->
setDhcp4o6Port
(
dhcp4o6_port
);
}
/// @brief Copies subnets from shared networks to regular subnets container
///
/// @param from pointer to shared networks container (copy from here)
/// @param dest pointer to cfg subnets6 (copy to here)
/// @throw BadValue if any pointer is missing
/// @throw DhcpConfigError if there are duplicates (or other subnet defects)
void
copySubnets6
(
const
CfgSubnets6Ptr
dest
,
const
CfgSharedNetworks6Ptr
from
)
{
if
(
!
dest
||
!
from
)
{
isc_throw
(
BadValue
,
"Unable to copy subnets: at least one pointer is null"
);
}
const
SharedNetwork6Collection
*
networks
=
from
->
getAll
();
if
(
!
networks
)
{
// Nothing to copy. Technically, it should return a pointer to empty
// container, but let's handle null pointer as well.
return
;
}
// Let's go through all the networks one by one
for
(
auto
net
=
networks
->
begin
();
net
!=
networks
->
end
();
++
net
)
{
// For each network go through all the subnets in it.
const
Subnet6Collection
*
subnets
=
(
*
net
)
->
getAllSubnets
();
if
(
!
subnets
)
{
// Shared network without subnets it weird, but we decided to
// accept such configurations.
continue
;
}
// For each subnet, add it to a list of regular subnets.
for
(
auto
subnet
=
subnets
->
begin
();
subnet
!=
subnets
->
end
();
++
subnet
)
{
dest
->
add
(
*
subnet
);
}
}
}
/// @brief Conducts global sanity checks
///
/// This method is very simply now, but more sanity checks are expected
/// in the future.
///
/// @param cfg - the parsed structure
/// @param global global Dhcp4 scope
/// @throw DhcpConfigError in case of issues found
void
sanityChecks
(
SrvConfigPtr
cfg
,
ConstElementPtr
global
)
{
/// Shared network sanity checks
const
SharedNetwork6Collection
*
networks
=
cfg
->
getCfgSharedNetworks6
()
->
getAll
();
if
(
networks
)
{
sharedNetworksSanityChecks
(
*
networks
,
global
->
get
(
"shared-networks"
));
}
}
/// @brief Sanity checks for shared networks
///
/// This method verifies if there are no issues with shared networks.
/// @param networks pointer to shared networks being checked
/// @param json shared-networks element
/// @throw DhcpConfigError if issues are encountered
void
sharedNetworksSanityChecks
(
const
SharedNetwork6Collection
&
networks
,
ConstElementPtr
json
)
{
/// @todo: in case of errors, use json to extract line numbers.
if
(
!
json
)
{
// No json? That means that the shared-networks was never specified
// in the config.
return
;
}
// Used for names uniqueness checks.
std
::
set
<
string
>
names
;
// Let's go through all the networks one by one
for
(
auto
net
=
networks
.
begin
();
net
!=
networks
.
end
();
++
net
)
{
string
txt
;
// Let's check if all subnets have either the same interface
// or don't have the interface specified at all.
string
iface
=
(
*
net
)
->
getIface
();
const
Subnet6Collection
*
subnets
=
(
*
net
)
->
getAllSubnets
();
if
(
subnets
)
{
// For each subnet, add it to a list of regular subnets.
for
(
auto
subnet
=
subnets
->
begin
();
subnet
!=
subnets
->
end
();
++
subnet
)
{
if
(
iface
.
empty
())
{
iface
=
(
*
subnet
)
->
getIface
();
continue
;
}
if
((
*
subnet
)
->
getIface
().
empty
())
{
continue
;
}
if
(
iface
!=
(
*
subnet
)
->
getIface
())
{
isc_throw
(
DhcpConfigError
,
"Subnet "
<<
(
*
subnet
)
->
toText
()
<<
" has specified interface "
<<
(
*
subnet
)
->
getIface
()
<<
", but earlier subnet in the same shared-network"
<<
" or the shared-network itself used "
<<
iface
);
}
// Let's collect the subnets in case we later find out the
// subnet doesn't have a mandatory name.
txt
+=
(
*
subnet
)
->
toText
()
+
" "
;
}
}
// Next, let's check name of the shared network.
if
((
*
net
)
->
getName
().
empty
())
{
isc_throw
(
DhcpConfigError
,
"Shared-network with subnets "
<<
txt
<<
" is missing mandatory 'name' parameter"
);
}
// Is it unique?
if
(
names
.
find
((
*
net
)
->
getName
())
!=
names
.
end
())
{
isc_throw
(
DhcpConfigError
,
"A shared-network with "
"name "
<<
(
*
net
)
->
getName
()
<<
" defined twice."
);
}
names
.
insert
((
*
net
)
->
getName
());
}
}
};
}
// anonymous namespace
...
...
@@ -270,6 +404,10 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
parser
.
parse
(
cfg_option_def
,
option_defs
);
}
// This parser is used in several places, so it should be available
// early.
Dhcp6ConfigParser
global_parser
;
BOOST_FOREACH
(
config_pair
,
values_map
)
{
// In principle we could have the following code structured as a series
// of long if else if clauses. That would give a marginal performance
...
...
@@ -375,19 +513,26 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
}
if
(
config_pair
.
first
==
"subnet6"
)
{
SrvConfigPtr
srv_cfg
=
CfgMgr
::
instance
().
getStagingCfg
();
Subnets6ListConfigParser
subnets_parser
;
// parse() returns number of subnets parsed. We may log it one day.
subnets_parser
.
parse
(
srv_c
f
g
,
config_pair
.
second
);
subnets_parser
.
parse
(
srv_c
onfi
g
,
config_pair
.
second
);
continue
;
}
if
(
config_pair
.
first
==
"shared-networks"
)
{
///
@todo
We need to create instance of SharedNetworks4ListParser
/// We need to create instance of SharedNetworks4ListParser
/// and parse the list of the shared networks into the
/// CfgSharedNetworks4 object. One additional step is then to
/// add subnets from the CfgSharedNetworks6 into CfgSubnets6
/// as well.
SharedNetworks6ListParser
parser
;
CfgSharedNetworks6Ptr
cfg
=
srv_config
->
getCfgSharedNetworks6
();
parser
.
parse
(
cfg
,
config_pair
.
second
);
// We also need to put the subnets it contains into normal
// subnets list.
global_parser
.
copySubnets6
(
srv_config
->
getCfgSubnets6
(),
cfg
);
continue
;
}
...
...
@@ -417,9 +562,13 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
}
// Apply global options in the staging config.
Dhcp6ConfigParser
global_parser
;
global_parser
.
parse
(
srv_config
,
mutable_cfg
);
// This method conducts final sanity checks and tweaks. In particular,
// it checks that there is no conflict between plain subnets and those
// defined as part of shared networks.
global_parser
.
sanityChecks
(
srv_config
,
mutable_cfg
);
}
catch
(
const
isc
::
Exception
&
ex
)
{
LOG_ERROR
(
dhcp6_logger
,
DHCP6_PARSER_FAIL
)
.
arg
(
config_pair
.
first
).
arg
(
ex
.
what
());
...
...
src/bin/dhcp6/tests/config_parser_unittest.cc
View file @
a5abebaa
...
...
@@ -280,6 +280,62 @@ public:
}
}
/// @brief Convenience method for running configuration
///
/// This method does not throw, but signals errors using gtest macros.
///
/// @param config text to be parsed as JSON
/// @param expected_code expected code (see cc/command_interpreter.h)
/// @param exp_error expected text error (check skipped if empty)
void
configure
(
std
::
string
config
,
int
expected_code
,
std
::
string
exp_error
=
""
)
{
ConstElementPtr
json
;
ASSERT_NO_THROW
(
json
=
parseDHCP6
(
config
,
true
));
ConstElementPtr
status
;
EXPECT_NO_THROW
(
status
=
configureDhcp6Server
(
srv_
,
json
));
ASSERT_TRUE
(
status
);
int
rcode
;
ConstElementPtr
comment
=
parseAnswer
(
rcode
,
status
);
EXPECT_EQ
(
expected_code
,
rcode
);
string
text
;
ASSERT_NO_THROW
(
text
=
comment
->
stringValue
());
if
(
expected_code
!=
rcode
)
{
std
::
cout
<<
"Reported status: "
<<
text
<<
std
::
endl
;
}
if
((
rcode
!=
0
))
{
if
(
!
exp_error
.
empty
())
{
EXPECT_EQ
(
exp_error
,
text
);
}
}
}
/// @brief Checks if specified subnet is part of the collection
///
/// @param col collection of subnets to be inspected
/// @param subnet text notation (e.g. 192.0.2.0/24)
/// @param t1 expected renew-timer value
/// @param t2 expected rebind-timer value
/// @param preferred expected preferred-lifetime value
/// @param valid expected valid-lifetime value
void
checkSubnet
(
const
Subnet6Collection
&
col
,
std
::
string
subnet
,
uint32_t
t1
,
uint32_t
t2
,
uint32_t
pref
,
uint32_t
valid
)
{
const
auto
&
index
=
col
.
get
<
SubnetPrefixIndexTag
>
();
auto
subnet_it
=
index
.
find
(
subnet
);
ASSERT_NE
(
subnet_it
,
index
.
cend
());
Subnet6Ptr
s
=
*
subnet_it
;
EXPECT_EQ
(
t1
,
s
->
getT1
());
EXPECT_EQ
(
t2
,
s
->
getT2
());
EXPECT_EQ
(
pref
,
s
->
getPreferred
());
EXPECT_EQ
(
valid
,
s
->
getValid
());
}
/// @brief Returns an interface configuration used by the most of the
/// unit tests.
std
::
string
genIfaceConfig
()
const
{
...
...
@@ -5060,9 +5116,9 @@ TEST_F(Dhcp6ParserTest, invalidClientClassDictionary) {
"
\"
bogus
\"
:
\"
bad
\"
\n
"
" }
\n
"
"],
\n
"
"
\"
subnet
4
\"
: [ {
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
192.0.2.1 - 192.0.2.100
\"
} ],
\n
"
"
\"
subnet
\"
:
\"
192.0.2.0/2
4
\"
\n
"
"
\"
subnet
6
\"
: [ {
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8::1 - 2001:db8::ffff
\"
} ],
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/6
4
\"
\n
"
" } ]
\n
"
"}
\n
"
;
...
...
@@ -5303,4 +5359,256 @@ TEST_F(Dhcp6ParserTest, outsideSubnetPool) {
EXPECT_EQ
(
expected
,
text
);
}
// Test verifies that empty shared networks are accepted.
TEST_F
(
Dhcp6ParserTest
,
sharedNetworksEmpty
)
{
string
config
=
"{
\n
"
"
\"
valid-lifetime
\"
: 4000,
\n
"
"
\"
rebind-timer
\"
: 2000,
\n
"
"
\"
renew-timer
\"
: 1000,
\n
"
"
\"
subnet6
\"
: [ {
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
\n
"
" } ],
\n
"
"
\"
shared-networks
\"
: [ ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_SUCCESS
,
""
);
}
// Test verifies that if a shared network is defined, it at least has to have
// a name.
TEST_F
(
Dhcp6ParserTest
,
sharedNetworksNoName
)
{
string
config
=
"{
\n
"
"
\"
valid-lifetime
\"
: 4000,
\n
"
"
\"
rebind-timer
\"
: 2000,
\n
"
"
\"
renew-timer
\"
: 1000,
\n
"
"
\"
subnet6
\"
: [ {
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
\n
"
" } ],
\n
"
"
\"
shared-networks
\"
: [ { } ]
\n
"
"}
\n
"
;
EXPECT_THROW
(
parseDHCP6
(
config
,
true
),
Dhcp6ParseError
);
}
// Test verifies that empty shared networks are accepted.
TEST_F
(
Dhcp6ParserTest
,
sharedNetworksEmptyName
)
{
string
config
=
"{
\n
"
"
\"
valid-lifetime
\"
: 4000,
\n
"
"
\"
rebind-timer
\"
: 2000,
\n
"
"
\"
renew-timer
\"
: 1000,
\n
"
"
\"
subnet6
\"
: [ {
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
\n
"
" } ],
\n
"
"
\"
shared-networks
\"
: [ {
\"
name
\"
:
\"\"
} ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_ERROR
,
"Shared-network with subnets is missing mandatory 'name' parameter"
);
}
// Test verifies that a degenerated shared-network (no subnets) is
// accepted.
TEST_F
(
Dhcp6ParserTest
,
sharedNetworksName
)
{
string
config
=
"{
\n
"
"
\"
subnet6
\"
: [ {
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8::1 - 2001:db8::ffff
\"
} ]
\n
"
" } ],
\n
"
"
\"
shared-networks
\"
: [ {
\"
name
\"
:
\"
foo
\"
} ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_SUCCESS
,
""
);
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr
cfg_net
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSharedNetworks6
();
ASSERT_TRUE
(
cfg_net
);
const
SharedNetwork6Collection
*
nets
=
cfg_net
->
getAll
();
ASSERT_TRUE
(
nets
);
ASSERT_EQ
(
1
,
nets
->
size
());
SharedNetwork6Ptr
net
=
*
(
nets
->
begin
());
ASSERT_TRUE
(
net
);
EXPECT_EQ
(
"foo"
,
net
->
getName
());
// Verify that there are no subnets in this shared-network
const
Subnet6Collection
*
subs
=
net
->
getAllSubnets
();
ASSERT_TRUE
(
subs
);
EXPECT_EQ
(
0
,
subs
->
size
());
}
// Test verifies that a degenerated shared-network (just one subnet) is
// accepted. Also tests that, unless explicitly specified, the subnet
// gets default values.
TEST_F
(
Dhcp6ParserTest
,
sharedNetworks1subnet
)
{
string
config
=
"{
\n
"
"
\"
shared-networks
\"
: [ {
\n
"
"
\"
name
\"
:
\"
foo
\"\n
,"
"
\"
subnet6
\"
: [ {
\n
"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8::1 - 2001:db8::ffff
\"
} ]
\n
"
" } ]
\n
"
" } ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_SUCCESS
,
""
);
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr
cfg_net
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSharedNetworks6
();
ASSERT_TRUE
(
cfg_net
);
// There should be exactly one shared subnet.
const
SharedNetwork6Collection
*
nets
=
cfg_net
->
getAll
();
ASSERT_TRUE
(
nets
);
ASSERT_EQ
(
1
,
nets
->
size
());
SharedNetwork6Ptr
net
=
*
(
nets
->
begin
());
ASSERT_TRUE
(
net
);
EXPECT_EQ
(
"foo"
,
net
->
getName
());
// It should have one subnet. The subnet should have default values.
const
Subnet6Collection
*
subs
=
net
->
getAllSubnets
();
ASSERT_TRUE
(
subs
);
EXPECT_EQ
(
1
,
subs
->
size
());
checkSubnet
(
*
subs
,
"2001:db8::/48"
,
900
,
1800
,
3600
,
7200
);
// Now make sure the subnet was added to global list of subnets.
CfgSubnets6Ptr
subnets6
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSubnets6
();
ASSERT_TRUE
(
subnets6
);
subs
=
subnets6
->
getAll
();
ASSERT_TRUE
(
subs
);
checkSubnet
(
*
subs
,
"2001:db8::/48"
,
900
,
1800
,
3600
,
7200
);
}
// Test verifies that a a proper shared-network (three subnets) is
// accepted. It verifies several things:
// - that more than one subnet can be added to shared subnets
// - that each subnet being part of the shared subnets is also stored in
// global subnets collection
// - that a subnet can inherit global values
// - that subnet can override global parameters
// - that overridden parameters only affect one subnet and not others
TEST_F
(
Dhcp6ParserTest
,
sharedNetworks3subnets
)
{
string
config
=
"{
\n
"
"
\"
renew-timer
\"
: 1000,
\n
"
"
\"
rebind-timer
\"
: 2000,
\n
"
"
\"
preferred-lifetime
\"
: 3000,
\n
"
"
\"
valid-lifetime
\"
: 4000,
\n
"
"
\"
shared-networks
\"
: [ {
\n
"
"
\"
name
\"
:
\"
foo
\"\n
,"
"
\"
subnet6
\"
: [
\n
"
" {
\n
"
"
\"
subnet
\"
:
\"
2001:db1::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db1::/64
\"
} ]
\n
"
" },
\n
"
" {
\n
"
"
\"
subnet
\"
:
\"
2001:db2::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db2::/64
\"
} ],
\n
"
"
\"
renew-timer
\"
: 2,
\n
"
"
\"
rebind-timer
\"
: 22,
\n
"
"
\"
preferred-lifetime
\"
: 222,
\n
"
"
\"
valid-lifetime
\"
: 2222
\n
"
" },
\n
"
" {
\n
"
"
\"
subnet
\"
:
\"
2001:db3::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db3::/64
\"
} ]
\n
"
" }
\n
"
" ]
\n
"
" } ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_SUCCESS
,
""
);
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr
cfg_net
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSharedNetworks6
();
// There is expected one shared subnet.
ASSERT_TRUE
(
cfg_net
);
const
SharedNetwork6Collection
*
nets
=
cfg_net
->
getAll
();
ASSERT_TRUE
(
nets
);
ASSERT_EQ
(
1
,
nets
->
size
());
SharedNetwork6Ptr
net
=
*
(
nets
->
begin
());
ASSERT_TRUE
(
net
);
EXPECT_EQ
(
"foo"
,
net
->
getName
());
const
Subnet6Collection
*
subs
=
net
->
getAllSubnets
();
ASSERT_TRUE
(
subs
);
EXPECT_EQ
(
3
,
subs
->
size
());
checkSubnet
(
*
subs
,
"2001:db1::/48"
,
1000
,
2000
,
3000
,
4000
);
checkSubnet
(
*
subs
,
"2001:db2::/48"
,
2
,
22
,
222
,
2222
);
checkSubnet
(
*
subs
,
"2001:db3::/48"
,
1000
,
2000
,
3000
,
4000
);
// Now make sure the subnet was added to global list of subnets.
CfgSubnets6Ptr
subnets6
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSubnets6
();
ASSERT_TRUE
(
subnets6
);
subs
=
subnets6
->
getAll
();
ASSERT_TRUE
(
subs
);
checkSubnet
(
*
subs
,
"2001:db1::/48"
,
1000
,
2000
,
3000
,
4000
);
checkSubnet
(
*
subs
,
"2001:db2::/48"
,
2
,
22
,
222
,
2222
);
checkSubnet
(
*
subs
,
"2001:db3::/48"
,
1000
,
2000
,
3000
,
4000
);
}
// This test checks if parameters are derived properly:
// - global to shared network
// - shared network to subnet
TEST_F
(
Dhcp6ParserTest
,
sharedNetworksDerive
)
{
string
config
=
"{
\n
"
"
\"
renew-timer
\"
: 1,
\n
"
"
\"
rebind-timer
\"
: 2,
\n
"
"
\"
preferred-lifetime
\"
: 3,
\n
"
"
\"
valid-lifetime
\"
: 4,
\n
"
"
\"
shared-networks
\"
: [ {
\n
"
"
\"
name
\"
:
\"
foo
\"\n
,"
"
\"
renew-timer
\"
: 10,
\n
"
"
\"
subnet6
\"
: [
\n
"
" {
\n
"
"
\"
subnet
\"
:
\"
2001:db1::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db1::/64
\"
} ]
\n
"
" },
\n
"
" {
\n
"
"
\"
subnet
\"
:
\"
2001:db2::/48
\"
,
\n
"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db2::/64
\"
} ],
\n
"
"
\"
renew-timer
\"
: 100
\n
"
" }
\n
"
" ]
\n
"
" } ]
\n
"
"}
\n
"
;
configure
(
config
,
CONTROL_RESULT_SUCCESS
,
""
);
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr
cfg_net
=
CfgMgr
::
instance
().
getStagingCfg
()
->
getCfgSharedNetworks6
();
// There is expected one shared subnet.
ASSERT_TRUE
(
cfg_net
);
const
SharedNetwork6Collection
*
nets
=
cfg_net
->
getAll
();
ASSERT_TRUE
(
nets
);
ASSERT_EQ
(
1
,
nets
->
size
());
SharedNetwork6Ptr
net
=
*
(
nets
->
begin
());
ASSERT_TRUE
(
net
);
const
Subnet6Collection
*
subs
=
net
->
getAllSubnets
();
ASSERT_TRUE
(
subs
);