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
ffdc326d
Commit
ffdc326d
authored
Jul 10, 2013
by
Marcin Siodelski
Browse files
[1555] Implemented configuration parameter to select interfaces for DHCPv4
parent
dd01c785
Changes
11
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/config_parser.cc
View file @
ffdc326d
...
...
@@ -347,7 +347,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
(
config_id
.
compare
(
"rebind-timer"
)
==
0
))
{
parser
=
new
Uint32Parser
(
config_id
,
globalContext
()
->
uint32_values_
);
}
else
if
(
config_id
.
compare
(
"interface"
)
==
0
)
{
}
else
if
(
config_id
.
compare
(
"interface
s
"
)
==
0
)
{
parser
=
new
InterfaceListConfigParser
(
config_id
);
}
else
if
(
config_id
.
compare
(
"subnet4"
)
==
0
)
{
parser
=
new
Subnets4ListConfigParser
(
config_id
);
...
...
@@ -397,6 +397,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
ParserCollection
independent_parsers
;
ParserPtr
subnet_parser
;
ParserPtr
option_parser
;
ParserPtr
iface_parser
;
// The subnet parsers implement data inheritance by directly
// accessing global storage. For this reason the global data
...
...
@@ -428,6 +429,11 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
subnet_parser
=
parser
;
}
else
if
(
config_pair
.
first
==
"option-data"
)
{
option_parser
=
parser
;
}
else
if
(
config_pair
.
first
==
"interfaces"
)
{
// The interface parser is independent from any other
// parser and can be run here before any other parsers.
iface_parser
=
parser
;
parser
->
build
(
config_pair
.
second
);
}
else
{
// Those parsers should be started before other
// parsers so we can call build straight away.
...
...
@@ -483,6 +489,10 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
if
(
subnet_parser
)
{
subnet_parser
->
commit
();
}
if
(
iface_parser
)
{
iface_parser
->
commit
();
}
}
catch
(
const
isc
::
Exception
&
ex
)
{
LOG_ERROR
(
dhcp4_logger
,
DHCP4_PARSER_COMMIT_FAIL
).
arg
(
ex
.
what
());
...
...
src/bin/dhcp4/dhcp4.spec
View file @
ffdc326d
...
...
@@ -3,7 +3,7 @@
"module_name": "Dhcp4",
"module_description": "DHCPv4 server daemon",
"config_data": [
{ "item_name": "interface",
{ "item_name": "interface
s
",
"item_type": "list",
"item_optional": false,
"item_default": [ "all" ],
...
...
src/bin/dhcp4/tests/config_parser_unittest.cc
View file @
ffdc326d
...
...
@@ -51,6 +51,7 @@ public:
// deal with sockets here, just check if configuration handling
// is sane.
srv_
.
reset
(
new
Dhcpv4Srv
(
0
));
CfgMgr
::
instance
().
deleteActiveIfaces
();
}
// Checks if global parameter of name have expected_value
...
...
@@ -138,7 +139,7 @@ public:
/// describing an option.
std
::
string
createConfigWithOption
(
const
std
::
map
<
std
::
string
,
std
::
string
>&
params
)
{
std
::
ostringstream
stream
;
stream
<<
"{
\"
interface
\"
: [
\"
all
\"
],"
stream
<<
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -245,7 +246,7 @@ public:
void
resetConfiguration
()
{
ConstElementPtr
status
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000, "
...
...
@@ -322,7 +323,7 @@ TEST_F(Dhcp4ParserTest, emptySubnet) {
ConstElementPtr
status
;
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
Element
::
fromJSON
(
"{
\"
interface
\"
: [
\"
all
\"
],"
Element
::
fromJSON
(
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ ], "
...
...
@@ -342,7 +343,7 @@ TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
ConstElementPtr
status
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -372,7 +373,7 @@ TEST_F(Dhcp4ParserTest, subnetLocal) {
ConstElementPtr
status
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -403,7 +404,7 @@ TEST_F(Dhcp4ParserTest, poolOutOfSubnet) {
ConstElementPtr
status
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -427,7 +428,7 @@ TEST_F(Dhcp4ParserTest, poolPrefixLen) {
ConstElementPtr
status
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -949,7 +950,7 @@ TEST_F(Dhcp4ParserTest, optionStandardDefOverride) {
// configuration does not include options configuration.
TEST_F
(
Dhcp4ParserTest
,
optionDataDefaults
)
{
ConstElementPtr
x
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1022,7 +1023,7 @@ TEST_F(Dhcp4ParserTest, optionDataTwoSpaces) {
// The definition is not required for the option that
// belongs to the 'dhcp4' option space as it is the
// standard option.
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1100,7 +1101,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
// at the very end (when all other parameters are configured).
// Starting stage 1. Configure sub-options and their definitions.
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1149,7 +1150,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
// the configuration from the stage 2 is repeated because BIND
// configuration manager sends whole configuration for the lists
// where at least one element is being modified or added.
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1245,7 +1246,7 @@ TEST_F(Dhcp4ParserTest, optionDataEncapsulate) {
// option setting.
TEST_F
(
Dhcp4ParserTest
,
optionDataInSingleSubnet
)
{
ConstElementPtr
x
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
option-data
\"
: [ {"
...
...
@@ -1317,7 +1318,7 @@ TEST_F(Dhcp4ParserTest, optionDataInSingleSubnet) {
// for multiple subnets.
TEST_F
(
Dhcp4ParserTest
,
optionDataInMultipleSubnets
)
{
ConstElementPtr
x
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet4
\"
: [ { "
...
...
@@ -1597,7 +1598,7 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
// In the first stahe we create definitions of suboptions
// that we will add to the base option.
// Let's create some dummy options: foo and foo2.
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
string
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1650,7 +1651,7 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
// We add our dummy options to this option space and thus
// they should be included as sub-options in the 'vendor-opts'
// option.
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
config
=
"{
\"
interface
s
\"
: [
\"
all
\"
],"
"
\"
rebind-timer
\"
: 2000,"
"
\"
renew-timer
\"
: 1000,"
"
\"
option-data
\"
: [ {"
...
...
@@ -1749,5 +1750,69 @@ TEST_F(Dhcp4ParserTest, stdOptionDataEncapsulate) {
EXPECT_FALSE
(
desc
.
option
->
getOption
(
3
));
}
// This test verifies that it is possible to select subset of interfaces
// on which server should listen.
TEST_F
(
Dhcp4ParserTest
,
selectedInterfaces
)
{
ConstElementPtr
x
;
string
config
=
"{
\"
interfaces
\"
: [
\"
eth0
\"
,
\"
eth1
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000 }"
;
};
ElementPtr
json
=
Element
::
fromJSON
(
config
);
ConstElementPtr
status
;
// Make sure the config manager is clean and there is no hanging
// interface configuration.
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth0"
));
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth1"
));
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth2"
));
// Apply configuration.
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// eth0 and eth1 were explicitly selected. eth2 was not.
EXPECT_TRUE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth0"
));
EXPECT_TRUE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth1"
));
EXPECT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth2"
));
}
// This test verifies that it is possible to configure the server in such a way
// that it listens on all interfaces.
TEST_F
(
Dhcp4ParserTest
,
allInterfaces
)
{
ConstElementPtr
x
;
// This configuration specifies two interfaces on which server should listen
// but it also includes keyword 'all'. This keyword switches server into the
// mode when it listens on all interfaces regardless of what interface names
// were specified in the "interfaces" parameter.
string
config
=
"{
\"
interfaces
\"
: [
\"
eth0
\"
,
\"
all
\"
,
\"
eth1
\"
],"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
valid-lifetime
\"
: 4000 }"
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
ConstElementPtr
status
;
// Make sure there is no old configuration.
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth0"
));
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth1"
));
ASSERT_FALSE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth2"
));
// Apply configuration.
EXPECT_NO_THROW
(
status
=
configureDhcp4Server
(
*
srv_
,
json
));
ASSERT_TRUE
(
status
);
checkResult
(
status
,
0
);
// All interfaces should be now active.
EXPECT_TRUE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth0"
));
EXPECT_TRUE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth1"
));
EXPECT_TRUE
(
CfgMgr
::
instance
().
isActiveIface
(
"eth2"
));
}
}
src/bin/dhcp6/dhcp6.spec
View file @
ffdc326d
...
...
@@ -3,7 +3,7 @@
"module_name": "Dhcp6",
"module_description": "DHCPv6 server daemon",
"config_data": [
{ "item_name": "interface",
{ "item_name": "interface
s
",
"item_type": "list",
"item_optional": false,
"item_default": [ "all" ],
...
...
src/lib/dhcpsrv/cfgmgr.cc
View file @
ffdc326d
...
...
@@ -266,9 +266,61 @@ std::string CfgMgr::getDataDir() {
return
(
datadir_
);
}
void
CfgMgr
::
addActiveIface
(
const
std
::
string
&
iface
)
{
if
(
isIfaceListedActive
(
iface
))
{
isc_throw
(
DuplicateListeningIface
,
"attempt to add duplicate interface '"
<<
iface
<<
"'"
" to the set of interfaces on which server listens"
);
}
LOG_DEBUG
(
dhcpsrv_logger
,
DHCPSRV_DBG_TRACE
,
DHCPSRV_CFGMGR_ADD_IFACE
)
.
arg
(
iface
);
active_ifaces_
.
push_back
(
iface
);
}
void
CfgMgr
::
activateAllIfaces
()
{
LOG_DEBUG
(
dhcpsrv_logger
,
DHCPSRV_DBG_TRACE
,
DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE
);
all_ifaces_active_
=
true
;
}
void
CfgMgr
::
deleteActiveIfaces
()
{
LOG_DEBUG
(
dhcpsrv_logger
,
DHCPSRV_DBG_TRACE
,
DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES
);
active_ifaces_
.
clear
();
all_ifaces_active_
=
false
;
}
bool
CfgMgr
::
isActiveIface
(
const
std
::
string
&
iface
)
const
{
// @todo Verify that the interface with the specified name is
// present in the system.
// If all interfaces are marked active, there is no need to check that
// the name of this interface has been explicitly listed.
if
(
all_ifaces_active_
)
{
return
(
true
);
}
return
(
isIfaceListedActive
(
iface
));
}
bool
CfgMgr
::
isIfaceListedActive
(
const
std
::
string
&
iface
)
const
{
for
(
ActiveIfacesCollection
::
const_iterator
it
=
active_ifaces_
.
begin
();
it
!=
active_ifaces_
.
end
();
++
it
)
{
if
(
iface
==
*
it
)
{
return
(
true
);
}
}
return
(
false
);
}
CfgMgr
::
CfgMgr
()
:
datadir_
(
DHCP_DATA_DIR
)
{
:
datadir_
(
DHCP_DATA_DIR
),
all_ifaces_active_
(
false
)
{
// DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
// Note: the definition of DHCP_DATA_DIR needs to include quotation marks
// See AM_CPPFLAGS definition in Makefile.am
...
...
src/lib/dhcpsrv/cfgmgr.h
View file @
ffdc326d
...
...
@@ -30,10 +30,21 @@
#include <map>
#include <string>
#include <vector>
#include <list>
namespace
isc
{
namespace
dhcp
{
/// @brief Exception thrown when the same interface has been specified twice.
///
/// In particular, this exception is thrown when adding interface to the set
/// of interfaces on which server is supposed to listen.
class
DuplicateListeningIface
:
public
Exception
{
public:
DuplicateListeningIface
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{
};
};
/// @brief Configuration Manager
///
...
...
@@ -237,6 +248,36 @@ public:
/// @return data directory
std
::
string
getDataDir
();
/// @brief Adds the name of the interface to the set of interfaces on which
/// server should listen.
///
/// @param iface A name of the interface being added to the listening set.
void
addActiveIface
(
const
std
::
string
&
iface
);
/// @brief Configures the server to listen on all interfaces.
///
/// This function configrues the server to listen on all available
/// interfaces regardless of the interfaces specified with
/// @c CfgMgr::addListeningInterface.
void
activateAllIfaces
();
/// @brief Clear the collection of the interfaces that server is configured
/// to use to listen for incoming requests.
///
/// Apart from clearing the list of interfaces specified with
/// @c CfgMgr::addListeningInterface, it also disables listening on all
/// interfaces if it has been enabled using @c CfgMgr::listenAllInterfaces.
void
deleteActiveIfaces
();
/// @brief Check if server is configured to listen on the interface which
/// name is specified as an argument to this function.
///
/// @param iface A name of the interface to be checked.
///
/// @return true if the specified interface belongs to the set of the
/// interfaces on which server is configured to listen.
bool
isActiveIface
(
const
std
::
string
&
iface
)
const
;
protected:
/// @brief Protected constructor.
...
...
@@ -268,6 +309,20 @@ protected:
private:
/// @brief Checks if the specified interface is listed as active.
///
/// This function searches for the specified interface name on the list of
/// active interfaces: @c CfgMgr::active_ifaces_. It does not take into
/// account @c CfgMgr::all_ifaces_active_ flag. If this flag is set to true
/// but the specified interface does not belong to
/// @c CfgMgr::active_ifaces_, it will return false.
///
/// @param iface interface name.
///
/// @return true if specified interface belongs to
/// @c CfgMgr::active_ifaces_.
bool
isIfaceListedActive
(
const
std
::
string
&
iface
)
const
;
/// @brief A collection of option definitions.
///
/// A collection of option definitions that can be accessed
...
...
@@ -283,6 +338,16 @@ private:
/// @brief directory where data files (e.g. server-id) are stored
std
::
string
datadir_
;
/// @name A collection of interface names on which server listens.
//@{
typedef
std
::
list
<
std
::
string
>
ActiveIfacesCollection
;
std
::
list
<
std
::
string
>
active_ifaces_
;
//@}
/// A flag which indicates that server should listen on all available
/// interfaces.
bool
all_ifaces_active_
;
};
}
// namespace isc::dhcp
...
...
src/lib/dhcpsrv/dhcp_parsers.cc
View file @
ffdc326d
...
...
@@ -33,6 +33,10 @@ using namespace isc::data;
namespace
isc
{
namespace
dhcp
{
namespace
{
const
char
*
ALL_IFACES_KEYWORD
=
"all"
;
}
// *********************** ParserContext *************************
ParserContext
::
ParserContext
(
Option
::
Universe
universe
)
:
...
...
@@ -140,33 +144,83 @@ template <> void ValueParser<std::string>::build(ConstElementPtr value) {
// ******************** InterfaceListConfigParser *************************
InterfaceListConfigParser
::
InterfaceListConfigParser
(
const
std
::
string
&
param_name
)
{
if
(
param_name
!=
"interface"
)
{
InterfaceListConfigParser
::
InterfaceListConfigParser
(
const
std
::
string
&
param_name
)
:
activate_all_
(
false
),
param_name_
(
param_name
)
{
if
(
param_name_
!=
"interfaces"
)
{
isc_throw
(
BadValue
,
"Internal error. Interface configuration "
"parser called for the wrong parameter: "
<<
param_name
);
}
}
void
void
InterfaceListConfigParser
::
build
(
ConstElementPtr
value
)
{
// First, we iterate over all specified entries and add it to the
// local container so as we can do some basic validation, e.g. eliminate
// duplicates.
BOOST_FOREACH
(
ConstElementPtr
iface
,
value
->
listValue
())
{
interfaces_
.
push_back
(
iface
->
str
());
std
::
string
iface_name
=
iface
->
stringValue
();
if
(
iface_name
!=
ALL_IFACES_KEYWORD
)
{
// Let's eliminate duplicates. We could possibly allow duplicates,
// but if someone specified duplicated interface name it is likely
// that he mistyped the configuration. Failing here should draw his
// attention.
if
(
isIfaceAdded
(
iface_name
))
{
isc_throw
(
isc
::
dhcp
::
DhcpConfigError
,
"duplicate interface"
<<
" name '"
<<
iface_name
<<
"' specified in '"
<<
param_name_
<<
"' configuration parameter"
);
}
// @todo check that this interface exists in the system!
// The IfaceMgr exposes mechanisms to check this.
// Add the interface name if ok.
interfaces_
.
push_back
(
iface_name
);
}
else
{
activate_all_
=
true
;
}
}
}
void
void
InterfaceListConfigParser
::
commit
()
{
/// @todo: Implement per interface listening. Currently always listening
/// on all interfaces.
CfgMgr
&
cfg_mgr
=
CfgMgr
::
instance
();
// Remove active interfaces and clear a flag which marks all interfaces
// active
cfg_mgr
.
deleteActiveIfaces
();
if
(
activate_all_
)
{
// Activate all interfaces. There is not need to add their names
// explicitly.
cfg_mgr
.
activateAllIfaces
();
}
else
{
// Explicitly add names of the interfaces which server should listen on.
BOOST_FOREACH
(
std
::
string
iface
,
interfaces_
)
{
cfg_mgr
.
addActiveIface
(
iface
);
}
}
}
bool
InterfaceListConfigParser
::
isIfaceAdded
(
const
std
::
string
&
iface
)
const
{
for
(
IfaceListStorage
::
const_iterator
it
=
interfaces_
.
begin
();
it
!=
interfaces_
.
end
();
++
it
)
{
if
(
iface
==
*
it
)
{
return
(
true
);
}
}
return
(
false
);
}
// **************************** OptionDataParser *************************
OptionDataParser
::
OptionDataParser
(
const
std
::
string
&
,
OptionStoragePtr
options
,
ParserContextPtr
global_context
)
:
boolean_values_
(
new
BooleanStorage
()),
string_values_
(
new
StringStorage
()),
uint32_values_
(
new
Uint32Storage
()),
options_
(
options
),
option_descriptor_
(
false
),
:
boolean_values_
(
new
BooleanStorage
()),
string_values_
(
new
StringStorage
()),
uint32_values_
(
new
Uint32Storage
()),
options_
(
options
),
option_descriptor_
(
false
),
global_context_
(
global_context
)
{
if
(
!
options_
)
{
isc_throw
(
isc
::
dhcp
::
DhcpConfigError
,
"parser logic error:"
...
...
src/lib/dhcpsrv/dhcp_parsers.h
View file @
ffdc326d
...
...
@@ -302,8 +302,23 @@ public:
virtual
void
commit
();
private:
/// @brief Check that specified interface exists in
/// @c InterfaceListConfigParser::interfaces_.
///
/// @param iface A name of the interface.
///
/// @return true if specified interface name was found.
bool
isIfaceAdded
(
const
std
::
string
&
iface
)
const
;
/// contains list of network interfaces
std
::
vector
<
std
::
string
>
interfaces_
;
typedef
std
::
list
<
std
::
string
>
IfaceListStorage
;
IfaceListStorage
interfaces_
;
// Should server listen on all interfaces.
bool
activate_all_
;
// Parsed parameter name
std
::
string
param_name_
;
};
...
...
src/lib/dhcpsrv/dhcpsrv_messages.mes
View file @
ffdc326d
...
...
@@ -54,6 +54,10 @@ consider reducing the lease lifetime. In this way, addresses allocated
to clients that are no longer active on the network will become available
available sooner.
% DHCPSRV_CFGMGR_ADD_IFACE adding listening interface %1
A debug message issued when new interface is being added to the collection of
interfaces on which server listens to DHCP messages.
% DHCPSRV_CFGMGR_ADD_SUBNET4 adding subnet %1
A debug message reported when the DHCP configuration manager is adding the
specified IPv4 subnet to its database.
...
...
@@ -62,6 +66,16 @@ specified IPv4 subnet to its database.
A debug message reported when the DHCP configuration manager is adding the
specified IPv6 subnet to its database.
% DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE enabling listening on all interfaces
A debug message issued when server is being configured to listen on all
interfaces.
% DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES stop listening on all interfaces
A debug message issued when configuration manager clears the internal list
of active interfaces. This doesn't prevent the server from listening to
the DHCP traffic through open sockets, but will rather be used by Interface
Manager to select active interfaces when sockets are re-opened.
% DHCPSRV_CFGMGR_DELETE_SUBNET4 deleting all IPv4 subnets
A debug message noting that the DHCP configuration manager has deleted all IPv4
subnets in its database.
...
...
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
View file @
ffdc326d
...
...
@@ -165,6 +165,7 @@ public:
CfgMgr
::
instance
().
deleteSubnets4
();
CfgMgr
::
instance
().
deleteSubnets6
();
CfgMgr
::
instance
().
deleteOptionDefs
();
CfgMgr
::
instance
().
deleteActiveIfaces
();
}
/// @brief generates interface-id option based on provided text
...
...
@@ -573,6 +574,50 @@ TEST_F(CfgMgrTest, optionSpace6) {
// @todo decide if a duplicate vendor space is allowed.
}
// This test verifies that it is possible to specify interfaces that server
// should listen on.
TEST_F
(
CfgMgrTest
,
addActiveIface
)
{
CfgMgr
&
cfg_mgr
=
CfgMgr
::
instance
();
cfg_mgr
.
addActiveIface
(
"eth0"
);
cfg_mgr
.
addActiveIface
(
"eth1"
);
EXPECT_TRUE
(
cfg_mgr
.
isActiveIface
(
"eth0"
));
EXPECT_TRUE
(
cfg_mgr
.
isActiveIface
(
"eth1"
));
EXPECT_FALSE
(
cfg_mgr
.
isActiveIface
(
"eth2"
));
cfg_mgr
.
deleteActiveIfaces
();
EXPECT_FALSE
(
cfg_mgr
.
isActiveIface
(
"eth0"
));
EXPECT_FALSE
(
cfg_mgr
.
isActiveIface
(
"eth1"
));
EXPECT_FALSE
(
cfg_mgr
.
isActiveIface
(
"eth2"
));
}
// This test verifies that it is possible to set the flag which configures the
// server to listen on all interfaces.