]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5425] Checkpoint: still a few new tests to add
authorFrancis Dupont <fdupont@isc.org>
Mon, 20 Nov 2017 19:59:17 +0000 (20:59 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 20 Nov 2017 19:59:17 +0000 (20:59 +0100)
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc

index 66329452a23cb1f3f214a30dd216b6b8f1c7e532..d0f3600d04971f6f8198a6a0beca46d35b51830e 100644 (file)
@@ -358,6 +358,32 @@ TEST_F(AllocEngine4Test, IterativeAllocator_class) {
     }
 }
 
+// This test verifies that the allocator picks addresses that belong to the
+// pool using unknown clients
+TEST_F(AllocEngine4Test, IterativeAllocator_unknown) {
+    boost::scoped_ptr<NakedAllocEngine::Allocator>
+        alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_V4));
+
+    // Restrict pool_ to known clients. Add a second pool for unknown clients.
+    pool_->setKnownClients(Pool::SERVE_KNOWN);
+    Pool4Ptr pool(new Pool4(IOAddress("192.0.2.200"),
+                            IOAddress("192.0.2.209")));
+    pool->setKnownClients(Pool::SERVE_UNKNOWN);
+    subnet_->addPool(pool);
+
+    // Clients are unknown
+    known_client_ = false;
+
+    for (int i = 0; i < 1000; ++i) {
+        IOAddress candidate = alloc->pickAddress(subnet_, cc_,
+                                                 known_client_, clientid_,
+                                                 IOAddress("0.0.0.0"));
+        EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate));
+        EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_, known_client_));
+        EXPECT_FALSE(subnet_->inPool(Lease::TYPE_V4, candidate, cc_, !known_client_));
+    }
+}
+
 // This test verifies that the iterative allocator really walks over all addresses
 // in all pools in specified subnet. It also must not pick the same address twice
 // unless it runs out of pool space and must start over.
@@ -717,8 +743,8 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkClassification) {
 
 // This test verifies that the server can offer an address from a
 // different subnet than orginally selected, when the address pool in
-// the first subnet requires another class.
-TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolClassification) {
+// the first subnet requires host reservations.
+TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolKnown) {
 
     // Try to offer address from subnet1. There is one address available
     // so it should be offerred.
@@ -731,11 +757,11 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolClassification) {
     EXPECT_TRUE(subnet1_->inPool(Lease::TYPE_V4, lease->addr_));
 
     // Apply restrictions on the pool1. This should be only assigned
-    // to clients belonging to cable-modem class.
-    pool1_->allowClientClass("cable-modem");
+    // to clients which have a reservation.
+    pool1_->setKnownClients(Pool::SERVE_KNOWN);
 
     // The allocation engine should determine that the pool1 is not
-    // available for the client not belonging to the cable-modem class.
+    // available for the client without a reservation.
     // Instead, it should offer an address from subnet2 that belongs
     // to the same shared network.
     ctx.subnet_ = subnet1_;
@@ -743,9 +769,14 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolClassification) {
     ASSERT_TRUE(lease);
     EXPECT_TRUE(subnet2_->inPool(Lease::TYPE_V4, lease->addr_));
 
-    // Assign cable-modem class and try again. This time, we should
+    // Add a host reservation and try again. This time, we should
     // offer an address from the pool1.
-    ctx.query_->addClass(ClientClass("cable-modem"));
+    HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+                          Host::IDENT_HWADDR, subnet1_->getID(),
+                          SubnetID(0), IOAddress::IPV4_ZERO_ADDRESS(), "foo"));
+    CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+    CfgMgr::instance().commit();
+    AllocEngine::findReservation(ctx);
 
     ctx.subnet_ = subnet1_;
     lease = engine_.allocateLease4(ctx);
@@ -1004,6 +1035,75 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkPoolClassification) {
     EXPECT_TRUE(subnet2_->inPool(Lease::TYPE_V4, lease->addr_));
 }
 
+// This test verifies that the server can assign an address from a
+// different subnet than orginally selected, when the address pool in
+// the first subnet requires host reservations.
+TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkPoolKnown) {
+    // Try to offer address from subnet1. There is one address available
+    // so it should be offerred.
+    AllocEngine::ClientContext4
+        ctx(subnet1_, ClientIdPtr(), hwaddr_, IOAddress::IPV4_ZERO_ADDRESS(),
+            false, false, "host.example.com.", false);
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+    Lease4Ptr lease = engine_.allocateLease4(ctx);
+    ASSERT_TRUE(lease);
+    EXPECT_TRUE(subnet1_->inPool(Lease::TYPE_V4, lease->addr_));
+
+    // Remove the lease so as we can start over.
+    LeaseMgrFactory::instance().deleteLease(lease->addr_);
+
+    // Apply restrictions on the pool1. This should be only assigned
+    // to clients which have a reservation.
+    pool1_->setKnownClients(Pool::SERVE_KNOWN);
+
+    // The allocation engine should determine that the pool1 is not
+    // available for the client without a reservation.
+    // Instead, it should assign an address from subnet2 that belongs
+    // to the same shared network.
+    ctx.subnet_ = subnet1_;
+    lease = engine_.allocateLease4(ctx);
+    ASSERT_TRUE(lease);
+    EXPECT_TRUE(subnet2_->inPool(Lease::TYPE_V4, lease->addr_));
+
+    // Remove the lease so as we can start over.
+    LeaseMgrFactory::instance().deleteLease(lease->addr_);
+
+    // Add a host reservation and try again. This time, we should
+    // offer an address from the pool1.
+    HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(),
+                          Host::IDENT_HWADDR, subnet1_->getID(),
+                          SubnetID(0), IOAddress::IPV4_ZERO_ADDRESS(), "foo"));
+    CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+    CfgMgr::instance().commit();
+    AllocEngine::findReservation(ctx);
+
+    ctx.subnet_ = subnet1_;
+    lease = engine_.allocateLease4(ctx);
+    ASSERT_TRUE(lease);
+    EXPECT_TRUE(subnet1_->inPool(Lease::TYPE_V4, lease->addr_));
+
+    // Let's now remove the client host reservation and try
+    // to renew the address. The engine should determine that the
+    // client doesn't have access to the pool1 anymore and
+    // assign an address from unrestricted pool.
+#if 0
+    CfgMgr::instance().getStagingCfg()->getCfgHosts()->del4(SubnetID(0),
+                                                            Host::IDENT_HWADDR,
+                                                            &hwaddr_->hwaddr_[0],
+                                                            hwaddr_->hwaddr_.size());
+    CfgMgr::instance().commit();
+    AllocEngine::findReservation(ctx);
+#else
+    // del4 is not always implemented
+    ctx.hosts_.clear();
+#endif
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+    ctx.subnet_ = subnet1_;
+    lease = engine_.allocateLease4(ctx);
+    ASSERT_TRUE(lease);
+    EXPECT_TRUE(subnet2_->inPool(Lease::TYPE_V4, lease->addr_));
+}
+
 // Test that reservations within shared network take precedence over the
 // existing leases regardless in which subnet belonging to a shared network
 // reservations belong (DHCPREQUEST case).
index 09dd38f7cf97a51930f40ebd10daae919f848b34..2b833ec8da4a24adb59bd73c3d5146add4132ffe 100644 (file)
@@ -219,6 +219,31 @@ TEST_F(AllocEngine6Test, IterativeAllocator_class) {
     }
 }
 
+// This test verifies that the allocator picks addresses that belong to the
+// pool not requiring reservations
+TEST_F(AllocEngine6Test, IterativeAllocator_unknown) {
+    boost::scoped_ptr<NakedAllocEngine::Allocator>
+        alloc(new NakedAllocEngine::IterativeAllocator(Lease::TYPE_NA));
+
+    // Restrict pool_ to known clients. Add a second pool for unknown clients.
+    pool_->setKnownClients(Pool::SERVE_KNOWN);
+    Pool6Ptr pool(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
+                            IOAddress("2001:db8:1::109")));
+    pool->setKnownClients(Pool::SERVE_UNKNOWN);
+    subnet_->addPool(pool);
+
+    // Clients are unknown
+    known_client_ = false;
+
+    for (int i = 0; i < 1000; ++i) {
+        IOAddress candidate = alloc->pickAddress(subnet_, cc_, known_client_,
+                                                 duid_, IOAddress("::"));
+        EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate));
+        EXPECT_TRUE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_, known_client_));
+        EXPECT_FALSE(subnet_->inPool(Lease::TYPE_NA, candidate, cc_, !known_client_));
+    }
+}
+
 TEST_F(AllocEngine6Test, IterativeAllocatorAddrStep) {
     NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
 
@@ -389,6 +414,66 @@ TEST_F(AllocEngine6Test, IterativeAllocatorAddrStepOutClass) {
                                 IOAddress("::")).toText());
 }
 
+TEST_F(AllocEngine6Test, IterativeAllocatorAddrStepKnown) {
+    NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
+
+    subnet_->delPools(Lease::TYPE_NA); // Get rid of default pool
+
+    Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::1"),
+                             IOAddress("2001:db8:1::5")));
+    Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::100"),
+                             IOAddress("2001:db8:1::100")));
+    Pool6Ptr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1::105"),
+                             IOAddress("2001:db8:1::106")));
+    // The pool1 serves everybody, pool2 known clients, pool3 unknown clients.
+    // Set pool1 and pool3 but not pool2 in foo class
+    pool1->setKnownClients(Pool::SERVE_BOTH);
+    pool2->setKnownClients(Pool::SERVE_KNOWN);
+    pool3->setKnownClients(Pool::SERVE_UNKNOWN);
+    subnet_->addPool(pool1);
+    subnet_->addPool(pool2);
+    subnet_->addPool(pool3);
+
+    // Clients have no reservation
+    known_client_ = false;
+
+    // Let's check the first pool (5 addresses here)
+    EXPECT_EQ("2001:db8:1::1",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::2",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::3",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::4",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::5",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+
+    // The second pool is skipped
+
+    // This is the third and last pool, with 2 addresses in it
+    EXPECT_EQ("2001:db8:1::105",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::106",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+
+    // We iterated over all addresses and reached to the end of the last pool.
+    // Let's wrap around and start from the beginning
+    EXPECT_EQ("2001:db8:1::1",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:1::2",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+}
+
 TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStep) {
     NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
 
@@ -691,6 +776,109 @@ TEST_F(AllocEngine6Test, IterativeAllocatorPrefixStepOutClass) {
                                 IOAddress("::")).toText());
 }
 
+TEST_F(AllocEngine6Test, IterativeAllocatorPrefixKnown) {
+    NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_PD);
+
+    subnet_.reset(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
+
+    Pool6Ptr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 56, 60));
+    Pool6Ptr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 48));
+    Pool6Ptr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 56, 64));
+    // Set pool2 in foo
+    pool1->setKnownClients(Pool::SERVE_BOTH);
+    pool2->setKnownClients(Pool::SERVE_UNKNOWN);
+    pool3->setKnownClients(Pool::SERVE_KNOWN);
+    subnet_->addPool(pool1);
+    subnet_->addPool(pool2);
+    subnet_->addPool(pool3);
+
+    // Clients have reservations
+    known_client_ = true;
+
+    // We have a 2001:db8::/48 subnet that has 3 pools defined in it:
+    // 2001:db8::/56 split into /60 prefixes (16 leases) (or 2001:db8:0:X0::)
+    // 2001:db8:1::/48 split into a single /48 prefix (just 1 lease)
+    // 2001:db8:2::/56 split into /64 prefixes (256 leases) (or 2001:db8:2:XX::)
+
+    // First pool check (Let's check over all 16 leases)
+    EXPECT_EQ("2001:db8::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:10::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:20::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:30::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:40::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:50::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:60::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:70::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:80::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:90::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:a0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:b0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:c0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:d0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:e0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:f0::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+
+    // The second pool is skipped
+
+    // Third pool (256 leases, let's check first and last explicitly and the
+    // rest over in a pool
+    EXPECT_EQ("2001:db8:2::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    for (int i = 1; i < 255; i++) {
+        stringstream exp;
+        exp << "2001:db8:2:" << hex << i << dec << "::";
+        EXPECT_EQ(exp.str(),
+                  alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                    IOAddress("::")).toText());
+
+    }
+    EXPECT_EQ("2001:db8:2:ff::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+
+    // Ok, we've iterated over all prefixes in all pools. We now wrap around.
+    // We're looping over now (iterating over first pool again)
+    EXPECT_EQ("2001:db8::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+    EXPECT_EQ("2001:db8:0:10::",
+              alloc.pickAddress(subnet_, cc_, known_client_, duid_,
+                                IOAddress("::")).toText());
+}
+
 // This test verifies that the iterative allocator can step over addresses
 TEST_F(AllocEngine6Test, IterativeAllocatorAddressIncrease) {
     NakedAllocEngine::NakedIterativeAllocator alloc(Lease::TYPE_NA);
@@ -2647,6 +2835,62 @@ TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkPoolClassification) {
     EXPECT_EQ("2001:db8:1::1", lease->addr_.toText());
 }
 
+// This test verifies that the server can offer an address from a
+// different subnet than orginally selected, when the address pool in
+// the first subnet requires a reservation.
+TEST_F(SharedNetworkAlloc6Test, solicitSharedNetworkPoolKnown) {
+    // Try to offer address from subnet1. There is an address available so
+    // it should be offerred.
+    Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
+    AllocEngine::ClientContext6 ctx(subnet1_, duid_, false, false, "", true,
+                                    query);
+    ctx.currentIA().iaid_ = iaid_;
+
+    Lease6Ptr lease;
+    ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx)));
+    ASSERT_TRUE(lease);
+    ASSERT_TRUE(subnet1_->inRange(lease->addr_));
+
+    // Apply restrictions on the pool1. This should be only assigned
+    // to clients with have a reservation.
+    pool1_->setKnownClients(Pool::SERVE_KNOWN);
+
+    // The allocation engine should determine that the pool1 is not
+    // available for the client without a reservation.
+    // Instead, it should offer an address from subnet2 that belongs
+    // to the same shared network.
+    AllocEngine::ClientContext6 ctx2(subnet1_, duid_, false, false, "", true,
+                                    query);
+    ctx2.currentIA().iaid_ = iaid_;
+    ctx2.query_ = query;
+    ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx2)));
+    ASSERT_TRUE(lease);
+    ASSERT_TRUE(subnet2_->inRange(lease->addr_));
+
+    AllocEngine::ClientContext6 ctx3(subnet1_, duid_, false, false, "", true,
+                                    query);
+    ctx3.currentIA().iaid_ = iaid_;
+    ctx3.query_ = query;
+
+    AllocEngine::ClientContext6 ctx4(subnet1_, duid_, false, false, "", true,
+                                    query);
+    ctx4.currentIA().iaid_ = iaid_;
+    ctx4.query_ = query;
+
+    // Add a host reservation and try again. This time, we should
+    // offer an address from the pool1_.
+    HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+                          Host::IDENT_DUID, SubnetID(0), subnet1_->getID(),
+                          IOAddress::IPV4_ZERO_ADDRESS(), "foo"));
+    CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+    CfgMgr::instance().commit();
+    AllocEngine::findReservation(ctx4);
+
+    ASSERT_NO_THROW(lease = expectOneLease(engine_.allocateLeases6(ctx4)));
+    ASSERT_TRUE(lease);
+    EXPECT_EQ("2001:db8:1::1", lease->addr_.toText());
+}
+
 // This test verifies that the client is offerred a reserved address
 // even if this address belongs to another subnet within the same
 // shared network.