From 3f877a825ad0835128ab0b41f55d0ff945afbf1b Mon Sep 17 00:00:00 2001 From: Francis Dupont Date: Mon, 20 Nov 2017 00:27:46 +0100 Subject: [PATCH] [5425] Added basic support (alloc engine todo) --- doc/examples/kea4/advanced.json | 21 +++++++++++++ doc/examples/kea6/advanced.json | 23 +++++++++++++- doc/guide/dhcp4-srv.xml | 9 ++++++ doc/guide/dhcp6-srv.xml | 9 ++++++ src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 31 ++++++++++++++++++- src/lib/dhcpsrv/parsers/dhcp_parsers.h | 1 + src/lib/dhcpsrv/pool.cc | 8 +++++ src/lib/dhcpsrv/pool.h | 20 ++++++++++++ src/lib/dhcpsrv/subnet.cc | 14 +++++++++ .../dhcpsrv/tests/cfg_subnets4_unittest.cc | 4 ++- .../dhcpsrv/tests/cfg_subnets6_unittest.cc | 8 +++-- src/lib/dhcpsrv/tests/pool_unittest.cc | 30 +++++++++++++++++- 12 files changed, 172 insertions(+), 6 deletions(-) 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. -- 2.47.2