Commit 339d60a7 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[1555] Implemented configuration parameter to select interfaces for DHCPv6.

parent ffdc326d
......@@ -413,7 +413,7 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(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("interfaces") == 0) {
parser = new InterfaceListConfigParser(config_id);
} else if (config_id.compare("subnet6") == 0) {
parser = new Subnets6ListConfigParser(config_id);
......@@ -463,6 +463,7 @@ configureDhcp6Server(Dhcpv6Srv&, 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
......@@ -495,6 +496,11 @@ configureDhcp6Server(Dhcpv6Srv&, 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 other parsers.
parser->build(config_pair.second);
iface_parser = parser;
} else {
// Those parsers should be started before other
// parsers so we can call build straight away.
......@@ -548,6 +554,10 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
if (subnet_parser) {
subnet_parser->commit();
}
if (iface_parser) {
iface_parser->commit();
}
}
catch (const isc::Exception& ex) {
LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
......
......@@ -66,11 +66,12 @@ public:
<< " while the test assumes that it doesn't, to execute"
<< " some negative scenarios. Can't continue this test.";
}
// Reset configuration for each test.
resetConfiguration();
}
~Dhcp6ParserTest() {
// Reset configuration database after each test.
resetConfiguration();
};
// Checks if config_result (result of DHCP server configuration) has
......@@ -133,7 +134,7 @@ public:
std::string>& params)
{
std::ostringstream stream;
stream << "{ \"interface\": [ \"all\" ],"
stream << "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -173,13 +174,13 @@ public:
///
/// This function resets configuration data base by
/// removing all subnets and option-data. Reset must
/// be performed after each test to make sure that
/// be performed before each test to make sure that
/// contents of the database do not affect result of
/// subsequent tests.
/// the test being executed.
void resetConfiguration() {
ConstElementPtr status;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -213,6 +214,12 @@ public:
<< " after the test. Configuration function returned"
<< " error code " << rcode_ << std::endl;
}
// The default setting is to listen on all interfaces. In order to
// properly test interface configuration we disable listening on
// all interfaces before each test and later check that this setting
// has been overriden by the configuration used in the test.
CfgMgr::instance().deleteActiveIfaces();
}
/// @brief Test invalid option parameter value.
......@@ -324,7 +331,7 @@ TEST_F(Dhcp6ParserTest, emptySubnet) {
ConstElementPtr status;
EXPECT_NO_THROW(status = configureDhcp6Server(srv_,
Element::fromJSON("{ \"interface\": [ \"all\" ],"
Element::fromJSON("{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -343,7 +350,7 @@ TEST_F(Dhcp6ParserTest, subnetGlobalDefaults) {
ConstElementPtr status;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -377,7 +384,7 @@ TEST_F(Dhcp6ParserTest, subnetLocal) {
ConstElementPtr status;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -415,7 +422,7 @@ TEST_F(Dhcp6ParserTest, subnetInterface) {
// There should be at least one interface
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -448,7 +455,7 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceBogus) {
// There should be at least one interface
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -479,7 +486,7 @@ TEST_F(Dhcp6ParserTest, interfaceGlobal) {
ConstElementPtr status;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -549,7 +556,7 @@ TEST_F(Dhcp6ParserTest, subnetInterfaceId) {
// parameter.
TEST_F(Dhcp6ParserTest, interfaceIdGlobal) {
const string config = "{ \"interface\": [ \"all\" ],"
const string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -604,7 +611,7 @@ TEST_F(Dhcp6ParserTest, poolOutOfSubnet) {
ConstElementPtr status;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -632,7 +639,7 @@ TEST_F(Dhcp6ParserTest, poolPrefixLen) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -1152,7 +1159,7 @@ TEST_F(Dhcp6ParserTest, optionStandardDefOverride) {
// configuration does not include options configuration.
TEST_F(Dhcp6ParserTest, optionDataDefaults) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
......@@ -1234,7 +1241,7 @@ TEST_F(Dhcp6ParserTest, optionDataTwoSpaces) {
// The definition is not required for the option that
// belongs to the 'dhcp6' option space as it is the
// standard option.
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
......@@ -1312,7 +1319,7 @@ TEST_F(Dhcp6ParserTest, 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 = "{ \"interfaces\": [ \"all\" ],"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
......@@ -1361,7 +1368,7 @@ TEST_F(Dhcp6ParserTest, 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 = "{ \"interfaces\": [ \"all\" ],"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
......@@ -1455,7 +1462,7 @@ TEST_F(Dhcp6ParserTest, optionDataEncapsulate) {
// for multiple subnets.
TEST_F(Dhcp6ParserTest, optionDataInMultipleSubnets) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......@@ -1698,7 +1705,7 @@ TEST_F(Dhcp6ParserTest, 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 = "{ \"interfaces\": [ \"all\" ],"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
......@@ -1751,7 +1758,7 @@ TEST_F(Dhcp6ParserTest, 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 = "{ \"interfaces\": [ \"all\" ],"
"\"rebind-timer\": 2000,"
"\"renew-timer\": 1000,"
"\"option-data\": [ {"
......@@ -1850,4 +1857,77 @@ TEST_F(Dhcp6ParserTest, stdOptionDataEncapsulate) {
EXPECT_FALSE(desc.option->getOption(112));
}
// This test verifies that it is possible to select subset of interfaces on
// which server should listen.
TEST_F(Dhcp6ParserTest, selectedInterfaces) {
// Make sure there is no garbage interface configuration in the CfgMgr.
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
ConstElementPtr status;
string config = "{ \"interfaces\": [ \"eth0\", \"eth1\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value must be 1 (values error)
// as the pool does not belong to that subnet
ASSERT_TRUE(status);
comment_ = parseAnswer(rcode_, status);
EXPECT_EQ(0, rcode_);
// 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 to listen on
// all interfaces.
TEST_F(Dhcp6ParserTest, allInterfaces) {
// Make sure there is no garbage interface configuration in the CfgMgr.
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth0"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth1"));
ASSERT_FALSE(CfgMgr::instance().isActiveIface("eth2"));
ConstElementPtr status;
// This configuration specifies two interfaces on which server should listen
// bu 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\", \"eth1\", \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
// returned value must be 1 (values error)
// as the pool does not belong to that subnet
ASSERT_TRUE(status);
comment_ = parseAnswer(rcode_, status);
EXPECT_EQ(0, rcode_);
// All interfaces should be now active.
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth0"));
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth1"));
EXPECT_TRUE(CfgMgr::instance().isActiveIface("eth2"));
}
};
......@@ -555,7 +555,7 @@ TEST_F(Dhcpv6SrvTest, DUID) {
// and the requested options are actually assigned.
TEST_F(Dhcpv6SrvTest, advertiseOptions) {
ConstElementPtr x;
string config = "{ \"interface\": [ \"all\" ],"
string config = "{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment