]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[897-add-infinite-valid-lifetime-for-bootp] Added BOOTP client class
authorFrancis Dupont <fdupont@isc.org>
Sun, 22 Sep 2019 22:24:31 +0000 (00:24 +0200)
committerFrancis Dupont <fdupont@isc.org>
Tue, 5 Nov 2019 10:24:45 +0000 (11:24 +0100)
doc/sphinx/arm/classify.rst
src/bin/dhcp4/dhcp4_srv.cc
src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/client_class_def.cc
src/lib/dhcpsrv/client_class_def.h
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc

index 31e1744c3b2b9f85e1da7a2477d0d0464e15bc18..184f15a744a2673d3732b123721b7cb3dd21a2a8 100644 (file)
@@ -152,6 +152,9 @@ server uses an appropriate pool or subnet to allocate IP addresses
 (and/or prefixes), based on the assigned client classes. The details can
 be found in :ref:`high-availability-library`.
 
+The BOOTP hook uses the BOOTP class: when an incoming BOOTP query is
+recognized it is put in this class and built BOOTP response too.
+
 Other examples are the ALL class, which all incoming packets belong to,
 and the KNOWN class, assigned when host reservations exist for a
 particular client. By convention, built-in classes' names begin with all
index 3edfd8231d5b848513ceb613732f86ea1cb7a958..01064d01feb9549e040d84633d59f816c5dba496 100644 (file)
@@ -2758,13 +2758,17 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request, AllocEngine::ClientContext4Ptr& cont
     // or even rebinding.
     assignLease(ex);
 
-    if (!ex.getResponse()) {
+    Pkt4Ptr response = ex.getResponse();
+    if (!response) {
         // The ack is empty so return it *now*!
         return (Pkt4Ptr());
+    } else if (request->inClass("BOOTP")) {
+        // Put BOOTP responses in the BOOTP class.
+        response->addClass("BOOTP");
     }
 
     // Adding any other options makes sense only when we got the lease.
-    if (!ex.getResponse()->getYiaddr().isV4Zero()) {
+    if (!response->getYiaddr().isV4Zero()) {
         // Assign reserved classes.
         ex.setReservedClientClasses();
         // Required classification
index d7a5551160a0dfcd68ea97d82658e36546ee04c1..040908c4fc8a681dffc586c5cddb4ceafa115f91 100644 (file)
@@ -3560,6 +3560,11 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr,
         valid_lft = ctx.subnet_->getValid().get(opt_lft->getValue());
     }
 
+    // BOOTP uses infinite valid lifetime.
+    if (ctx.query_->inClass("BOOTP")) {
+        valid_lft = Lease::INFINITY_LFT;
+    }
+
     time_t now = time(NULL);
 
     // @todo: remove this kludge?
@@ -3992,6 +3997,10 @@ AllocEngine::updateLease4Information(const Lease4Ptr& lease,
     } else {
         lease->valid_lft_ = ctx.subnet_->getValid();
     }
+    // BOOTP uses infinite valid lifetime.
+    if (ctx.query_->inClass("BOOTP")) {
+        lease->valid_lft_ = Lease::INFINITY_LFT;
+    }
     lease->fqdn_fwd_ = ctx.fwd_dns_update_;
     lease->fqdn_rev_ = ctx.rev_dns_update_;
     lease->hostname_ = ctx.hostname_;
index bb18d8c328584c5aa42163fee8ce23e77b095412..ebb692aeee5113ec9f14ba526ce5b8d0584b6d55 100644 (file)
@@ -345,7 +345,7 @@ builtinNames = {
     // In fact DROP is set from an expression as callouts can drop
     // directly the incoming packet. The expression must not depend on
     // KNOWN/UNKNOWN which are set far after the drop point.
-    "ALL", "KNOWN", "UNKNOWN"
+    "ALL", "KNOWN", "UNKNOWN", "BOOTP"
 };
 
 std::list<std::string>
index 88425d0a97b69aca149e47571fcaf7506e682532..2eb574386986119086e357d9ca65be54658126a0 100644 (file)
@@ -382,7 +382,7 @@ private:
 typedef boost::shared_ptr<ClientClassDictionary> ClientClassDictionaryPtr;
 
 /// @brief List of built-in client class names.
-/// i.e. ALL, KNOWN and UNKNOWN but not DROP.
+/// i.e. ALL, KNOWN, UNKNOWN and BOOTP but not DROP.
 extern std::list<std::string> builtinNames;
 
 /// @brief List of built-in client class prefixes
index ac5dea7da2abe9e2869a1943be500f778af150cf..b7f7423853ddba91d45b9043023cb402d5b006a4 100644 (file)
@@ -276,6 +276,49 @@ TEST_F(AllocEngine4Test, maxAlloc4) {
     detailCompareLease(lease, from_mgr);
 }
 
+// This test checks that simple allocation handles BOOTP queries.
+TEST_F(AllocEngine4Test, bootpAlloc4) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 0, false)));
+    ASSERT_TRUE(engine);
+
+    AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+                                    false, true, "somehost.example.com.", false);
+    subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+    // Make the query a BOOTP one.
+    ctx.query_->addClass("BOOTP");
+
+    Lease4Ptr lease = engine->allocateLease4(ctx);
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(ctx.old_lease_);
+
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // Check that is belongs to the right subnet and client.
+    EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+    EXPECT_TRUE(subnet_->inRange(lease->addr_));
+    EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, lease->addr_));
+    ASSERT_TRUE(lease->client_id_);
+    EXPECT_TRUE(*lease->client_id_ == *clientid_);
+    ASSERT_TRUE(lease->hwaddr_);
+    EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+
+    // Check the valid lifetime is infinite.
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease(lease, from_mgr);
+}
+
 // This test checks if the fake allocation (for DHCPDISCOVER) can succeed
 TEST_F(AllocEngine4Test, fakeAlloc4) {
     boost::scoped_ptr<AllocEngine> engine;
@@ -681,6 +724,64 @@ TEST_F(AllocEngine4Test, maxRenew4) {
     EXPECT_EQ(subnet_->getValid().getMax(), lease2->valid_lft_);
 }
 
+// This test checks simple renewal handles BOOTP queries.
+TEST_F(AllocEngine4Test, bootpRenew4) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 0, false)));
+    ASSERT_TRUE(engine);
+
+    AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+                                    false, true, "somehost.example.com.", false);
+    subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+    // Make the query a BOOTP one.
+    ctx.query_->addClass("BOOTP");
+
+    Lease4Ptr lease = engine->allocateLease4(ctx);
+
+    // Check that we got a lease.
+    ASSERT_TRUE(lease);
+
+    // Check that is belongs to the right subnet and client.
+    EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+    EXPECT_TRUE(subnet_->inRange(lease->addr_));
+    EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, lease->addr_));
+    ASSERT_TRUE(lease->client_id_);
+    EXPECT_TRUE(*lease->client_id_ == *clientid_);
+    ASSERT_TRUE(lease->hwaddr_);
+    EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+
+    // Check the valid lifetime is infinite.
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(ctx.old_lease_);
+
+    // Do it again, this should amount to the renew of an existing lease
+    Lease4Ptr lease2 = engine->allocateLease4(ctx);
+
+    // Check that we got a lease.
+    ASSERT_TRUE(lease2);
+
+    // Check that is belongs to the right subnet and client.
+    EXPECT_EQ(lease2->subnet_id_, subnet_->getID());
+    EXPECT_TRUE(subnet_->inRange(lease2->addr_));
+    EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, lease2->addr_));
+    ASSERT_TRUE(lease2->client_id_);
+    EXPECT_TRUE(*lease2->client_id_ == *clientid_);
+    ASSERT_TRUE(lease2->hwaddr_);
+    EXPECT_TRUE(*lease2->hwaddr_ == *hwaddr_);
+
+    // Lease already existed, so old_lease should be set.
+    EXPECT_TRUE(ctx.old_lease_);
+
+    // Check the renewed valid lifetime has the max value.
+    EXPECT_EQ(infinity_lft, lease2->valid_lft_);
+}
+
 // This test verifies that the allocator picks addresses that belong to the
 // pool
 TEST_F(AllocEngine4Test, IterativeAllocator) {