-
+// 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"
},
"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",
"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": [
{
"id": 3
}
]
-
+
} // end of Dhcp4
}
| next_server
| relay
| reservation_mode
- | echo_client_id
| client_classes
| valid_lifetime
| unknown_map_entry
///
/// @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)
/// @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");
/// @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();
/// @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<SubnetPrefixIndexTag>();
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
// - 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"
" { \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"
// 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);
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());
}
-
}
shared_network_param: name
| subnet6_list
| interface
+ | interface_id
| renew_timer
| rebind_timer
| option_data_list
/// @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<SubnetPrefixIndexTag>();
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
ConstElementPtr status;
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
-
+
// returned value should be 0 (success)
checkResult(status, 0);
// - 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"
"\"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"
" { \n"
" \"subnet\": \"2001:db2::/48\",\n"
" \"pools\": [ { \"pool\": \"2001:db2::/64\" } ],\n"
- " \"renew-timer\": 100\n"
+ " \"interface\": \"eth0\"\n"
" }\n"
" ]\n"
" },\n"
// 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);
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());
}
};
#include <dhcpsrv/parsers/simple_parser4.h>
#include <cc/data.h>
#include <boost/foreach.hpp>
+#include <iostream>
using namespace isc::data;
};
/// @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, "" },
{ "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"
};
+
/// @}
/// ---------------------------------------------------------------------------
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);
}
}
}
if (subnets) {
BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
cnt += SimpleParser::deriveParams(global, single_subnet,
- INHERIT_GLOBAL_TO_SUBNET4);
+ INHERIT_TO_SUBNET4);
}
}
// 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);
}
}
+
}
}
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;
};
};
{ "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" }
/// 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"
};
/// @}
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);
}
}
}
if (subnets) {
BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
cnt += SimpleParser::deriveParams(global, single_subnet,
- INHERIT_GLOBAL_TO_SUBNET6);
+ INHERIT_TO_SUBNET6);
}
}
// 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);
}
}
}
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;
};
};