From: Tomek Mrugalski Date: Wed, 13 Sep 2017 19:04:25 +0000 (+0200) Subject: [5357] Addressed comments after review: X-Git-Tag: trac5073a_base~9^2~4 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=3e1e56f15161aa6286583fd5ed9da22073073a49;p=thirdparty%2Fkea.git [5357] Addressed comments after review: - many more parameters are now inherited from shared-network to subnet4 - parameters now passed as const reference - it is no longer possible to specify echo-client-id on shared-network level (because it's a global parameter) - example config commented properly --- diff --git a/doc/examples/kea4/shared-network.json b/doc/examples/kea4/shared-network.json index 5566547489..cdcc84415e 100644 --- a/doc/examples/kea4/shared-network.json +++ b/doc/examples/kea4/shared-network.json @@ -1,38 +1,84 @@ - +// This is an example configuration file for DHCPv4 server in Kea. +// It demonstrates an advanced feature called shared network. Typically, for +// each physical link there is one IPv4 subnet that the server is expected +// to manage. However, in some cases there is a need to configure more subnets +// in the same physical location. The most common use case is an existing +// subnet that grew past its original assumptions and ran out of addresses, +// so the sysadmin needs to add another subnet on top of existing one. { "Dhcp4": { + + // As with any other configuration, you need to tell Kea the interface + // names, so it would listen to incoming traffic. "interfaces-config": { "interfaces": [ "eth0" ] }, + // You also need to tell where to store lease information. + // memfile is the backend that is easiest to set up. "lease-database": { "type": "memfile", "lfc-interval": 3600 }, + // Here the shared networks definition starts. shared-networks can + // contain a list of shared networks. There are many parameters + // that can be specfied here, so this example may be overwhelming + // at first, but the only mandatory parameter for each shared + // network is name. It must be unique. Typically, each shared + // subnet also needs to have at least two subnets to be functional, + // but if you really want to, you can define a degraded shared + // network that has 1 or even 0 subnets. This may come in handy + // when migrating between regular subnets and shared networks + // or when debugging a problem. It is not recommended to use + // 1 subnet per shared network, as there is extra processing + // overhead for shared networks. "shared-networks": [ { + // Name of the shared network. It may be an arbitrary string + // and it must be unique among all shared networks. + "name": "frog", + + // You may specify interface name if the shared network is + // reachable directly from the server. "interface": "eth1", + + // You can specify many parameters that are allowed in subnet scope + // here. It's useful to put them here if they apply to all subnets + // in this shared network. It's likely that the most common + // parameter here will be option values defined with option-data. "match-client-id": false, - "name": "frog", "option-data": [ ], "rebind-timer": 150, + + // If all the traffic coming from that shared subnet is reachable + // via relay and that relay always use the same IP address, you + // can specify that relay address here. Since this example shows + // a shared network reachable directly, we put 0.0.0.0 here. + // It would be better to skip the relay scope altogether, but + // it was left here for demonstration purposes. "relay": { "ip-address": "0.0.0.0" }, + + // Timer values can be overridden here. "renew-timer": 100, "reservation-mode": "all", + + // This starts a list of subnets allowed in this shared network. + // In our example, there are two subnets. "subnet4": [ { - "4o6-interface": "", - "4o6-interface-id": "", - "4o6-subnet": "", "id": 1, "match-client-id": true, "next-server": "0.0.0.0", "option-data": [ ], "pools": [ ], "rebind-timer": 20, + + // You can override the value inherited from shared-network + // here if your relay uses different IP addresses for + // each subnet. "relay": { "ip-address": "0.0.0.0" }, @@ -42,18 +88,12 @@ "valid-lifetime": 30 }, { - "4o6-interface": "", - "4o6-interface-id": "", - "4o6-subnet": "", "id": 2, "match-client-id": true, "next-server": "0.0.0.0", "option-data": [ ], "pools": [ ], "rebind-timer": 20, - "relay": { - "ip-address": "0.0.0.0" - }, "renew-timer": 10, "reservation-mode": "all", "subnet": "192.0.2.0/24", @@ -63,6 +103,10 @@ "valid-lifetime": 200 } ], // end of shared-networks + // It is likely that in your network you'll have a mix or regular, + // "plain" subnets and shared networks. It is perfectly valid to mix + // them in the same config file. + // // This is regular subnet. It's not part of any shared-network. "subnet4": [ { @@ -72,6 +116,6 @@ "id": 3 } ] - + } // end of Dhcp4 } diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 0d98b0db31..db0f919890 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -1002,7 +1002,6 @@ shared_network_param: name | next_server | relay | reservation_mode - | echo_client_id | client_classes | valid_lifetime | unknown_map_entry diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index e64920ac0e..b2e0704ea2 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -72,7 +72,7 @@ public: /// /// @throw DhcpConfigError if parameters are missing or /// or having incorrect values. - void parse(SrvConfigPtr cfg, ConstElementPtr global) { + void parse(const SrvConfigPtr& cfg, const ConstElementPtr& global) { // Set whether v4 server is supposed to echo back client-id // (yes = RFC6842 compatible, no = backward compatibility) @@ -96,7 +96,7 @@ public: /// @throw BadValue if any pointer is missing /// @throw DhcpConfigError if there are duplicates (or other subnet defects) void - copySubnets4(const CfgSubnets4Ptr dest, const CfgSharedNetworks4Ptr from) { + copySubnets4(const CfgSubnets4Ptr& dest, const CfgSharedNetworks4Ptr& from) { if (!dest || !from) { isc_throw(BadValue, "Unable to copy subnets: at least one pointer is null"); @@ -136,7 +136,7 @@ public: /// @param global global Dhcp4 scope /// @throw DhcpConfigError in case of issues found void - sanityChecks(SrvConfigPtr cfg, ConstElementPtr global) { + sanityChecks(const SrvConfigPtr& cfg, const ConstElementPtr& global) { /// Shared network sanity checks const SharedNetwork4Collection* networks = cfg->getCfgSharedNetworks4()->getAll(); diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index b24a7fd0b3..7bfa776c98 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -611,17 +611,23 @@ public: /// @param t1 expected renew-timer value /// @param t2 expected rebind-timer value /// @param valid expected valid-lifetime value - void + /// @return the subnet that was examined + Subnet4Ptr checkSubnet(const Subnet4Collection& col, std::string subnet, uint32_t t1, uint32_t t2, uint32_t valid) { const auto& index = col.get(); auto subnet_it = index.find(subnet); - ASSERT_NE(subnet_it, index.cend()); + if (subnet_it == index.cend()) { + ADD_FAILURE() << "Unable to find expected subnet " << subnet; + return (Subnet4Ptr()); + } Subnet4Ptr s = *subnet_it; EXPECT_EQ(t1, s->getT1()); EXPECT_EQ(t2, s->getT2()); EXPECT_EQ(valid, s->getValid()); + + return (s); } /// @brief This utility method attempts to configure using specified @@ -5209,13 +5215,34 @@ TEST_F(Dhcp4ParserTest, sharedNetworks3subnets) { // - shared network to subnet // Also, it tests that more than one shared network can be defined. TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { + + // We need to fake the interfaces present, because we want to test + // interface names inheritance. However, there are sanity checks + // on subnet level that would refuse the value if the interface + // is not present. + IfaceMgrTestConfig iface_config(true); + + // This config is structured in a way that the first shared + // subnet have many parameters defined. The first subnet + // should inherit them. The second subnet overrides all + // values and those values should be used, not those from + // shared network scope. string config = "{\n" - "\"renew-timer\": 1, \n" + "\"renew-timer\": 1, \n" // global values here "\"rebind-timer\": 2, \n" "\"valid-lifetime\": 4, \n" "\"shared-networks\": [ {\n" - " \"name\": \"foo\"\n," + " \"name\": \"foo\"\n," // shared network values here + " \"interface\": \"eth0\",\n" + " \"match-client-id\": false,\n" + " \"next-server\": \"1.2.3.4\",\n" + " \"relay\": {\n" + " \"ip-address\": \"5.6.7.8\"\n" + " },\n" + " \"reservation-mode\": \"out-of-pool\",\n" " \"renew-timer\": 10,\n" + " \"rebind-timer\": 20,\n" + " \"valid-lifetime\": 40,\n" " \"subnet4\": [\n" " { \n" " \"subnet\": \"192.0.1.0/24\",\n" @@ -5224,10 +5251,17 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { " { \n" " \"subnet\": \"192.0.2.0/24\",\n" " \"pools\": [ { \"pool\": \"192.0.2.1-192.0.2.10\" } ],\n" - " \"renew-timer\": 100\n" + " \"renew-timer\": 100,\n" + " \"rebind-timer\": 200,\n" + " \"valid-lifetime\": 400,\n" + " \"match-client-id\": true,\n" + " \"next-server\": \"11.22.33.44\",\n" + " \"relay\": {\n" + " \"ip-address\": \"55.66.77.88\"\n" + " },\n" + " \"reservation-mode\": \"disabled\"\n" " }\n" " ]\n" - " },\n" "{ // second shared-network starts here\n" " \"name\": \"bar\",\n" @@ -5265,13 +5299,28 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { // derived from shared-network level. Other parameters a derived // from global scope to shared-network level and later again to // subnet4 level. - checkSubnet(*subs, "192.0.1.0/24", 10, 2, 4); + Subnet4Ptr s = checkSubnet(*subs, "192.0.1.0/24", 10, 20, 40); + ASSERT_TRUE(s); + + // These are values derived from shared network scope: + EXPECT_EQ("eth0", s->getIface()); + EXPECT_EQ(false, s->getMatchClientId()); + EXPECT_EQ(IOAddress("1.2.3.4"), s->getSiaddr()); + EXPECT_EQ(IOAddress("5.6.7.8"), s->getRelayInfo().addr_); + EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode()); // For the second subnet, the renew-timer should be 100, because it // was specified explicitly. Other parameters a derived // from global scope to shared-network level and later again to // subnet4 level. - checkSubnet(*subs, "192.0.2.0/24", 100, 2, 4); + s = checkSubnet(*subs, "192.0.2.0/24", 100, 200, 400); + + // These are values derived from shared network scope: + EXPECT_EQ("eth0", s->getIface()); + EXPECT_EQ(true, s->getMatchClientId()); + EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr()); + EXPECT_EQ(IOAddress("55.66.77.88"), s->getRelayInfo().addr_); + EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode()); // Ok, now check the second shared subnet. net = nets->at(1); @@ -5282,9 +5331,13 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDerive) { EXPECT_EQ(1, subs->size()); // This subnet should derive its renew-timer from global scope. - checkSubnet(*subs, "192.0.3.0/24", 1, 2, 4); - + // All other parameters should have default values. + s = checkSubnet(*subs, "192.0.3.0/24", 1, 2, 4); + EXPECT_EQ("", s->getIface()); + EXPECT_EQ(true, s->getMatchClientId()); + EXPECT_EQ(IOAddress("0.0.0.0"), s->getSiaddr()); + EXPECT_EQ(IOAddress("0.0.0.0"), s->getRelayInfo().addr_); + EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode()); } - } diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index cdf3870e6c..6402f26b09 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -982,6 +982,7 @@ shared_network_params: shared_network_param shared_network_param: name | subnet6_list | interface + | interface_id | renew_timer | rebind_timer | option_data_list diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 9482a11945..98b0735e0a 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -322,18 +322,24 @@ public: /// @param t2 expected rebind-timer value /// @param preferred expected preferred-lifetime value /// @param valid expected valid-lifetime value - void + /// @return the subnet that was examined + Subnet6Ptr checkSubnet(const Subnet6Collection& col, std::string subnet, uint32_t t1, uint32_t t2, uint32_t pref, uint32_t valid) { const auto& index = col.get(); auto subnet_it = index.find(subnet); - ASSERT_NE(subnet_it, index.cend()); + if (subnet_it == index.cend()) { + ADD_FAILURE() << "Unable to find expected subnet " << subnet; + return (Subnet6Ptr()); + } Subnet6Ptr s = *subnet_it; EXPECT_EQ(t1, s->getT1()); EXPECT_EQ(t2, s->getT2()); EXPECT_EQ(pref, s->getPreferred()); EXPECT_EQ(valid, s->getValid()); + + return (s); } /// @brief Returns an interface configuration used by the most of the @@ -863,7 +869,7 @@ TEST_F(Dhcp6ParserTest, emptySubnet) { ConstElementPtr status; EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json)); - + // returned value should be 0 (success) checkResult(status, 0); @@ -5558,6 +5564,21 @@ TEST_F(Dhcp6ParserTest, sharedNetworks3subnets) { // - shared network to subnet // Also, it tests that more than one shared network can be defined. TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { + + // We need to fake the interfaces present, because we want to test + // interface names inheritance. However, there are sanity checks + // on subnet level that would refuse the value if the interface + // is not present. + IfaceMgrTestConfig iface_config(true); + + // Build some expected interface-id values. + const string text1 = "oneone"; + const string text2 = "twotwo"; + OptionBuffer buffer1 = OptionBuffer(text1.begin(), text1.end()); + OptionBuffer buffer2 = OptionBuffer(text2.begin(), text2.end()); + Option iface_id1(Option::V6, D6O_INTERFACE_ID, buffer1); + Option iface_id2(Option::V6, D6O_INTERFACE_ID, buffer2); + string config = "{\n" "\"renew-timer\": 1, \n" "\"rebind-timer\": 2, \n" @@ -5566,6 +5587,121 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { "\"shared-networks\": [ {\n" " \"name\": \"foo\"\n," " \"renew-timer\": 10,\n" + " \"rebind-timer\": 20, \n" + " \"preferred-lifetime\": 30,\n" + " \"valid-lifetime\": 40, \n" + " \"interface-id\": \"oneone\",\n" + " \"relay\": {\n" + " \"ip-address\": \"1111::1\"\n" + " },\n" + " \"rapid-commit\": true,\n" + " \"reservation-mode\": \"disabled\",\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," + " \"rebind-timer\": 200, \n" + " \"preferred-lifetime\": 300,\n" + " \"relay\": {\n" + " \"ip-address\": \"2222::2\"\n" + " },\n" + " \"valid-lifetime\": 400, \n" + " \"interface-id\": \"twotwo\",\n" + " \"rapid-commit\": false,\n" + " \"reservation-mode\": \"out-of-pool\"\n" + " }\n" + " ]\n" + " },\n" + "{ // second shared-network starts here\n" + " \"name\": \"bar\",\n" + " \"subnet6\": [\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(); + + // Two shared networks are expeced. + ASSERT_TRUE(cfg_net); + const SharedNetwork6Collection* nets = cfg_net->getAll(); + ASSERT_TRUE(nets); + ASSERT_EQ(2, nets->size()); + + // Let's check the first one. + SharedNetwork6Ptr net = nets->at(0); + ASSERT_TRUE(net); + + const Subnet6Collection * subs = net->getAllSubnets(); + ASSERT_TRUE(subs); + EXPECT_EQ(2, subs->size()); + + // For the first subnet, the renew-timer should be 10, because it was + // derived from shared-network level. Other parameters a derived + // from global scope to shared-network level and later again to + // subnet6 level. + Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 10, 20, 30, 40); + ASSERT_TRUE(s); + ASSERT_TRUE(s->getInterfaceId()); + EXPECT_TRUE(iface_id1.equals(s->getInterfaceId())); + EXPECT_EQ(IOAddress("1111::1"), s->getRelayInfo().addr_); + EXPECT_EQ(true, s->getRapidCommit()); + EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode()); + + // For the second subnet, the renew-timer should be 100, because it + // was specified explicitly. Other parameters a derived + // from global scope to shared-network level and later again to + // subnet6 level. + s = checkSubnet(*subs, "2001:db2::/48", 100, 200, 300, 400); + ASSERT_TRUE(s->getInterfaceId()); + EXPECT_TRUE(iface_id2.equals(s->getInterfaceId())); + EXPECT_EQ(IOAddress("2222::2"), s->getRelayInfo().addr_); + EXPECT_EQ(false, s->getRapidCommit()); + EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode()); + + // Ok, now check the second shared subnet. + net = nets->at(1); + ASSERT_TRUE(net); + + subs = net->getAllSubnets(); + ASSERT_TRUE(subs); + EXPECT_EQ(1, subs->size()); + + // This subnet should derive its renew-timer from global scope. + s = checkSubnet(*subs, "2001:db3::/48", 1, 2, 3, 4); + EXPECT_FALSE(s->getInterfaceId()); + EXPECT_EQ(IOAddress("::"), s->getRelayInfo().addr_); + EXPECT_EQ(false, s->getRapidCommit()); + EXPECT_EQ(Network::HR_ALL, s->getHostReservationMode()); +} + +// Since it is not allowed to define both interface-id and interface +// for the same subnet, we need dedicated test that will check +// interface separately. +TEST_F(Dhcp6ParserTest, sharedNetworksDeriveInterfaces) { + + // We need to fake the interfaces present, because we want to test + // interface names inheritance. However, there are sanity checks + // on subnet level that would refuse the value if the interface + // is not present. + IfaceMgrTestConfig iface_config(true); + + string config = "{\n" + "\"shared-networks\": [ {\n" + " \"name\": \"foo\"\n," + " \"interface\": \"eth0\",\n" " \"subnet6\": [\n" " { \n" " \"subnet\": \"2001:db1::/48\",\n" @@ -5574,7 +5710,7 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { " { \n" " \"subnet\": \"2001:db2::/48\",\n" " \"pools\": [ { \"pool\": \"2001:db2::/64\" } ],\n" - " \"renew-timer\": 100\n" + " \"interface\": \"eth0\"\n" " }\n" " ]\n" " },\n" @@ -5613,13 +5749,16 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { // derived from shared-network level. Other parameters a derived // from global scope to shared-network level and later again to // subnet6 level. - checkSubnet(*subs, "2001:db1::/48", 10, 2, 3, 4); + Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 900, 1800, 3600, 7200); + ASSERT_TRUE(s); + EXPECT_EQ("eth0", s->getIface()); // For the second subnet, the renew-timer should be 100, because it // was specified explicitly. Other parameters a derived // from global scope to shared-network level and later again to // subnet6 level. - checkSubnet(*subs, "2001:db2::/48", 100, 2, 3, 4); + checkSubnet(*subs, "2001:db2::/48", 900, 1800, 3600, 7200); + EXPECT_EQ("eth0", s->getIface()); // Ok, now check the second shared subnet. net = nets->at(1); @@ -5630,7 +5769,8 @@ TEST_F(Dhcp6ParserTest, sharedNetworksDerive) { EXPECT_EQ(1, subs->size()); // This subnet should derive its renew-timer from global scope. - checkSubnet(*subs, "2001:db3::/48", 1, 2, 3, 4); + s = checkSubnet(*subs, "2001:db3::/48", 900, 1800, 3600, 7200); + EXPECT_EQ("", s->getIface()); } }; diff --git a/src/lib/dhcpsrv/parsers/simple_parser4.cc b/src/lib/dhcpsrv/parsers/simple_parser4.cc index 3aee76a446..21a2bcbcae 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser4.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser4.cc @@ -7,6 +7,7 @@ #include #include #include +#include using namespace isc::data; @@ -66,6 +67,12 @@ const SimpleDefaults SimpleParser4::GLOBAL4_DEFAULTS = { }; /// @brief This table defines default values for each IPv4 subnet. +/// +/// Note: When updating this array, please also update SHARED_SUBNET4_DEFAULTS +/// below. In most cases, those two should be kept in sync, except cases +/// where a parameter can be derived from shared-networks, but is not +/// defined on global level. Currently there are two such parameters: +/// interface and reservation-mode const SimpleDefaults SimpleParser4::SUBNET4_DEFAULTS = { { "id", Element::integer, "0" }, // 0 means autogenerate { "interface", Element::string, "" }, @@ -76,24 +83,51 @@ const SimpleDefaults SimpleParser4::SUBNET4_DEFAULTS = { { "4o6-subnet", Element::string, "" }, }; +/// @brief This table defines default values for each IPv4 subnet that is +/// part of a shared network +/// +/// This is mostly the same as @ref SUBNET4_DEFAULTS, except two parameters +/// that can be derived from shared-network, but cannot from global scope. +/// Those are: interface and reservation-mode. +const SimpleDefaults SimpleParser4::SHARED_SUBNET4_DEFAULTS = { + { "id", Element::integer, "0" }, // 0 means autogenerate + { "client-class", Element::string, "" }, + { "4o6-interface", Element::string, "" }, + { "4o6-interface-id", Element::string, "" }, + { "4o6-subnet", Element::string, "" }, +}; + +/// @brief This table defines default values for each IPv4 shared network. +const SimpleDefaults SimpleParser4::SHARED_NETWORK4_DEFAULTS = { + { "interface", Element::string, "" }, + { "reservation-mode", Element::string, "all" } +}; + /// @brief This table defines default values for interfaces for DHCPv4. const SimpleDefaults SimpleParser4::IFACE4_DEFAULTS = { { "re-detect", Element::boolean, "true" } }; -/// @brief List of parameters that can be inherited from the global to subnet4 scope. +/// @brief List of parameters that can be inherited to subnet4 scope. /// /// Some parameters may be defined on both global (directly in Dhcp4) and /// subnet (Dhcp4/subnet4/...) scope. If not defined in the subnet scope, /// the value is being inherited (derived) from the global scope. This /// array lists all of such parameters. -const ParamsList SimpleParser4::INHERIT_GLOBAL_TO_SUBNET4 = { - "renew-timer", - "rebind-timer", - "valid-lifetime", +/// +/// This list is also used for inheriting from global to shared networks +/// and from shared networks to subnets within it. +const ParamsList SimpleParser4::INHERIT_TO_SUBNET4 = { + "interface", "match-client-id", - "next-server" + "next-server", + "rebind-timer", + "relay", + "renew-timer", + "reservation-mode", + "valid-lifetime" }; + /// @} /// --------------------------------------------------------------------------- @@ -137,9 +171,12 @@ size_t SimpleParser4::setAllDefaults(isc::data::ElementPtr global) { ConstElementPtr shared = global->get("shared-networks"); if (shared) { BOOST_FOREACH(ElementPtr net, shared->listValue()) { + + cnt += setDefaults(net, SHARED_NETWORK4_DEFAULTS); + ConstElementPtr subs = net->get("subnet4"); if (subs) { - cnt += setListDefaults(subs, SUBNET4_DEFAULTS); + cnt += setListDefaults(subs, SHARED_SUBNET4_DEFAULTS); } } } @@ -155,7 +192,7 @@ size_t SimpleParser4::deriveParameters(isc::data::ElementPtr global) { if (subnets) { BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) { cnt += SimpleParser::deriveParams(global, single_subnet, - INHERIT_GLOBAL_TO_SUBNET4); + INHERIT_TO_SUBNET4); } } @@ -169,16 +206,17 @@ size_t SimpleParser4::deriveParameters(isc::data::ElementPtr global) { // if defined there. // Then try to inherit them from global. cnt += SimpleParser::deriveParams(global, net, - INHERIT_GLOBAL_TO_SUBNET4); + INHERIT_TO_SUBNET4); // Now we need to go thrugh all the subnets in this net. subnets = net->get("subnet4"); if (subnets) { BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) { cnt += SimpleParser::deriveParams(net, single_subnet, - INHERIT_GLOBAL_TO_SUBNET4); + INHERIT_TO_SUBNET4); } } + } } diff --git a/src/lib/dhcpsrv/parsers/simple_parser4.h b/src/lib/dhcpsrv/parsers/simple_parser4.h index 4e73e31204..c4663bf63d 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser4.h +++ b/src/lib/dhcpsrv/parsers/simple_parser4.h @@ -41,8 +41,10 @@ public: static const isc::data::SimpleDefaults OPTION4_DEFAULTS; static const isc::data::SimpleDefaults GLOBAL4_DEFAULTS; static const isc::data::SimpleDefaults SUBNET4_DEFAULTS; + static const isc::data::SimpleDefaults SHARED_SUBNET4_DEFAULTS; + static const isc::data::SimpleDefaults SHARED_NETWORK4_DEFAULTS; static const isc::data::SimpleDefaults IFACE4_DEFAULTS; - static const isc::data::ParamsList INHERIT_GLOBAL_TO_SUBNET4; + static const isc::data::ParamsList INHERIT_TO_SUBNET4; }; }; diff --git a/src/lib/dhcpsrv/parsers/simple_parser6.cc b/src/lib/dhcpsrv/parsers/simple_parser6.cc index d8acd87d8c..a041c55b97 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser6.cc +++ b/src/lib/dhcpsrv/parsers/simple_parser6.cc @@ -73,6 +73,21 @@ const SimpleDefaults SimpleParser6::SUBNET6_DEFAULTS = { { "interface-id", Element::string, "" }, }; +/// @brief This table defines default values for each IPv6 subnet. +const SimpleDefaults SimpleParser6::SHARED_SUBNET6_DEFAULTS = { + { "id", Element::integer, "0" }, // 0 means autogenerate + { "client-class", Element::string, "" } +}; + +/// @brief This table defines default values for each IPv6 shared network. +const SimpleDefaults SimpleParser6::SHARED_NETWORK6_DEFAULTS = { + { "interface", Element::string, "" }, + { "interface-id", Element::string, "" }, + { "reservation-mode", Element::string, "all" }, + { "rapid-commit", Element::boolean, "false" } // rapid-commit disabled by default +}; + + /// @brief This table defines default values for interfaces for DHCPv6. const SimpleDefaults SimpleParser6::IFACE6_DEFAULTS = { { "re-detect", Element::boolean, "true" } @@ -84,10 +99,18 @@ const SimpleDefaults SimpleParser6::IFACE6_DEFAULTS = { /// subnet (Dhcp6/subnet6/...) scope. If not defined in the subnet scope, /// the value is being inherited (derived) from the global scope. This /// array lists all of such parameters. -const ParamsList SimpleParser6::INHERIT_GLOBAL_TO_SUBNET6 = { - "renew-timer", - "rebind-timer", +/// +/// This list is also used for inheriting from global to shared networks +/// and from shared networks to subnets within it. +const ParamsList SimpleParser6::INHERIT_TO_SUBNET6 = { + "interface", + "interface-id", "preferred-lifetime", + "rapid-commit", + "rebind-timer", + "relay", + "renew-timer", + "reservation-mode", "valid-lifetime" }; /// @} @@ -135,9 +158,12 @@ size_t SimpleParser6::setAllDefaults(isc::data::ElementPtr global) { ConstElementPtr shared = global->get("shared-networks"); if (shared) { BOOST_FOREACH(ElementPtr net, shared->listValue()) { + + cnt += setDefaults(net, SHARED_NETWORK6_DEFAULTS); + ConstElementPtr subs = net->get("subnet6"); if (subs) { - cnt += setListDefaults(subs, SUBNET6_DEFAULTS); + cnt += setListDefaults(subs, SHARED_SUBNET6_DEFAULTS); } } } @@ -152,7 +178,7 @@ size_t SimpleParser6::deriveParameters(isc::data::ElementPtr global) { if (subnets) { BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) { cnt += SimpleParser::deriveParams(global, single_subnet, - INHERIT_GLOBAL_TO_SUBNET6); + INHERIT_TO_SUBNET6); } } @@ -166,14 +192,14 @@ size_t SimpleParser6::deriveParameters(isc::data::ElementPtr global) { // if defined there. // Then try to inherit them from global. cnt += SimpleParser::deriveParams(global, net, - INHERIT_GLOBAL_TO_SUBNET6); + INHERIT_TO_SUBNET6); // Now we need to go thrugh all the subnets in this net. subnets = net->get("subnet6"); if (subnets) { BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) { cnt += SimpleParser::deriveParams(net, single_subnet, - INHERIT_GLOBAL_TO_SUBNET6); + INHERIT_TO_SUBNET6); } } } diff --git a/src/lib/dhcpsrv/parsers/simple_parser6.h b/src/lib/dhcpsrv/parsers/simple_parser6.h index 755f0c2b86..252d713879 100644 --- a/src/lib/dhcpsrv/parsers/simple_parser6.h +++ b/src/lib/dhcpsrv/parsers/simple_parser6.h @@ -42,8 +42,10 @@ public: static const isc::data::SimpleDefaults OPTION6_DEFAULTS; static const isc::data::SimpleDefaults GLOBAL6_DEFAULTS; static const isc::data::SimpleDefaults SUBNET6_DEFAULTS; + static const isc::data::SimpleDefaults SHARED_SUBNET6_DEFAULTS; + static const isc::data::SimpleDefaults SHARED_NETWORK6_DEFAULTS; static const isc::data::SimpleDefaults IFACE6_DEFAULTS; - static const isc::data::ParamsList INHERIT_GLOBAL_TO_SUBNET6; + static const isc::data::ParamsList INHERIT_TO_SUBNET6; }; };