diff --git a/doc/examples/kea4/advanced.json b/doc/examples/kea4/advanced.json
index 327047bcd2..34b062e269 100644
--- a/doc/examples/kea4/advanced.json
+++ b/doc/examples/kea4/advanced.json
@@ -137,6 +137,27 @@
"relay": {
"ip-address": "192.168.1.1"
}
+ },
+ {
+ // This subnet is divided in two pools for unknown and
+ // known (i.e. which have a reservation) clients.
+ "pools": [
+ {
+ "pool": "192.0.8.100 - 192.0.8.200",
+ "known-clients": "never"
+ },
+ {
+ "pool": "192.0.9.100 - 192.0.9.200",
+ "known-clients": "only"
+ }
+ ],
+ "subnet": "192.0.8.0/23",
+ "reservations": [
+ { "hw-address": "00:00:00:11:22:33" },
+ { "hw-address": "00:00:00:44:55:66" },
+ { "hw-address": "00:00:00:77:88:99" },
+ { "hw-address": "00:00:00:aa:bb:cc" }
+ ]
}
]
},
diff --git a/doc/examples/kea6/advanced.json b/doc/examples/kea6/advanced.json
index a8e67ee973..7a6a50a152 100644
--- a/doc/examples/kea6/advanced.json
+++ b/doc/examples/kea6/advanced.json
@@ -133,7 +133,28 @@
// and another is when there is a shared subnet scenario.
"relay": {
"ip-address": "3000::1"
- }
+ },
+ },
+ {
+ // This subnet is divided in two pools for unknown and
+ // known (i.e. which have a reservation) clients.
+ "pools": [
+ {
+ "pool": "2001:db8:8::/64",
+ "known-clients": "never"
+ },
+ {
+ "pool": "2001:db8:9::/64",
+ "known-clients": "only"
+ }
+ ],
+ "subnet": "2001:db8:8::/46",
+ "reservations": [
+ { "hw-address": "00:00:00:11:22:33" },
+ { "hw-address": "00:00:00:44:55:66" },
+ { "hw-address": "00:00:00:77:88:99" },
+ { "hw-address": "00:00:00:aa:bb:cc" }
+ ]
}
]
},
diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml
index bdd58cf015..34f2fd9e81 100644
--- a/doc/guide/dhcp4-srv.xml
+++ b/doc/guide/dhcp4-srv.xml
@@ -2090,6 +2090,15 @@ It is merely echoed by the server
at the pool level, see .
+
+ In a similar way a pool can be constrained to serve only known clients,
+ i.e. clients which have a reservation, using
+ "known-clients": "only", or only unknown clients
+ with "known-clients": "never". One can assign
+ addresses to registered clients without giving a different address per
+ reservations, for instance when there is not enough available addresses.
+
+
The process of doing classification is conducted in three steps. The first step
is to assess an incoming packet and assign it to zero or more classes. The
diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml
index a577843c37..1ac0cf5aac 100644
--- a/doc/guide/dhcp6-srv.xml
+++ b/doc/guide/dhcp6-srv.xml
@@ -1950,6 +1950,15 @@ should include options from the isc option space:
linkend="classification-pools"/>.
+
+ In a similar way a pool can be constrained to serve only known clients,
+ i.e. clients which have a reservation, using
+ "known-clients": "only", or only unknown clients
+ with "known-clients": "never". One can assign
+ prefixes to registered clients without giving a different prefix per
+ reservations, forinstance when there is not enough available prefixes.
+
+
The process of doing classification is conducted in three steps. The first step
is to assess an incoming packet and assign it to zero or more classes. The
diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc
index 4499cbe4aa..a384dbf135 100644
--- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc
+++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc
@@ -387,6 +387,19 @@ PoolParser::parse(PoolStoragePtr pools,
pool->allowClientClass(cclass);
}
}
+
+ // Known-clients.
+ ConstElementPtr known_clients = pool_structure->get("known-clients");
+ if (known_clients) {
+ string kc = known_clients->stringValue();
+ if (kc == "only") {
+ pool->setKnownClients(Pool::SERVE_KNOWN);
+ } else if (kc == "never") {
+ pool->setKnownClients(Pool::SERVE_UNKNOWN);
+ } else
+ isc_throw(DhcpConfigError, "invalid known-clients value: " << kc
+ << " (" << known_clients->getPosition() << ")");
+ }
}
//****************************** Pool4Parser *************************
@@ -861,6 +874,11 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
client_class_ = client_class;
}
+ ConstElementPtr known_clients = pd_pool_->get("known-clients");
+ if (known_clients) {
+ known_clients_ = known_clients;
+ }
+
// Check the pool parameters. It will throw an exception if any
// of the required parameters are invalid.
try {
@@ -884,7 +902,6 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
pool_->setContext(user_context_);
}
-
if (client_class_) {
string cclass = client_class_->stringValue();
if (!cclass.empty()) {
@@ -892,6 +909,18 @@ PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
}
}
+ if (known_clients_) {
+ string kc = known_clients_->stringValue();
+ if (kc == "only") {
+ pool_->setKnownClients(Pool::SERVE_KNOWN);
+ } else if (kc == "never") {
+ pool_->setKnownClients(Pool::SERVE_UNKNOWN);
+ } else
+ isc_throw(isc::dhcp::DhcpConfigError,
+ "invalid known-clients value: " << kc
+ << " (" << known_clients_->getPosition() << ")");
+ }
+
// Add the local pool to the external storage ptr.
pools->push_back(pool_);
}
diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h
index e195cd4bad..adabdb7732 100644
--- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h
+++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h
@@ -655,6 +655,7 @@ private:
isc::data::ConstElementPtr client_class_;
+ isc::data::ConstElementPtr known_clients_;
};
/// @brief Parser for a list of prefix delegation pools.
diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc
index 3e41426eac..da3258f2b9 100644
--- a/src/lib/dhcpsrv/pool.cc
+++ b/src/lib/dhcpsrv/pool.cc
@@ -19,6 +19,7 @@ Pool::Pool(Lease::Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:id_(getNextID()), first_(first), last_(last), type_(type),
capacity_(0), cfg_option_(new CfgOption()), white_list_(),
+ known_clients_(SERVE_BOTH),
last_allocated_(first), last_allocated_valid_(false) {
}
@@ -121,6 +122,13 @@ Pool::toElement() const {
map->set("client-class", Element::create(*cclasses.cbegin()));
}
+ // Set known-clients
+ KnownClients kc = getKnownClients();
+ if (kc != SERVE_BOTH) {
+ map->set("known-clients",
+ Element::create(kc == SERVE_KNOWN ? "only" : "never"));
+ }
+
return (map);
}
diff --git a/src/lib/dhcpsrv/pool.h b/src/lib/dhcpsrv/pool.h
index 5254ea5ca5..d74022ac33 100644
--- a/src/lib/dhcpsrv/pool.h
+++ b/src/lib/dhcpsrv/pool.h
@@ -28,6 +28,13 @@ namespace dhcp {
class Pool {
public:
+ /// @brief Value of known clients
+ typedef enum {
+ SERVE_BOTH = 0, ///< the pool serves both known and unknown clients
+ SERVE_KNOWN = 1, ///< the pool serves only known clients
+ SERVE_UNKNOWN = 2 ///< the pool never serves known clients
+ } KnownClients;
+
/// @note:
/// PoolType enum was removed. Please use Lease::Type instead
@@ -133,6 +140,16 @@ public:
return (white_list_);
}
+ /// @brief Returns the value of known clients
+ KnownClients getKnownClients() const {
+ return (known_clients_);
+ }
+
+ /// @brief Sets the value of known clients
+ void setKnownClients(KnownClients known_clients) {
+ known_clients_ = known_clients;
+ }
+
/// @brief returns the last address that was tried from this pool
///
/// @return address/prefix that was last tried from this pool
@@ -222,6 +239,9 @@ protected:
/// @ref Network::white_list_
ClientClasses white_list_;
+ /// @brief Value of known clients
+ KnownClients known_clients_;
+
/// @brief Pointer to the user context (may be NULL)
data::ConstElementPtr user_context_;
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
index a07a9c47c0..8585264aa9 100644
--- a/src/lib/dhcpsrv/subnet.cc
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -742,6 +742,13 @@ Subnet6::toElement() const {
} else if (!cclasses.empty()) {
pool_map->set("client-class", Element::create(*cclasses.cbegin()));
}
+ // Set known-clients
+ Pool::KnownClients kc = (*pool)->getKnownClients();
+ if (kc != Pool::SERVE_BOTH) {
+ pool_map->set("known-clients",
+ Element::create(kc == Pool::SERVE_KNOWN ?
+ "only" : "never"));
+ }
// Push on the pool list
pool_list->add(pool_map);
}
@@ -804,6 +811,13 @@ Subnet6::toElement() const {
} else if (!cclasses.empty()) {
pool_map->set("client-class", Element::create(*cclasses.cbegin()));
}
+ // Set known-clients
+ Pool::KnownClients kc = pdpool->getKnownClients();
+ if (kc != Pool::SERVE_BOTH) {
+ pool_map->set("known-clients",
+ Element::create(kc == Pool::SERVE_KNOWN ?
+ "only" : "never"));
+ }
// Push on the pool list
pdpool_list->add(pool_map);
}
diff --git a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
index 0e5e0c59ed..c97c7bee84 100644
--- a/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
@@ -813,6 +813,7 @@ TEST(CfgSubnets4Test, unparsePool) {
Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.1"), IOAddress("192.0.2.10")));
Pool4Ptr pool2(new Pool4(IOAddress("192.0.2.64"), 26));
pool2->allowClientClass("bar");
+ pool2->setKnownClients(Pool::SERVE_KNOWN);
subnet->addPool(pool1);
subnet->addPool(pool2);
@@ -843,7 +844,8 @@ TEST(CfgSubnets4Test, unparsePool) {
" },{\n"
" \"option-data\": [ ],\n"
" \"pool\": \"192.0.2.64/26\",\n"
- " \"client-class\": \"bar\"\n"
+ " \"client-class\": \"bar\",\n"
+ " \"known-clients\": \"only\"\n"
" }\n"
" ]\n"
"} ]\n";
diff --git a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
index df09f3301f..d12cada956 100644
--- a/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
+++ b/src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc
@@ -504,6 +504,7 @@ TEST(CfgSubnets6Test, unparsePool) {
IOAddress("2001:db8:1::199")));
Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
pool2->allowClientClass("bar");
+ pool2->setKnownClients(Pool::SERVE_UNKNOWN);
subnet->addPool(pool1);
subnet->addPool(pool2);
@@ -528,7 +529,8 @@ TEST(CfgSubnets6Test, unparsePool) {
" },{\n"
" \"pool\": \"2001:db8:1:1::/64\",\n"
" \"option-data\": [ ],\n"
- " \"client-class\": \"bar\"\n"
+ " \"client-class\": \"bar\",\n"
+ " \"known-clients\": \"never\"\n"
" }\n"
" ],\n"
" \"pd-pools\": [ ],\n"
@@ -550,6 +552,7 @@ TEST(CfgSubnets6Test, unparsePdPool) {
Pool6Ptr pdpool2(new Pool6(IOAddress("2001:db8:3::"), 48, 56,
IOAddress("2001:db8:3::"), 64));
pdpool2->allowClientClass("bar");
+ pdpool2->setKnownClients(Pool::SERVE_KNOWN);
subnet->addPool(pdpool1);
subnet->addPool(pdpool2);
@@ -581,7 +584,8 @@ TEST(CfgSubnets6Test, unparsePdPool) {
" \"excluded-prefix\": \"2001:db8:3::\",\n"
" \"excluded-prefix-len\": 64,\n"
" \"option-data\": [ ],\n"
- " \"client-class\": \"bar\"\n"
+ " \"client-class\": \"bar\",\n"
+ " \"known-clients\": \"only\"\n"
" }\n"
" ],\n"
" \"option-data\": [ ]\n"
diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc
index 5662f6a5ce..d720c2b023 100644
--- a/src/lib/dhcpsrv/tests/pool_unittest.cc
+++ b/src/lib/dhcpsrv/tests/pool_unittest.cc
@@ -268,6 +268,20 @@ TEST(Pool4Test, clientClasses) {
EXPECT_TRUE(pool->clientSupported(bar_class));
}
+// This test checks that handling for known-clients is valid.
+TEST(Pool4Test, knownClients) {
+ // Create a pool.
+ Pool4Ptr pool(new Pool4(IOAddress("192.0.2.0"),
+ IOAddress("192.0.2.255")));
+
+ // This pool serves everybody by default.
+ EXPECT_EQ(Pool::SERVE_BOTH, pool->getKnownClients());
+
+ // Set it to only known clients.
+ pool->setKnownClients(Pool::SERVE_KNOWN);
+ EXPECT_EQ(Pool::SERVE_KNOWN,pool->getKnownClients());
+}
+
// This test checks that handling for last allocated address/prefix is valid.
TEST(Pool4Test, lastAllocated) {
// Create a pool.
@@ -638,7 +652,7 @@ TEST(Pool6Test, clientClass) {
TEST(Pool6Test, clientClasses) {
// Create a pool.
Pool6 pool(Lease::TYPE_NA, IOAddress("2001:db8::1"),
- IOAddress("2001:db8::2"));
+ IOAddress("2001:db8::2"));
// This client does not belong to any class.
isc::dhcp::ClientClasses no_class;
@@ -672,6 +686,20 @@ TEST(Pool6Test, clientClasses) {
EXPECT_TRUE(pool.clientSupported(bar_class));
}
+// This test checks that handling for known-clients is valid.
+TEST(Pool6Test, knownClients) {
+ // Create a pool.
+ Pool6 pool(Lease::TYPE_NA, IOAddress("2001:db8::1"),
+ IOAddress("2001:db8::2"));
+
+ // This pool serves everybody by default.
+ EXPECT_EQ(Pool::SERVE_BOTH, pool.getKnownClients());
+
+ // Set it to only known clients.
+ pool.setKnownClients(Pool::SERVE_KNOWN);
+ EXPECT_EQ(Pool::SERVE_KNOWN,pool.getKnownClients());
+}
+
// This test checks that handling for last allocated address/prefix is valid.
TEST(Pool6Test, lastAllocated) {
// Create a pool.