alloc_engine_unittest.cc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <asiolink/io_address.h>
  16. #include <dhcp/duid.h>
  17. #include <dhcp/dhcp4.h>
  18. #include <dhcpsrv/alloc_engine.h>
  19. #include <dhcpsrv/cfgmgr.h>
  20. #include <dhcpsrv/lease_mgr.h>
  21. #include <dhcpsrv/lease_mgr_factory.h>
  22. #include <dhcpsrv/memfile_lease_mgr.h>
  23. #include <dhcpsrv/tests/test_utils.h>
  24. #include <boost/shared_ptr.hpp>
  25. #include <boost/scoped_ptr.hpp>
  26. #include <gtest/gtest.h>
  27. #include <iostream>
  28. #include <sstream>
  29. #include <set>
  30. #include <time.h>
  31. using namespace std;
  32. using namespace isc;
  33. using namespace isc::asiolink;
  34. using namespace isc::dhcp;
  35. using namespace isc::dhcp::test;
  36. namespace {
  37. /// @brief Allocation engine with some internal methods exposed
  38. class NakedAllocEngine : public AllocEngine {
  39. public:
  40. /// @brief the sole constructor
  41. /// @param engine_type specifies engine type (e.g. iterative)
  42. /// @param attempts number of lease selection attempts before giving up
  43. NakedAllocEngine(AllocEngine::AllocType engine_type, unsigned int attempts)
  44. :AllocEngine(engine_type, attempts) {
  45. }
  46. // Expose internal classes for testing purposes
  47. using AllocEngine::Allocator;
  48. using AllocEngine::IterativeAllocator;
  49. };
  50. /// @brief Used in Allocation Engine tests for IPv6
  51. class AllocEngine6Test : public ::testing::Test {
  52. public:
  53. /// @brief Default constructor
  54. ///
  55. /// Sets duid_, iaid_, subnet_, pool_ fields to example values used
  56. /// in many tests, initializes cfg_mgr configuration and creates
  57. /// lease database.
  58. AllocEngine6Test() {
  59. duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
  60. iaid_ = 42;
  61. // instantiate cfg_mgr
  62. CfgMgr& cfg_mgr = CfgMgr::instance();
  63. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
  64. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::10"),
  65. IOAddress("2001:db8:1::20")));
  66. subnet_->addPool(pool_);
  67. cfg_mgr.addSubnet6(subnet_);
  68. factory_.create("type=memfile");
  69. }
  70. /// @brief checks if Lease6 matches expected configuration
  71. ///
  72. /// @param lease lease to be checked
  73. void checkLease6(const Lease6Ptr& lease) {
  74. // that is belongs to the right subnet
  75. EXPECT_EQ(lease->subnet_id_, subnet_->getID());
  76. EXPECT_TRUE(subnet_->inRange(lease->addr_));
  77. EXPECT_TRUE(subnet_->inPool(lease->addr_));
  78. // that it have proper parameters
  79. EXPECT_EQ(iaid_, lease->iaid_);
  80. EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
  81. EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
  82. EXPECT_EQ(subnet_->getT1(), lease->t1_);
  83. EXPECT_EQ(subnet_->getT2(), lease->t2_);
  84. EXPECT_EQ(0, lease->prefixlen_); // this is IA_NA, not IA_PD
  85. EXPECT_TRUE(false == lease->fqdn_fwd_);
  86. EXPECT_TRUE(false == lease->fqdn_rev_);
  87. EXPECT_TRUE(*lease->duid_ == *duid_);
  88. // @todo: check cltt
  89. }
  90. ~AllocEngine6Test() {
  91. factory_.destroy();
  92. }
  93. DuidPtr duid_; ///< client-identifier (value used in tests)
  94. uint32_t iaid_; ///< IA identifier (value used in tests)
  95. Subnet6Ptr subnet_; ///< subnet6 (used in tests)
  96. Pool6Ptr pool_; ///< pool belonging to subnet_
  97. LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
  98. };
  99. /// @brief Used in Allocation Engine tests for IPv4
  100. class AllocEngine4Test : public ::testing::Test {
  101. public:
  102. /// @brief Default constructor
  103. ///
  104. /// Sets clientid_, hwaddr_, subnet_, pool_ fields to example values
  105. /// used in many tests, initializes cfg_mgr configuration and creates
  106. /// lease database.
  107. AllocEngine4Test() {
  108. clientid_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x44)));
  109. static uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
  110. // Let's use odd hardware type to check if there is no Ethernet
  111. // hardcoded anywhere.
  112. hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
  113. // instantiate cfg_mgr
  114. CfgMgr& cfg_mgr = CfgMgr::instance();
  115. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
  116. pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"),
  117. IOAddress("192.0.2.109")));
  118. subnet_->addPool(pool_);
  119. cfg_mgr.addSubnet4(subnet_);
  120. factory_.create("type=memfile");
  121. }
  122. /// @brief checks if Lease4 matches expected configuration
  123. ///
  124. /// @param lease lease to be checked
  125. void checkLease4(const Lease4Ptr& lease) {
  126. // that is belongs to the right subnet
  127. EXPECT_EQ(lease->subnet_id_, subnet_->getID());
  128. EXPECT_TRUE(subnet_->inRange(lease->addr_));
  129. EXPECT_TRUE(subnet_->inPool(lease->addr_));
  130. // that it have proper parameters
  131. EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
  132. EXPECT_EQ(subnet_->getT1(), lease->t1_);
  133. EXPECT_EQ(subnet_->getT2(), lease->t2_);
  134. EXPECT_TRUE(false == lease->fqdn_fwd_);
  135. EXPECT_TRUE(false == lease->fqdn_rev_);
  136. EXPECT_TRUE(*lease->client_id_ == *clientid_);
  137. EXPECT_TRUE(lease->hwaddr_ == hwaddr_->hwaddr_);
  138. // @todo: check cltt
  139. }
  140. ~AllocEngine4Test() {
  141. factory_.destroy();
  142. }
  143. ClientIdPtr clientid_; ///< client-identifier (value used in tests)
  144. HWAddrPtr hwaddr_; ///< hardware address (value used in tests)
  145. Subnet4Ptr subnet_; ///< subnet4 (used in tests)
  146. Pool4Ptr pool_; ///< pool belonging to subnet_
  147. LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
  148. };
  149. // This test checks if the Allocation Engine can be instantiated and that it
  150. // parses parameters string properly.
  151. TEST_F(AllocEngine6Test, constructor) {
  152. boost::scoped_ptr<AllocEngine> x;
  153. // Hashed and random allocators are not supported yet
  154. ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_HASHED, 5)), NotImplemented);
  155. ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_RANDOM, 5)), NotImplemented);
  156. ASSERT_NO_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  157. }
  158. // This test checks if the simple allocation can succeed
  159. TEST_F(AllocEngine6Test, simpleAlloc6) {
  160. boost::scoped_ptr<AllocEngine> engine;
  161. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  162. ASSERT_TRUE(engine);
  163. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  164. false);
  165. // check that we got a lease
  166. ASSERT_TRUE(lease);
  167. // do all checks on the lease
  168. checkLease6(lease);
  169. // Check that the lease is indeed in LeaseMgr
  170. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  171. ASSERT_TRUE(from_mgr);
  172. // Now check that the lease in LeaseMgr has the same parameters
  173. detailCompareLease(lease, from_mgr);
  174. }
  175. // This test checks if the fake allocation (for SOLICIT) can succeed
  176. TEST_F(AllocEngine6Test, fakeAlloc6) {
  177. boost::scoped_ptr<AllocEngine> engine;
  178. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  179. ASSERT_TRUE(engine);
  180. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  181. true);
  182. // check that we got a lease
  183. ASSERT_TRUE(lease);
  184. // do all checks on the lease
  185. checkLease6(lease);
  186. // Check that the lease is NOT in LeaseMgr
  187. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  188. ASSERT_FALSE(from_mgr);
  189. }
  190. // This test checks if the allocation with a hint that is valid (in range,
  191. // in pool and free) can succeed
  192. TEST_F(AllocEngine6Test, allocWithValidHint6) {
  193. boost::scoped_ptr<AllocEngine> engine;
  194. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  195. ASSERT_TRUE(engine);
  196. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
  197. IOAddress("2001:db8:1::15"),
  198. false);
  199. // check that we got a lease
  200. ASSERT_TRUE(lease);
  201. // we should get what we asked for
  202. EXPECT_EQ(lease->addr_.toText(), "2001:db8:1::15");
  203. // do all checks on the lease
  204. checkLease6(lease);
  205. // Check that the lease is indeed in LeaseMgr
  206. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  207. ASSERT_TRUE(from_mgr);
  208. // Now check that the lease in LeaseMgr has the same parameters
  209. detailCompareLease(lease, from_mgr);
  210. }
  211. // This test checks if the allocation with a hint that is in range,
  212. // in pool, but is currently used) can succeed
  213. TEST_F(AllocEngine6Test, allocWithUsedHint6) {
  214. boost::scoped_ptr<AllocEngine> engine;
  215. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  216. ASSERT_TRUE(engine);
  217. // let's create a lease and put it in the LeaseMgr
  218. DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
  219. time_t now = time(NULL);
  220. Lease6Ptr used(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1f"),
  221. duid2, 1, 2, 3, 4, now, subnet_->getID()));
  222. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  223. // another client comes in and request an address that is in pool, but
  224. // unfortunately it is used already. The same address must not be allocated
  225. // twice.
  226. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
  227. IOAddress("2001:db8:1::1f"),
  228. false);
  229. // check that we got a lease
  230. ASSERT_TRUE(lease);
  231. // allocated address must be different
  232. EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
  233. // we should NOT get what we asked for, because it is used already
  234. EXPECT_TRUE(lease->addr_.toText() != "2001:db8:1::1f");
  235. // do all checks on the lease
  236. checkLease6(lease);
  237. // Check that the lease is indeed in LeaseMgr
  238. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  239. ASSERT_TRUE(from_mgr);
  240. // Now check that the lease in LeaseMgr has the same parameters
  241. detailCompareLease(lease, from_mgr);
  242. }
  243. // This test checks if the allocation with a hint that is out the blue
  244. // can succeed. The invalid hint should be ignored completely.
  245. TEST_F(AllocEngine6Test, allocBogusHint6) {
  246. boost::scoped_ptr<AllocEngine> engine;
  247. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  248. ASSERT_TRUE(engine);
  249. // Client would like to get a 3000::abc lease, which does not belong to any
  250. // supported lease. Allocation engine should ignore it and carry on
  251. // with the normal allocation
  252. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
  253. IOAddress("3000::abc"),
  254. false);
  255. // check that we got a lease
  256. ASSERT_TRUE(lease);
  257. // we should NOT get what we asked for, because it is used already
  258. EXPECT_TRUE(lease->addr_.toText() != "3000::abc");
  259. // do all checks on the lease
  260. checkLease6(lease);
  261. // Check that the lease is indeed in LeaseMgr
  262. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  263. ASSERT_TRUE(from_mgr);
  264. // Now check that the lease in LeaseMgr has the same parameters
  265. detailCompareLease(lease, from_mgr);
  266. }
  267. // This test verifies that the allocator picks addresses that belong to the
  268. // pool
  269. TEST_F(AllocEngine6Test, IterativeAllocator) {
  270. boost::scoped_ptr<NakedAllocEngine::Allocator>
  271. alloc(new NakedAllocEngine::IterativeAllocator());
  272. for (int i = 0; i < 1000; ++i) {
  273. IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
  274. EXPECT_TRUE(subnet_->inPool(candidate));
  275. }
  276. }
  277. // This test verifies that the iterative allocator really walks over all addresses
  278. // in all pools in specified subnet. It also must not pick the same address twice
  279. // unless it runs out of pool space and must start over.
  280. TEST_F(AllocEngine6Test, IterativeAllocator_manyPools6) {
  281. NakedAllocEngine::IterativeAllocator* alloc = new NakedAllocEngine::IterativeAllocator();
  282. // let's start from 2, as there is 2001:db8:1::10 - 2001:db8:1::20 pool already.
  283. for (int i = 2; i < 10; ++i) {
  284. stringstream min, max;
  285. min << "2001:db8:1::" << hex << i*16 + 1;
  286. max << "2001:db8:1::" << hex << i*16 + 9;
  287. Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, IOAddress(min.str()),
  288. IOAddress(max.str())));
  289. // cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
  290. subnet_->addPool(pool);
  291. }
  292. int total = 17 + 8*9; // first pool (::10 - ::20) has 17 addresses in it,
  293. // there are 8 extra pools with 9 addresses in each.
  294. // Let's keep picked addresses here and check their uniqueness.
  295. std::set<IOAddress> generated_addrs;
  296. int cnt = 0;
  297. while (++cnt) {
  298. IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
  299. EXPECT_TRUE(subnet_->inPool(candidate));
  300. // One way to easily verify that the iterative allocator really works is
  301. // to uncomment the following line and observe its output that it
  302. // covers all defined subnets.
  303. // cout << candidate.toText() << endl;
  304. if (generated_addrs.find(candidate) == generated_addrs.end()) {
  305. // we haven't had this
  306. generated_addrs.insert(candidate);
  307. } else {
  308. // we have seen this address before. That should mean that we
  309. // iterated over all addresses.
  310. if (generated_addrs.size() == total) {
  311. // we have exactly the number of address in all pools
  312. break;
  313. }
  314. ADD_FAILURE() << "Too many or not enough unique addresses generated.";
  315. break;
  316. }
  317. if ( cnt>total ) {
  318. ADD_FAILURE() << "Too many unique addresses generated.";
  319. break;
  320. }
  321. }
  322. delete alloc;
  323. }
  324. // This test checks if really small pools are working
  325. TEST_F(AllocEngine6Test, smallPool6) {
  326. boost::scoped_ptr<AllocEngine> engine;
  327. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  328. ASSERT_TRUE(engine);
  329. IOAddress addr("2001:db8:1::ad");
  330. CfgMgr& cfg_mgr = CfgMgr::instance();
  331. cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
  332. // Create configuration similar to other tests, but with a single address pool
  333. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
  334. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
  335. subnet_->addPool(pool_);
  336. cfg_mgr.addSubnet6(subnet_);
  337. Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  338. false);
  339. // Check that we got that single lease
  340. ASSERT_TRUE(lease);
  341. EXPECT_EQ("2001:db8:1::ad", lease->addr_.toText());
  342. // do all checks on the lease
  343. checkLease6(lease);
  344. // Check that the lease is indeed in LeaseMgr
  345. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
  346. ASSERT_TRUE(from_mgr);
  347. // Now check that the lease in LeaseMgr has the same parameters
  348. detailCompareLease(lease, from_mgr);
  349. }
  350. // This test checks if all addresses in a pool are currently used, the attempt
  351. // to find out a new lease fails.
  352. TEST_F(AllocEngine6Test, outOfAddresses6) {
  353. boost::scoped_ptr<AllocEngine> engine;
  354. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  355. ASSERT_TRUE(engine);
  356. IOAddress addr("2001:db8:1::ad");
  357. CfgMgr& cfg_mgr = CfgMgr::instance();
  358. cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
  359. // Create configuration similar to other tests, but with a single address pool
  360. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
  361. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
  362. subnet_->addPool(pool_);
  363. cfg_mgr.addSubnet6(subnet_);
  364. // Just a different duid
  365. DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
  366. const uint32_t other_iaid = 3568;
  367. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, other_duid, other_iaid,
  368. 501, 502, 503, 504, subnet_->getID(), 0));
  369. lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago
  370. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  371. // There is just a single address in the pool and allocated it to someone
  372. // else, so the allocation should fail
  373. Lease6Ptr lease2 = engine->allocateAddress6(subnet_, duid_, iaid_,
  374. IOAddress("::"), false);
  375. EXPECT_FALSE(lease2);
  376. }
  377. // This test checks if an expired lease can be reused in SOLICIT (fake allocation)
  378. TEST_F(AllocEngine6Test, solicitReuseExpiredLease6) {
  379. boost::scoped_ptr<AllocEngine> engine;
  380. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  381. ASSERT_TRUE(engine);
  382. IOAddress addr("2001:db8:1::ad");
  383. CfgMgr& cfg_mgr = CfgMgr::instance();
  384. cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
  385. // Create configuration similar to other tests, but with a single address pool
  386. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
  387. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
  388. subnet_->addPool(pool_);
  389. cfg_mgr.addSubnet6(subnet_);
  390. // Just a different duid
  391. DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
  392. const uint32_t other_iaid = 3568;
  393. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, other_duid, other_iaid,
  394. 501, 502, 503, 504, subnet_->getID(), 0));
  395. lease->cltt_ = time(NULL) - 500; // Allocated 500 seconds ago
  396. lease->valid_lft_ = 495; // Lease was valid for 495 seconds
  397. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  398. // Make sure that we really created expired lease
  399. ASSERT_TRUE(lease->expired());
  400. // CASE 1: Asking for any address
  401. lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  402. true);
  403. // Check that we got that single lease
  404. ASSERT_TRUE(lease);
  405. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  406. // Do all checks on the lease (if subnet-id, preferred/valid times are ok etc.)
  407. checkLease6(lease);
  408. // CASE 2: Asking specifically for this address
  409. lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress(addr.toText()),
  410. true);
  411. // Check that we got that single lease
  412. ASSERT_TRUE(lease);
  413. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  414. }
  415. // This test checks if an expired lease can be reused in REQUEST (actual allocation)
  416. TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
  417. boost::scoped_ptr<AllocEngine> engine;
  418. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  419. ASSERT_TRUE(engine);
  420. IOAddress addr("2001:db8:1::ad");
  421. CfgMgr& cfg_mgr = CfgMgr::instance();
  422. cfg_mgr.deleteSubnets6(); // Get rid of the default test configuration
  423. // Create configuration similar to other tests, but with a single address pool
  424. subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
  425. pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, addr, addr)); // just a single address
  426. subnet_->addPool(pool_);
  427. cfg_mgr.addSubnet6(subnet_);
  428. // Let's create an expired lease
  429. DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
  430. const uint32_t other_iaid = 3568;
  431. const SubnetID other_subnetid = 999;
  432. Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, other_duid, other_iaid,
  433. 501, 502, 503, 504, other_subnetid, 0));
  434. lease->cltt_ = time(NULL) - 500; // Allocated 500 seconds ago
  435. lease->valid_lft_ = 495; // Lease was valid for 495 seconds
  436. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  437. // A client comes along, asking specifically for this address
  438. lease = engine->allocateAddress6(subnet_, duid_, iaid_,
  439. IOAddress(addr.toText()), false);
  440. // Check that he got that single lease
  441. ASSERT_TRUE(lease);
  442. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  443. // Check that the lease is indeed updated in LeaseMgr
  444. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(addr);
  445. ASSERT_TRUE(from_mgr);
  446. // Now check that the lease in LeaseMgr has the same parameters
  447. detailCompareLease(lease, from_mgr);
  448. }
  449. // --- IPv4 ---
  450. // This test checks if the simple IPv4 allocation can succeed
  451. TEST_F(AllocEngine4Test, simpleAlloc4) {
  452. boost::scoped_ptr<AllocEngine> engine;
  453. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  454. ASSERT_TRUE(engine);
  455. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  456. IOAddress("0.0.0.0"), false);
  457. // Check that we got a lease
  458. ASSERT_TRUE(lease);
  459. // Do all checks on the lease
  460. checkLease4(lease);
  461. // Check that the lease is indeed in LeaseMgr
  462. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  463. ASSERT_TRUE(from_mgr);
  464. // Now check that the lease in LeaseMgr has the same parameters
  465. detailCompareLease(lease, from_mgr);
  466. }
  467. // This test checks if the fake allocation (for DISCOVER) can succeed
  468. TEST_F(AllocEngine4Test, fakeAlloc4) {
  469. boost::scoped_ptr<AllocEngine> engine;
  470. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  471. ASSERT_TRUE(engine);
  472. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  473. IOAddress("0.0.0.0"), true);
  474. // Check that we got a lease
  475. ASSERT_TRUE(lease);
  476. // Do all checks on the lease
  477. checkLease4(lease);
  478. // Check that the lease is NOT in LeaseMgr
  479. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  480. ASSERT_FALSE(from_mgr);
  481. }
  482. // This test checks if the allocation with a hint that is valid (in range,
  483. // in pool and free) can succeed
  484. TEST_F(AllocEngine4Test, allocWithValidHint4) {
  485. boost::scoped_ptr<AllocEngine> engine;
  486. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  487. ASSERT_TRUE(engine);
  488. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  489. IOAddress("192.0.2.105"),
  490. false);
  491. // Check that we got a lease
  492. ASSERT_TRUE(lease);
  493. // We should get what we asked for
  494. EXPECT_EQ(lease->addr_.toText(), "192.0.2.105");
  495. // Do all checks on the lease
  496. checkLease4(lease);
  497. // Check that the lease is indeed in LeaseMgr
  498. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  499. ASSERT_TRUE(from_mgr);
  500. // Now check that the lease in LeaseMgr has the same parameters
  501. detailCompareLease(lease, from_mgr);
  502. }
  503. // This test checks if the allocation with a hint that is in range,
  504. // in pool, but is currently used) can succeed
  505. TEST_F(AllocEngine4Test, allocWithUsedHint4) {
  506. boost::scoped_ptr<AllocEngine> engine;
  507. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  508. ASSERT_TRUE(engine);
  509. // Let's create a lease and put it in the LeaseMgr
  510. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  511. uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
  512. time_t now = time(NULL);
  513. Lease4Ptr used(new Lease4(IOAddress("192.0.2.106"), hwaddr2, sizeof(hwaddr2),
  514. clientid2, sizeof(clientid2), 1, 2, 3, now, subnet_->getID()));
  515. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  516. // Another client comes in and request an address that is in pool, but
  517. // unfortunately it is used already. The same address must not be allocated
  518. // twice.
  519. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  520. IOAddress("192.0.2.106"),
  521. false);
  522. // Check that we got a lease
  523. ASSERT_TRUE(lease);
  524. // Allocated address must be different
  525. EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
  526. // We should NOT get what we asked for, because it is used already
  527. EXPECT_TRUE(lease->addr_.toText() != "192.0.2.106");
  528. // Do all checks on the lease
  529. checkLease4(lease);
  530. // Check that the lease is indeed in LeaseMgr
  531. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  532. ASSERT_TRUE(from_mgr);
  533. // Now check that the lease in LeaseMgr has the same parameters
  534. detailCompareLease(lease, from_mgr);
  535. }
  536. // This test checks if the allocation with a hint that is out the blue
  537. // can succeed. The invalid hint should be ignored completely.
  538. TEST_F(AllocEngine4Test, allocBogusHint4) {
  539. boost::scoped_ptr<AllocEngine> engine;
  540. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  541. ASSERT_TRUE(engine);
  542. // Client would like to get a 3000::abc lease, which does not belong to any
  543. // supported lease. Allocation engine should ignore it and carry on
  544. // with the normal allocation
  545. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  546. IOAddress("10.1.1.1"),
  547. false);
  548. // Check that we got a lease
  549. ASSERT_TRUE(lease);
  550. // We should NOT get what we asked for, because it is used already
  551. EXPECT_TRUE(lease->addr_.toText() != "10.1.1.1");
  552. // Do all checks on the lease
  553. checkLease4(lease);
  554. // Check that the lease is indeed in LeaseMgr
  555. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  556. ASSERT_TRUE(from_mgr);
  557. // Now check that the lease in LeaseMgr has the same parameters
  558. detailCompareLease(lease, from_mgr);
  559. }
  560. // This test verifies that the allocator picks addresses that belong to the
  561. // pool
  562. TEST_F(AllocEngine4Test, IterativeAllocator) {
  563. boost::scoped_ptr<NakedAllocEngine::Allocator>
  564. alloc(new NakedAllocEngine::IterativeAllocator());
  565. for (int i = 0; i < 1000; ++i) {
  566. IOAddress candidate = alloc->pickAddress(subnet_, clientid_,
  567. IOAddress("0.0.0.0"));
  568. EXPECT_TRUE(subnet_->inPool(candidate));
  569. }
  570. }
  571. // This test verifies that the iterative allocator really walks over all addresses
  572. // in all pools in specified subnet. It also must not pick the same address twice
  573. // unless it runs out of pool space and must start over.
  574. TEST_F(AllocEngine4Test, IterativeAllocator_manyPools4) {
  575. NakedAllocEngine::IterativeAllocator* alloc = new NakedAllocEngine::IterativeAllocator();
  576. // Let's start from 2, as there is 2001:db8:1::10 - 2001:db8:1::20 pool already.
  577. for (int i = 2; i < 10; ++i) {
  578. stringstream min, max;
  579. min << "192.0.2." << i * 10 + 1;
  580. max << "192.0.2." << i * 10 + 9;
  581. Pool4Ptr pool(new Pool4(IOAddress(min.str()),
  582. IOAddress(max.str())));
  583. // cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
  584. subnet_->addPool(pool);
  585. }
  586. int total = 10 + 8 * 9; // first pool (.100 - .109) has 10 addresses in it,
  587. // there are 8 extra pools with 9 addresses in each.
  588. // Let's keep picked addresses here and check their uniqueness.
  589. std::set<IOAddress> generated_addrs;
  590. int cnt = 0;
  591. while (++cnt) {
  592. IOAddress candidate = alloc->pickAddress(subnet_, clientid_, IOAddress("0.0.0.0"));
  593. EXPECT_TRUE(subnet_->inPool(candidate));
  594. // One way to easily verify that the iterative allocator really works is
  595. // to uncomment the following line and observe its output that it
  596. // covers all defined subnets.
  597. // cout << candidate.toText() << endl;
  598. if (generated_addrs.find(candidate) == generated_addrs.end()) {
  599. // We haven't had this
  600. generated_addrs.insert(candidate);
  601. } else {
  602. // we have seen this address before. That should mean that we
  603. // iterated over all addresses.
  604. if (generated_addrs.size() == total) {
  605. // we have exactly the number of address in all pools
  606. break;
  607. }
  608. ADD_FAILURE() << "Too many or not enough unique addresses generated.";
  609. break;
  610. }
  611. if ( cnt>total ) {
  612. ADD_FAILURE() << "Too many unique addresses generated.";
  613. break;
  614. }
  615. }
  616. delete alloc;
  617. }
  618. // This test checks if really small pools are working
  619. TEST_F(AllocEngine4Test, smallPool4) {
  620. boost::scoped_ptr<AllocEngine> engine;
  621. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  622. ASSERT_TRUE(engine);
  623. IOAddress addr("192.0.2.17");
  624. CfgMgr& cfg_mgr = CfgMgr::instance();
  625. cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
  626. // Create configuration similar to other tests, but with a single address pool
  627. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
  628. pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
  629. subnet_->addPool(pool_);
  630. cfg_mgr.addSubnet4(subnet_);
  631. Lease4Ptr lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
  632. false);
  633. // Check that we got that single lease
  634. ASSERT_TRUE(lease);
  635. EXPECT_EQ("192.0.2.17", lease->addr_.toText());
  636. // Do all checks on the lease
  637. checkLease4(lease);
  638. // Check that the lease is indeed in LeaseMgr
  639. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  640. ASSERT_TRUE(from_mgr);
  641. // Now check that the lease in LeaseMgr has the same parameters
  642. detailCompareLease(lease, from_mgr);
  643. }
  644. // This test checks if all addresses in a pool are currently used, the attempt
  645. // to find out a new lease fails.
  646. TEST_F(AllocEngine4Test, outOfAddresses4) {
  647. boost::scoped_ptr<AllocEngine> engine;
  648. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  649. ASSERT_TRUE(engine);
  650. IOAddress addr("192.0.2.17");
  651. CfgMgr& cfg_mgr = CfgMgr::instance();
  652. cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
  653. // Create configuration similar to other tests, but with a single address pool
  654. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
  655. pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
  656. subnet_->addPool(pool_);
  657. cfg_mgr.addSubnet4(subnet_);
  658. // Just a different hw/client-id for the second client
  659. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  660. uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
  661. time_t now = time(NULL);
  662. Lease4Ptr lease(new Lease4(addr, hwaddr2, sizeof(hwaddr2), clientid2, sizeof(clientid2),
  663. 501, 502, 503, now, subnet_->getID()));
  664. lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago
  665. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  666. // There is just a single address in the pool and allocated it to someone
  667. // else, so the allocation should fail
  668. Lease4Ptr lease2 = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  669. IOAddress("0.0.0.0"), false);
  670. EXPECT_FALSE(lease2);
  671. }
  672. // This test checks if an expired lease can be reused in DISCOVER (fake allocation)
  673. TEST_F(AllocEngine4Test, discoverReuseExpiredLease4) {
  674. boost::scoped_ptr<AllocEngine> engine;
  675. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  676. ASSERT_TRUE(engine);
  677. IOAddress addr("192.0.2.15");
  678. CfgMgr& cfg_mgr = CfgMgr::instance();
  679. cfg_mgr.deleteSubnets4(); // Get rid of the default test configuration
  680. // Create configuration similar to other tests, but with a single address pool
  681. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
  682. pool_ = Pool4Ptr(new Pool4(addr, addr)); // just a single address
  683. subnet_->addPool(pool_);
  684. cfg_mgr.addSubnet4(subnet_);
  685. // Just a different hw/client-id for the second client
  686. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  687. uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
  688. time_t now = time(NULL) - 500; // Allocated 500 seconds ago
  689. Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2, sizeof(hwaddr2),
  690. 495, 100, 200, now, subnet_->getID()));
  691. // Lease was assigned 500 seconds ago, but its valid lifetime is 495, so it
  692. // is expired already
  693. ASSERT_TRUE(lease->expired());
  694. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  695. // CASE 1: Asking for any address
  696. lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
  697. true);
  698. // Check that we got that single lease
  699. ASSERT_TRUE(lease);
  700. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  701. // Do all checks on the lease (if subnet-id, preferred/valid times are ok etc.)
  702. checkLease4(lease);
  703. // CASE 2: Asking specifically for this address
  704. lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_, IOAddress(addr.toText()),
  705. true);
  706. // Check that we got that single lease
  707. ASSERT_TRUE(lease);
  708. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  709. }
  710. // This test checks if an expired lease can be reused in REQUEST (actual allocation)
  711. TEST_F(AllocEngine4Test, requestReuseExpiredLease4) {
  712. boost::scoped_ptr<AllocEngine> engine;
  713. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  714. ASSERT_TRUE(engine);
  715. IOAddress addr("192.0.2.105");
  716. // Just a different hw/client-id for the second client
  717. uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  718. uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
  719. time_t now = time(NULL) - 500; // Allocated 500 seconds ago
  720. Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2, sizeof(hwaddr2),
  721. 495, 100, 200, now, subnet_->getID()));
  722. // lease was assigned 500 seconds ago, but its valid lifetime is 495, so it
  723. // is expired already
  724. ASSERT_TRUE(lease->expired());
  725. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  726. // A client comes along, asking specifically for this address
  727. lease = engine->allocateAddress4(subnet_, clientid_, hwaddr_,
  728. IOAddress(addr.toText()), false);
  729. // Check that he got that single lease
  730. ASSERT_TRUE(lease);
  731. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  732. // Check that the lease is indeed updated in LeaseMgr
  733. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  734. ASSERT_TRUE(from_mgr);
  735. // Now check that the lease in LeaseMgr has the same parameters
  736. detailCompareLease(lease, from_mgr);
  737. }
  738. // This test checks if a lease is really renewed when renewLease4 method is
  739. // called
  740. TEST_F(AllocEngine4Test, renewLease4) {
  741. boost::scoped_ptr<AllocEngine> engine;
  742. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  743. ASSERT_TRUE(engine);
  744. IOAddress addr("192.0.2.102");
  745. const uint32_t old_lifetime = 100;
  746. const uint32_t old_t1 = 50;
  747. const uint32_t old_t2 = 75;
  748. const time_t old_timestamp = time(NULL) - 45; // Allocated 45 seconds ago
  749. // Just a different hw/client-id for the second client
  750. const uint8_t hwaddr2[] = { 0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
  751. const uint8_t clientid2[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
  752. Lease4Ptr lease(new Lease4(addr, clientid2, sizeof(clientid2), hwaddr2,
  753. sizeof(hwaddr2), old_lifetime, old_t1, old_t2,
  754. old_timestamp, subnet_->getID()));
  755. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
  756. // Lease was assigned 45 seconds ago and is valid for 100 seconds. Let's
  757. // renew it.
  758. ASSERT_FALSE(lease->expired());
  759. lease = engine->renewLease4(subnet_, clientid_, hwaddr_, lease, false);
  760. // Check that he got that single lease
  761. ASSERT_TRUE(lease);
  762. EXPECT_EQ(addr.toText(), lease->addr_.toText());
  763. // Check that the lease matches subnet_, hwaddr_,clientid_ parameters
  764. checkLease4(lease);
  765. // Check that the lease is indeed updated in LeaseMgr
  766. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(addr);
  767. ASSERT_TRUE(from_mgr);
  768. // Now check that the lease in LeaseMgr has the same parameters
  769. detailCompareLease(lease, from_mgr);
  770. }
  771. }; // end of anonymous namespace