/// @brief Represents configuration of IPv4 shared networks.
class CfgSharedNetworks4 : public CfgSharedNetworks<SharedNetwork4Ptr> {
+public:
+
+ /// @brief Returns pointer to all configured shared networks.
+ const SharedNetwork4Collection* getAll() const {
+ return (&networks_);
+ }
+
};
/// @brief Pointer to the configuration of IPv4 shared networks.
/// @brief Represents configuration of IPv6 shared networks.
class CfgSharedNetworks6 : public CfgSharedNetworks<SharedNetwork6Ptr> {
+public:
+
+ /// @brief Returns pointer to all configured shared networks.
+ const SharedNetwork6Collection* getAll() const {
+ return (&networks_);
+ }
};
/// @brief Pointer to the configuration of IPv6 shared networks.
return (cnt);
}
+size_t
+Subnets4ListConfigParser::parse(Subnet4Collection& subnets,
+ data::ConstElementPtr subnets_list) {
+ size_t cnt = 0;
+ BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
+
+ Subnet4ConfigParser parser;
+ Subnet4Ptr subnet = parser.parse(subnet_json);
+ if (subnet) {
+ try {
+ subnets.push_back(subnet);
+ ++cnt;
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << subnet_json->getPosition() << ")");
+ }
+ }
+ }
+ return (cnt);
+}
+
+
//**************************** Pool6Parser *********************************
PoolPtr
return (cnt);
}
+size_t
+Subnets6ListConfigParser::parse(Subnet6Collection& subnets,
+ ConstElementPtr subnets_list) {
+ size_t cnt = 0;
+ BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
+
+ Subnet6ConfigParser parser;
+ Subnet6Ptr subnet = parser.parse(subnet_json);
+ try {
+ subnets.push_back(subnet);
+ ++cnt;
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << subnet_json->getPosition() << ")");
+ }
+ }
+ return (cnt);
+}
+
//**************************** D2ClientConfigParser **********************
/// @param subnets_list pointer to a list of IPv4 subnets
/// @return number of subnets created
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list);
+
+ /// @brief Parses contents of the subnet4 list.
+ ///
+ /// @param [out] subnets Container where parsed subnets will be stored.
+ /// @param subnets_list pointer to a list of IPv4 subnets
+ /// @return Number of subnets created.
+ size_t parse(Subnet4Collection& subnets,
+ data::ConstElementPtr subnets_list);
};
/// @brief Parser for IPv6 pool definitions.
/// @param subnets_list pointer to a list of IPv6 subnets
/// @throw DhcpConfigError if CfgMgr rejects the subnet (e.g. subnet-id is a duplicate)
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list);
+
+ /// @brief Parses contents of the subnet6 list.
+ ///
+ /// @param [out] subnets Container where parsed subnets will be stored.
+ /// @param subnets_list pointer to a list of IPv6 subnets
+ /// @return Number of subnets created.
+ size_t parse(Subnet6Collection& subnets,
+ data::ConstElementPtr subnets_list);
+
};
/// @brief Parser for D2ClientConfig
#include <cc/data.h>
#include <cc/simple_parser.h>
+#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
#include <util/optional_value.h>
#include <cstdint>
#define SHARED_NETWORK_PARSER_H
#include <cc/data.h>
+#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/parsers/dhcp_parsers.h>
+#include <dhcpsrv/parsers/option_data_parser.h>
#include <dhcpsrv/parsers/shared_network_parser.h>
#include <dhcpsrv/shared_network.h>
+#include <boost/pointer_cast.hpp>
+#include <string>
using namespace isc::data;
namespace isc {
namespace dhcp {
-SharedNetworkParser::~SharedNetworkParser() {
+SharedNetwork4Ptr
+SharedNetwork4Parser::parse(const data::ConstElementPtr& shared_network_data) {
+ SharedNetwork4Ptr shared_network;
+ std::string name;
+ try {
+ // Shared network is a map.
+ const auto& element = shared_network_data->mapValue();
+
+ // Make sure that the network name has been specified. The name is required
+ // to create a SharedNetwork4 object.
+ const auto& name_it = element.find("name");
+ if (name_it == element.cend()) {
+ isc_throw(DhcpConfigError, "parameter \"name\" must be specified for"
+ " a shared network");
+
+ }
+ shared_network.reset(new SharedNetwork4(name_it->second->stringValue()));
+
+ // Iterate over all parameters within the map and assign them to the
+ // shared network.
+ for (auto param = element.cbegin(); param != element.cend(); ++param) {
+ if (param->first == "interface") {
+ shared_network->setIface(param->second->stringValue());
+
+ } else if (param->first == "option-data") {
+ // Create parser instance for option-data.
+ CfgOptionPtr cfg_option = shared_network->getCfgOption();
+ OptionDataListParser parser(AF_INET);
+ parser.parse(cfg_option, param->second);
+
+ } else if (param->first == "subnet4") {
+ // Create parser instance of subnet4.
+ Subnets4ListConfigParser parser;
+ Subnet4Collection subnets;
+ parser.parse(subnets, param->second);
+
+ // Add all returned subnets into shared network.
+ for (auto subnet = subnets.cbegin(); subnet != subnets.cend();
+ ++subnet) {
+ shared_network->add(*subnet);
+ }
+ }
+ }
+
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << shared_network_data->getPosition() << ")");
+ }
+
+ return (shared_network);
}
-SharedNetworkPtr
-SharedNetworkParser::parse(const ConstElementPtr& shared_network_data) {
- return (SharedNetworkPtr());
+SharedNetwork6Ptr
+SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) {
+ SharedNetwork6Ptr shared_network;
+ std::string name;
+ try {
+ // Shared network is a map.
+ const auto& element = shared_network_data->mapValue();
+
+ // Make sure that the network name has been specified. The name is required
+ // to create a SharedNetwork6 object.
+ const auto& name_it = element.find("name");
+ if (name_it == element.cend()) {
+ isc_throw(DhcpConfigError, "parameter \"name\" must be specified for"
+ " a shared network");
+
+ }
+ shared_network.reset(new SharedNetwork6(name_it->second->stringValue()));
+
+ // Iterate over all parameters within the map and assign them to the
+ // shared network.
+ for (auto param = element.cbegin(); param != element.cend(); ++param) {
+ if (param->first == "interface") {
+ shared_network->setIface(param->second->stringValue());
+
+ } else if (param->first == "option-data") {
+ // Create parser instance for option-data.
+ CfgOptionPtr cfg_option = shared_network->getCfgOption();
+ OptionDataListParser parser(AF_INET6);
+ parser.parse(cfg_option, param->second);
+
+ } else if (param->first == "subnet6") {
+ // Create parser instance of subnet6.
+ Subnets6ListConfigParser parser;
+ Subnet6Collection subnets;
+ parser.parse(subnets, param->second);
+
+ // Add all returned subnets into shared network.
+ for (auto subnet = subnets.cbegin(); subnet != subnets.cend();
+ ++subnet) {
+ shared_network->add(*subnet);
+ }
+ }
+ }
+
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << shared_network_data->getPosition() << ")");
+ }
+
+ return (shared_network);
}
} // end of namespace isc::dhcp
#include <cc/data.h>
#include <cc/simple_parser.h>
+#include <dhcpsrv/cfg_subnets4.h>
+#include <dhcpsrv/cfg_subnets6.h>
#include <dhcpsrv/shared_network.h>
namespace isc {
namespace dhcp {
-class SharedNetworkParser : public isc::data::SimpleParser {
+/// @brief Implements parser for IPv4 shared networks.
+class SharedNetwork4Parser {
public:
- virtual ~SharedNetworkParser();
-
- virtual SharedNetworkPtr
+ /// @brief Parses shared configuration information for IPv4 shared network.
+ ///
+ /// @param shared_network_data Data element holding shared network
+ /// configuration to be parsed.
+ ///
+ /// @return Pointer to an object representing shared network.
+ /// @throw DhcpConfigError when shared network configuration is invalid.
+ SharedNetwork4Ptr
parse(const data::ConstElementPtr& shared_network_data);
+};
+/// @brief Implements parser for IPv6 shared networks.
+class SharedNetwork6Parser {
+public:
+
+ /// @brief Parses shared configuration information for IPv6 shared network.
+ ///
+ /// @param shared_network_data Data element holding shared network
+ /// configuration to be parsed.
+ ///
+ /// @return Pointer to an object representing shared network.
+ /// @throw DhcpConfigError when shared network configuration is invalid.
+ SharedNetwork6Ptr
+ parse(const data::ConstElementPtr& shared_network_data);
};
} // enf of namespace isc::dhcp
#include <exceptions/exceptions.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/parsers/shared_network_parser.h>
+#include <vector>
namespace isc {
namespace dhcp {
+/// @brief Parser for a list of shared networks.
+///
+/// This is a generic parser for a list of IPv4 or IPv6 shared networks.
+///
+/// @tparam SharedNetworkParserType Type of the parser to be used for
+/// parsing shared network, i.e. @ref SharedNetwork4Parser or
+/// @ref SharedNetwork6Parser.
template<typename SharedNetworkParserType>
class SharedNetworksListParser : public data::SimpleParser {
-protected:
+public:
+ /// @brief Parses a list of shared networks.
+ ///
+ /// @param [out] cfg Shared networks configuration structure into which
+ /// the data should be parsed.
+ /// @param shared_networks_list_data List element holding a list of
+ /// shared networks.
+ /// @tparam Type of the configuration structure into which the result
+ /// will be stored, i.e. @ref CfgSharedNetworks4 or @ref CfgSharedNetworks6.
+ ///
+ /// @throw DhcpConfigError when error has occurred, e.g. when networks
+ /// with duplicated names have been specified.
template<typename CfgSharedNetworksTypePtr>
- void parse(const data::ConstElementPtr& shared_networks_list_data,
- CfgSharedNetworksTypePtr& cfg) {
- if (shared_networks_list_data->getType() != Element::list) {
- isc_throw(data::DhcpConfigError, "shared-networks value must be a list");
+ void parse(CfgSharedNetworksTypePtr& cfg,
+ const data::ConstElementPtr& shared_networks_list_data) {
+ try {
+ // Get the C++ vector holding networks.
+ const std::vector<data::ElementPtr>& networks_list =
+ shared_networks_list_data->listValue();
+ // Iterate over all networks and do the parsing.
+ for (auto network_element = networks_list.cbegin();
+ network_element != networks_list.cend(); ++network_element) {
+ SharedNetworkParserType parser;
+ auto network = parser.parse(*network_element);
+ cfg->add(network);
+ }
+ } catch (const DhcpConfigError&) {
+ // Such exceptions are emitted by the lower level parsers and
+ // errors should already include element's positions. So, we
+ // simply rethrow.
+ throw;
+
+ } catch (const std::exception& ex) {
+ // Other exceptions don't include positions of the elements, so
+ // we should append one.
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << shared_networks_list_data->getPosition() << ")");
}
}
-
};
+/// @brief Type of the shared networks list parser for IPv4.
+typedef SharedNetworksListParser<SharedNetwork4Parser> SharedNetworks4ListParser;
+
+/// @brief Type of the shared networks list parser for IPv6.
+typedef SharedNetworksListParser<SharedNetwork6Parser> SharedNetworks6ListParser;
+
+
} // end of namespace isc::dhcp
} // end of namespace isc
libdhcpsrv_unittests_SOURCES += cql_lease_mgr_unittest.cc
endif
libdhcpsrv_unittests_SOURCES += pool_unittest.cc
+libdhcpsrv_unittests_SOURCES += shared_network_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += shared_network_unittest.cc
+libdhcpsrv_unittests_SOURCES += shared_networks_list_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += srv_config_unittest.cc
libdhcpsrv_unittests_SOURCES += subnet_unittest.cc
libdhcpsrv_unittests_SOURCES += test_get_callout_handle.cc test_get_callout_handle.h
--- /dev/null
+// Copyright (C) 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <cc/data.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcpsrv/cfg_option.h>
+#include <dhcpsrv/parsers/shared_network_parser.h>
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::data;
+using namespace isc::dhcp;
+
+namespace {
+
+/// @brief Test fixture class for SharedNetwork4Parser class.
+class SharedNetwork4ParserTest : public ::testing::Test {
+public:
+
+ /// @brief Creates valid shared network configuration.
+ ///
+ /// @return Valid shared network configuration.
+ std::string getWorkingConfig() const {
+ std::string config = "{"
+ " \"name\": \"bird\","
+ " \"interface\": \"eth1\","
+ " \"option-data\": ["
+ " {"
+ " \"name\": \"domain-name-servers\","
+ " \"data\": \"192.0.2.3\""
+ " }"
+ " ],"
+ " \"subnet4\": ["
+ " {"
+ " \"id\": 1,"
+ " \"subnet\": \"10.1.2.0/24\","
+ " \"interface\": \"\","
+ " \"renew-timer\": 100,"
+ " \"rebind-timer\": 200,"
+ " \"valid-lifetime\": 300,"
+ " \"match-client-id\": false,"
+ " \"next-server\": \"\","
+ " \"client-class\": \"\","
+ " \"reservation-mode\": \"all\","
+ " \"4o6-interface\": \"\","
+ " \"4o6-interface-id\": \"\","
+ " \"4o6-subnet\": \"\","
+ " \"dhcp4o6-port\": 0,"
+ " \"decline-probation-period\": 86400,"
+ " \"reservation-mode\": \"all\""
+ " },"
+ " {"
+ " \"id\": 2,"
+ " \"subnet\": \"192.0.2.0/24\","
+ " \"interface\": \"\","
+ " \"renew-timer\": 10,"
+ " \"rebind-timer\": 20,"
+ " \"valid-lifetime\": 30,"
+ " \"match-client-id\": false,"
+ " \"next-server\": \"\","
+ " \"client-class\": \"\","
+ " \"reservation-mode\": \"all\","
+ " \"4o6-interface\": \"\","
+ " \"4o6-interface-id\": \"\","
+ " \"4o6-subnet\": \"\","
+ " \"dhcp4o6-port\": 0,"
+ " \"decline-probation-period\": 86400,"
+ " \"reservation-mode\": \"all\""
+ " }"
+ " ]"
+ "}";
+
+ return (config);
+ }
+};
+
+// This test verifies that shared network parser for IPv4 works properly
+// in a positive test scenario.
+TEST_F(SharedNetwork4ParserTest, parse) {
+ // Basic configuration for shared network. A bunch of parameters
+ // have to be specified for subnets because subnet parsers expect
+ // that default and global values are set.
+ std::string config = getWorkingConfig();
+ ElementPtr config_element = Element::fromJSON(config);
+
+ // Parse configuration specified above.
+ SharedNetwork4Parser parser;
+ SharedNetwork4Ptr network;
+ ASSERT_NO_THROW(network = parser.parse(config_element));
+ ASSERT_TRUE(network);
+
+ // Check basic parameters.
+ EXPECT_EQ("bird", network->getName());
+ EXPECT_EQ("eth1", network->getIface());
+
+ // Subnet with id 1
+ Subnet4Ptr subnet1 = network->getSubnet(SubnetID(1));
+ ASSERT_TRUE(subnet1);
+ EXPECT_EQ("10.1.2.0", subnet1->get().first.toText());
+
+ // Subnet with id 2
+ Subnet4Ptr subnet2 = network->getSubnet(SubnetID(2));
+ ASSERT_TRUE(subnet2);
+ EXPECT_EQ("192.0.2.0", subnet2->get().first.toText());
+
+ // DHCP options
+ ConstCfgOptionPtr cfg_option = network->getCfgOption();
+ ASSERT_TRUE(cfg_option);
+ OptionDescriptor opt_dns_servers = cfg_option->get("dhcp4",
+ DHO_DOMAIN_NAME_SERVERS);
+ ASSERT_TRUE(opt_dns_servers.option_);
+ Option4AddrLstPtr dns_servers = boost::dynamic_pointer_cast<
+ Option4AddrLst>(opt_dns_servers.option_);
+ ASSERT_TRUE(dns_servers);
+ Option4AddrLst::AddressContainer addresses = dns_servers->getAddresses();
+ ASSERT_EQ(1, addresses.size());
+ EXPECT_EQ("192.0.2.3", addresses[0].toText());
+}
+
+// This test verifies that parser throws an exception when mandatory parameter
+// "name" is not specified.
+TEST_F(SharedNetwork4ParserTest, missingName) {
+ // Remove a name parameter from the valid configuration.
+ std::string config = getWorkingConfig();
+ ElementPtr config_element = Element::fromJSON(config);
+ ASSERT_NO_THROW(config_element->remove("name"));
+
+ // Parse configuration specified above.
+ SharedNetwork4Parser parser;
+ SharedNetwork4Ptr network;
+ ASSERT_THROW(network = parser.parse(config_element), DhcpConfigError);
+}
+
+/// @brief Test fixture class for SharedNetwork6Parser class.
+class SharedNetwork6ParserTest : public ::testing::Test {
+public:
+
+ /// @brief Creates valid shared network configuration.
+ ///
+ /// @return Valid shared network configuration.
+ std::string getWorkingConfig() const {
+ std::string config = "{"
+ " \"name\": \"bird\","
+ " \"interface\": \"eth1\","
+ " \"option-data\": ["
+ " {"
+ " \"name\": \"dns-servers\","
+ " \"data\": \"2001:db8:1::cafe\""
+ " }"
+ " ],"
+ " \"subnet6\": ["
+ " {"
+ " \"id\": 1,"
+ " \"subnet\": \"3000::/16\","
+ " \"interface\": \"\","
+ " \"interface-id\": \"\","
+ " \"renew-timer\": 100,"
+ " \"rebind-timer\": 200,"
+ " \"preferred-lifetime\": 300,"
+ " \"valid-lifetime\": 400,"
+ " \"client-class\": \"\","
+ " \"reservation-mode\": \"all\","
+ " \"decline-probation-period\": 86400,"
+ " \"dhcp4o6-port\": 0,"
+ " \"rapid-commit\": false"
+ " },"
+ " {"
+ " \"id\": 2,"
+ " \"subnet\": \"2001:db8:1::/64\","
+ " \"interface\": \"\","
+ " \"interface-id\": \"\","
+ " \"renew-timer\": 10,"
+ " \"rebind-timer\": 20,"
+ " \"preferred-lifetime\": 30,"
+ " \"valid-lifetime\": 40,"
+ " \"client-class\": \"\","
+ " \"reservation-mode\": \"all\","
+ " \"decline-probation-period\": 86400,"
+ " \"dhcp4o6-port\": 0,"
+ " \"rapid-commit\": false"
+ " }"
+ " ]"
+ "}";
+
+ return (config);
+ }
+};
+
+// This test verifies that shared network parser for IPv4 works properly
+// in a positive test scenario.
+TEST_F(SharedNetwork6ParserTest, parse) {
+ // Basic configuration for shared network. A bunch of parameters
+ // have to be specified for subnets because subnet parsers expect
+ // that default and global values are set.
+ std::string config = getWorkingConfig();
+ ElementPtr config_element = Element::fromJSON(config);
+
+ // Parse configuration specified above.
+ SharedNetwork6Parser parser;
+ SharedNetwork6Ptr network;
+ ASSERT_NO_THROW(network = parser.parse(config_element));
+ ASSERT_TRUE(network);
+
+ // Check basic parameters.
+ EXPECT_EQ("bird", network->getName());
+ EXPECT_EQ("eth1", network->getIface());
+
+ // Subnet with id 1
+ Subnet6Ptr subnet1 = network->getSubnet(SubnetID(1));
+ ASSERT_TRUE(subnet1);
+ EXPECT_EQ("3000::", subnet1->get().first.toText());
+
+ // Subnet with id 2
+ Subnet6Ptr subnet2 = network->getSubnet(SubnetID(2));
+ ASSERT_TRUE(subnet2);
+ EXPECT_EQ("2001:db8:1::", subnet2->get().first.toText());
+
+ // DHCP options
+ ConstCfgOptionPtr cfg_option = network->getCfgOption();
+ ASSERT_TRUE(cfg_option);
+ OptionDescriptor opt_dns_servers = cfg_option->get("dhcp6",
+ D6O_NAME_SERVERS);
+ ASSERT_TRUE(opt_dns_servers.option_);
+ Option6AddrLstPtr dns_servers = boost::dynamic_pointer_cast<
+ Option6AddrLst>(opt_dns_servers.option_);
+ ASSERT_TRUE(dns_servers);
+ Option6AddrLst::AddressContainer addresses = dns_servers->getAddresses();
+ ASSERT_EQ(1, addresses.size());
+ EXPECT_EQ("2001:db8:1::cafe", addresses[0].toText());
+}
+
+
+} // end of anonymous namespace
--- /dev/null
+// Copyright (C) 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <cc/data.h>
+#include <dhcpsrv/cfg_shared_networks.h>
+#include <dhcpsrv/shared_network.h>
+#include <dhcpsrv/parsers/shared_networks_list_parser.h>
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace isc;
+using namespace isc::data;
+using namespace isc::dhcp;
+
+namespace {
+
+// This is a basic test verifying that all shared networks are correctly
+// parsed.
+TEST(SharedNetworkListParserTest, parse) {
+ // Basic configuration with array of shared networks.
+ std::string config = "["
+ " {"
+ " \"name\": \"bird\","
+ " \"interface\": \"eth0\""
+ " },"
+ " {"
+ " \"name\": \"monkey\","
+ " \"interface\": \"eth1\""
+ " }"
+ "]";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ SharedNetworks4ListParser parser;
+ CfgSharedNetworks4Ptr cfg(new CfgSharedNetworks4());;
+ ASSERT_NO_THROW(parser.parse(cfg, config_element));
+
+ SharedNetwork4Ptr network1 = cfg->getByName("bird");
+ ASSERT_TRUE(network1);
+ EXPECT_EQ("bird", network1->getName());
+ EXPECT_EQ("eth0", network1->getIface());
+
+ SharedNetwork4Ptr network2 = cfg->getByName("monkey");
+ ASSERT_TRUE(network2);
+ EXPECT_EQ("monkey", network2->getName());
+ EXPECT_EQ("eth1", network2->getIface());
+}
+
+// This test verifies that specifying two networks with the same name
+// yields an error.
+TEST(SharedNetworkListParserTest, duplicatedName) {
+ // Basic configuration with two networks having the same name.
+ std::string config = "["
+ " {"
+ " \"name\": \"bird\","
+ " \"interface\": \"eth0\""
+ " },"
+ " {"
+ " \"name\": \"bird\","
+ " \"interface\": \"eth1\""
+ " }"
+ "]";
+
+ ElementPtr config_element = Element::fromJSON(config);
+
+ SharedNetworks4ListParser parser;
+ CfgSharedNetworks4Ptr cfg(new CfgSharedNetworks4());;
+ EXPECT_THROW(parser.parse(cfg, config_element), DhcpConfigError);
+}
+
+} // end of anonymous namespace