alloc_engine_expiration_unittest.cc 94 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315
  1. // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <dhcp/duid.h>
  8. #include <dhcp/option_data_types.h>
  9. #include <dhcp_ddns/ncr_msg.h>
  10. #include <dhcpsrv/tests/alloc_engine_utils.h>
  11. #include <dhcpsrv/tests/test_utils.h>
  12. #include <hooks/hooks_manager.h>
  13. #include <stats/stats_mgr.h>
  14. #include <gtest/gtest.h>
  15. #include <boost/bind.hpp>
  16. #include <boost/function.hpp>
  17. #include <boost/static_assert.hpp>
  18. #include <iomanip>
  19. #include <sstream>
  20. #include <time.h>
  21. #include <unistd.h>
  22. #include <vector>
  23. using namespace std;
  24. using namespace isc;
  25. using namespace isc::asiolink;
  26. using namespace isc::dhcp;
  27. using namespace isc::dhcp::test;
  28. using namespace isc::dhcp_ddns;
  29. using namespace isc::hooks;
  30. using namespace isc::stats;
  31. namespace {
  32. /// @brief Number of leases to be initialized for each test.
  33. ///
  34. /// This value is expected by some of the tests to be multiple
  35. /// of 10.
  36. const unsigned int TEST_LEASES_NUM = 100;
  37. /// @brief Structure wrapping a lower limit within the collection
  38. /// of leases.
  39. ///
  40. /// We're using this structure rather than a size_t value directly
  41. /// to make API of the test fixture class more readable, i.e. the
  42. /// struct name indicates the purpose of the value being held.
  43. struct LowerBound {
  44. /// @brief Constructor.
  45. ///
  46. /// @param lower_bound Interger value wrapped by the structure.
  47. explicit LowerBound(const size_t lower_bound)
  48. : lower_bound_(lower_bound) { };
  49. /// @brief Operator returning the size_t value wrapped.
  50. operator size_t() const {
  51. return (lower_bound_);
  52. }
  53. /// @brief Value wrapped in the structure.
  54. size_t lower_bound_;
  55. };
  56. /// @brief Structure wrapping an upper limit within the collection
  57. /// of leases.
  58. ///
  59. /// We're using this structure rather than a size_t value directly
  60. /// to make API of the test fixture class more readable, i.e. the
  61. /// struct name indicates the purpose of the value being held.
  62. struct UpperBound {
  63. /// @brief Constructor.
  64. ///
  65. /// @param lower_bound Interger value wrapped by the structure.
  66. explicit UpperBound(const size_t upper_bound)
  67. : upper_bound_(upper_bound) { };
  68. /// @brief Operator returning the size_t value wrapped.
  69. operator size_t() const {
  70. return (upper_bound_);
  71. }
  72. /// @brief Value wrapped in the structure.
  73. size_t upper_bound_;
  74. };
  75. /// @brief List holding addresses for executed callouts.
  76. std::list<IOAddress> callouts_;
  77. /// @brief Callout argument name for expired lease.
  78. std::string callout_argument_name("lease4");
  79. /// @brief Base test fixture class for the lease reclamation routines in the
  80. /// @c AllocEngine.
  81. ///
  82. /// This class implements infrastructure for testing leases reclamation
  83. /// routines. The lease reclamation routine has the following
  84. /// characteristic:
  85. /// - it processes multiple leases,
  86. /// - leases are processed in certain order,
  87. /// - number of processed leases may be limited by the parameters,
  88. /// - maxium duration of the lease reclamation routine may be limited,
  89. /// - reclaimed leases may be marked as reclaimed or deleted,
  90. /// - DNS records for some of the leases must be removed when the lease
  91. /// is reclaimed and DNS updates are enabled,
  92. /// - hooks must be invoked (if installed) for each reclaimed lease
  93. /// - statistics must be updated to increase the number of reclaimed
  94. /// leases and decrease the number of allocated leases
  95. ///
  96. /// The typical test requires many leases to be initialized and stored
  97. /// in the lease database for the test. The test fixture class creates
  98. /// these leases upon construction. It is possible to modify these
  99. /// leases to test various properties of the lease reclamation routine
  100. /// as listed above. For example: some of the leases may be marked
  101. /// as expired or hostname may be cleared for some of the leases to
  102. /// check that DNS updates are not generated for them.
  103. ///
  104. /// The tests are built around the
  105. /// @c ExpirationAllocEngineTest::testLeases methods. These methods
  106. /// verify that the certain operations have been performed by the
  107. /// lease reclamation routine on selected leases. The leases for which
  108. /// certain conditions should be met are selected using the "index
  109. /// algorithms". Various index algorithms are implemented in the
  110. /// test fixture class as static functions and the algorithm is
  111. /// selected by passing function pointer to the @c testLeases method.
  112. ///
  113. /// Examples of index algorithms are:
  114. /// - evenLeaseIndex(index) - picks even index numbers,
  115. /// - oddLeaseIndex(index) - picks odd index numbers,
  116. /// - allLeasesIndexes(index) - picks all index number.
  117. ///
  118. /// For example, the test may use the @c evenLeaseIndex algorithm
  119. /// to mark leases with even indexes as expired and then test whether
  120. /// leases with even indexes have been successfully reclaimed.
  121. ///
  122. /// The "lease algorithm" verifies if the given lease fulfils the
  123. /// specific conditions after reclamation. These are the examples of
  124. /// the lease algorithms:
  125. /// - leaseExists - lease still exists in the database,
  126. /// - leaseDoesntExist - lease removed from the database,
  127. /// - leaseReclaimed - lease exists but has reclaimed status,
  128. /// - leaseNotReclaimed - lease exists and is not in the reclaimed status,
  129. /// - leaseDeclined - lease exists and is in declined state,
  130. /// - dnsUpdateGeneratedForLease - DNS updates generated for lease,
  131. /// - dnsUpdateNotGeneratedForLease - DNS updates not generated for lease
  132. ///
  133. /// The combination of index algorithm and lease algorithm allows for
  134. /// verifying that the whole sets of leases in the lease database fulfil
  135. /// certain conditions. For example, it is possible to verify that
  136. /// after lease reclamation leases with even indexes have state set to
  137. /// "expired-reclaimed".
  138. ///
  139. /// See @c ExpirationAllocEngineTest::testLeases for further details.
  140. ///
  141. /// @todo These tests should be extended to cover the following cases:
  142. /// - declined leases - declined leases expire and should be removed
  143. /// from the lease database by the lease reclamation routine. See
  144. /// ticket #3976.
  145. template<typename LeasePtrType>
  146. class ExpirationAllocEngineTest : public ::testing::Test {
  147. public:
  148. /// @brief Type definition for the lease algorithm.
  149. typedef boost::function<bool (const LeasePtrType)> LeaseAlgorithmFun;
  150. /// @brief type definition for the lease index algorithm.
  151. typedef boost::function<bool (const size_t)> IndexAlgorithmFun;
  152. /// @brief Constructor.
  153. ///
  154. /// Clears configuration, creates new lease manager and allocation engine
  155. /// instances.
  156. ExpirationAllocEngineTest(const std::string& lease_mgr_params) {
  157. // Clear configuration.
  158. CfgMgr::instance().clear();
  159. D2ClientConfigPtr cfg(new D2ClientConfig());
  160. CfgMgr::instance().setD2ClientConfig(cfg);
  161. // Remove all statistics.
  162. StatsMgr::instance().resetAll();
  163. // Set the 'reclaimed-leases' statistics to '0'. This statistics
  164. // is used by some tests to verify that the leases reclamation
  165. // routine has been called.
  166. StatsMgr::instance().setValue("reclaimed-leases",
  167. static_cast<int64_t>(0));
  168. // Create lease manager.
  169. LeaseMgrFactory::create(lease_mgr_params);
  170. // Create allocation engine instance.
  171. engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
  172. 100, true));
  173. }
  174. /// @brief Destructor
  175. ///
  176. /// Stops D2 client (if running), clears configuration and removes
  177. /// an instance of the lease manager.
  178. virtual ~ExpirationAllocEngineTest() {
  179. // Stop D2 client if running and remove all queued name change
  180. // requests.
  181. D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
  182. if (mgr.amSending()) {
  183. mgr.stopSender();
  184. mgr.clearQueue();
  185. }
  186. // Clear configuration.
  187. CfgMgr::instance().clear();
  188. D2ClientConfigPtr cfg(new D2ClientConfig());
  189. CfgMgr::instance().setD2ClientConfig(cfg);
  190. // Remove all statistics.
  191. StatsMgr::instance().resetAll();
  192. // Kill lease manager.
  193. LeaseMgrFactory::destroy();
  194. // Remove callouts executed.
  195. callouts_.clear();
  196. }
  197. /// @brief Starts D2 client.
  198. void enableDDNS() const {
  199. // Start DDNS and assign no-op error handler.
  200. D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
  201. D2ClientConfigPtr cfg(new D2ClientConfig());
  202. cfg->enableUpdates(true);
  203. mgr.setD2ClientConfig(cfg);
  204. mgr.startSender(boost::bind(&ExpirationAllocEngineTest::d2ErrorHandler, _1, _2));
  205. }
  206. /// @brief No-op error handler for the D2 client.
  207. static void d2ErrorHandler(const dhcp_ddns::NameChangeSender::Result,
  208. dhcp_ddns::NameChangeRequestPtr&) {
  209. }
  210. /// @brief Marks a lease as expired.
  211. ///
  212. /// @param lease_index Lease index. Must be between 0 and
  213. /// @c TEST_LEASES_NUM.
  214. /// @param secs Offset of the expiration time since now. For example
  215. /// a value of 2 would set the lease expiration time to 2 seconds ago.
  216. void expire(const uint16_t lease_index, const time_t secs) {
  217. ASSERT_GT(leases_.size(), lease_index);
  218. // We set the expiration time indirectly by modifying the cltt value.
  219. leases_[lease_index]->cltt_ = time(NULL) - secs -
  220. leases_[lease_index]->valid_lft_;
  221. ASSERT_NO_THROW(updateLease(lease_index));
  222. }
  223. /// @brief Changes the owner of a lease.
  224. ///
  225. /// This method changes the owner of the lease. It must be implemented in
  226. /// the derived classes to update the unique identifier(s) in the lease to
  227. /// point to a different client.
  228. ///
  229. /// @param lease_index Lease index. Must be between 0 and
  230. /// @c TEST_LEASES_NUM.
  231. virtual void transferOwnership(const uint16_t lease_index) = 0;
  232. /// @brief Marks lease as expired-reclaimed.
  233. ///
  234. /// @param lease_index Lease index. Must be between 0 and
  235. /// @c TEST_LEASES_NUM.
  236. /// @param secs Offset of the expiration time since now. For example
  237. /// a value of 2 would set the lease expiration time to 2 seconds ago.
  238. void reclaim(const uint16_t lease_index, const time_t secs) {
  239. ASSERT_GT(leases_.size(), lease_index);
  240. leases_[lease_index]->cltt_ = time(NULL) - secs -
  241. leases_[lease_index]->valid_lft_;
  242. leases_[lease_index]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
  243. ASSERT_NO_THROW(updateLease(lease_index));
  244. }
  245. /// @brief Declines specified lease
  246. ///
  247. /// Sets specified lease to declined state and sets its probation-period.
  248. /// @param lease_index Index of the lease.
  249. /// @param probation_time value of probation period to be set (in seconds)
  250. void decline(const uint16_t lease_index, const time_t probation_time) {
  251. ASSERT_GT(leases_.size(), lease_index);
  252. leases_[lease_index]->decline(probation_time);
  253. ASSERT_NO_THROW(updateLease(lease_index));
  254. }
  255. /// @brief Updates lease in the lease database.
  256. ///
  257. /// @param lease_index Index of the lease.
  258. virtual void updateLease(const unsigned int lease_index) = 0;
  259. /// @brief Retrieves lease from the database.
  260. ///
  261. /// @param lease_index Index of the lease.
  262. virtual LeasePtrType getLease(const unsigned int lease_index) const = 0;
  263. /// @brief Sets subnet id for a lease.
  264. ///
  265. /// It also updates statistics of assigned leases in the stats manager.
  266. ///
  267. /// @param lease_index Lease index.
  268. /// @param id New subnet id.
  269. virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id) = 0;
  270. /// @brief Wrapper method running lease reclamation routine.
  271. ///
  272. /// @param max_leases Maximum number of leases to be reclaimed.
  273. /// @param timeout Maximum amount of time that the reclaimation routine
  274. /// may be processing expired leases, expressed in seconds.
  275. /// @param remove_lease A boolean value indicating if the lease should
  276. /// be removed when it is reclaimed (if true) or it should be left in the
  277. /// database in the "expired-reclaimed" state (if false).
  278. virtual void reclaimExpiredLeases(const size_t max_leases,
  279. const uint16_t timeout,
  280. const bool remove_lease) = 0;
  281. /// @brief Wrapper method for removing expired-reclaimed leases.
  282. ///
  283. /// @param secs The minimum amount of time, expressed in seconds,
  284. /// for the lease to be left in the "expired-reclaimed" state
  285. /// before it can be removed.
  286. virtual void deleteExpiredReclaimedLeases(const uint32_t secs) = 0;
  287. /// @brief Test selected leases using the specified algorithms.
  288. ///
  289. /// This function picks leases from the range of 0 thru
  290. /// @c TEST_LEASES_NUM and selects the ones to be verified using the
  291. /// specified index algorithm. Selected leases are tested using
  292. /// the specified lease algorithm.
  293. ///
  294. /// @param lease_algorithm Pointer to the lease algorithm function.
  295. /// @param index_algorithm Pointer to the index algorithm function.
  296. bool testLeases(const LeaseAlgorithmFun& lease_algorithm,
  297. const IndexAlgorithmFun& index_algorithm) const {
  298. // No limits are specified, so test all leases in the range of
  299. // 0 .. TEST_LEASES_NUM.
  300. return (testLeases(lease_algorithm, index_algorithm, LowerBound(0),
  301. UpperBound(TEST_LEASES_NUM)));
  302. }
  303. /// @brief Test selected leases using the specified algorithms.
  304. ///
  305. /// This function picks leases from the range of @c lower_bound
  306. /// thru @c upper_bound and selects the ones to be verified using the
  307. /// specified index algorithm. Selected leases are tested using the
  308. /// specified lease algorithm.
  309. ///
  310. /// @param lease_algorithm Pointer to the lease algorithm function.
  311. /// @param index_algorithm Pointer to the index algorithm function.
  312. /// @param lower_bound First index in the range.
  313. /// @param upper_bound Last + 1 index in the range.
  314. bool testLeases(const LeaseAlgorithmFun& lease_algorithm,
  315. const IndexAlgorithmFun& index_algorithm,
  316. const LowerBound& lower_bound,
  317. const UpperBound& upper_bound) const {
  318. // Select leases between the lower_bound and upper_bound.
  319. for (size_t i = lower_bound; i < upper_bound; ++i) {
  320. // Get the lease from the lease database.
  321. LeasePtrType lease = getLease(i);
  322. // index_algorithm(i) checks if the lease should be checked.
  323. // If so, check if the lease_algorithm indicates that the
  324. // lease fulfils a given condition, e.g. is present in the
  325. // database. If not, return false.
  326. if (index_algorithm(i) && !lease_algorithm(lease)) {
  327. return (false);
  328. }
  329. }
  330. // All leases checked, so return true.
  331. return (true);
  332. }
  333. /// @brief Index algorithm selecting even indexes.
  334. ///
  335. /// @param index Lease index.
  336. /// @return true if index is an even number.
  337. static bool evenLeaseIndex(const size_t index) {
  338. return (index % 2 == 0);
  339. }
  340. /// @brief Index algorithm selecting odd indexes.
  341. ///
  342. /// @param index Lease index.
  343. /// @return true if index is an odd number.
  344. static bool oddLeaseIndex(const size_t index) {
  345. return (!evenLeaseIndex(index));
  346. }
  347. /// @brief Index algorithm selecting all indexes.
  348. ///
  349. /// @param index Lease index.
  350. /// @return true if the index is in the range of [0 .. TEST_LEASES_NUM).
  351. static bool allLeaseIndexes(const size_t index) {
  352. return (index < TEST_LEASES_NUM);
  353. }
  354. /// @brief Lease algorithm checking if lease exists.
  355. ///
  356. /// @param lease Pointer to lease.
  357. /// @return true if lease pointer is non-null.
  358. static bool leaseExists(const LeasePtrType& lease) {
  359. return (static_cast<bool>(lease));
  360. }
  361. /// @brief Lease algorithm checking if lease doesn't exist.
  362. ///
  363. /// @param lease Pointer to lease.
  364. /// @return true if lease pointer is null.
  365. static bool leaseDoesntExist(const LeasePtrType& lease) {
  366. return (static_cast<bool>(!lease));
  367. }
  368. /// @brief Lease algorithm checking if lease state is expired-reclaimed.
  369. ///
  370. /// This algorithm also checks that the FQDN information has been removed
  371. /// from the lease.
  372. ///
  373. /// @param lease Pointer to lease.
  374. /// @return true if lease state is "expired-reclaimed" and the FQDN
  375. /// information has been removed from the lease.
  376. static bool leaseReclaimed(const LeasePtrType& lease) {
  377. return (lease && lease->stateExpiredReclaimed() &&
  378. lease->hostname_.empty() && !lease->fqdn_fwd_ &&
  379. !lease->fqdn_rev_);
  380. }
  381. /// @brief Lease algorithm checking if lease state is Declined.
  382. ///
  383. /// @param lease Pointer to lease.
  384. /// @return true if lease state is "declined".
  385. static bool leaseDeclined(const LeasePtrType& lease) {
  386. return (lease && lease->stateDeclined());
  387. }
  388. /// @brief Lease algorithm checking if lease state is not
  389. /// expired-reclaimed.
  390. ///
  391. /// @param lease Pointer to lease.
  392. /// @return true if lease state is not "expired-reclaimed".
  393. static bool leaseNotReclaimed(const LeasePtrType& lease) {
  394. return (lease && !lease->stateExpiredReclaimed());
  395. }
  396. /// @brief Lease algorithm checking if removal name change request
  397. /// has been generated for lease.
  398. ///
  399. /// @param lease Pointer to lease.
  400. /// @return true if NCR has been generated for the lease.
  401. static bool dnsUpdateGeneratedForLease(const LeasePtrType& lease) {
  402. try {
  403. return (static_cast<bool>(getNCRForLease(lease)));
  404. } catch (...) {
  405. // If error occurred, treat it as no match.
  406. return (false);
  407. }
  408. }
  409. /// @brief Lease algorithm checking if removal name change request
  410. /// hasn't been generated for lease.
  411. ///
  412. /// @param lease Pointer to lease.
  413. /// @return true if NCR has not been generated for the lease.
  414. static bool dnsUpdateNotGeneratedForLease(const LeasePtrType& lease) {
  415. try {
  416. // Iterate over the generated name change requests and try
  417. // to find the match with our lease (using IP address). If
  418. D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
  419. for (size_t i = 0; i < mgr.getQueueSize(); ++i) {
  420. const NameChangeRequestPtr& ncr = mgr.peekAt(i);
  421. // If match found, we treat it as if the test fails
  422. // because we expected no NCR.
  423. if (ncr->getIpAddress() == lease->addr_.toText()) {
  424. return (false);
  425. }
  426. }
  427. } catch (...) {
  428. return (false);
  429. }
  430. // No match found, so we're good.
  431. return (true);
  432. }
  433. /// @brief Lease algorithm checking if callout has been executed for
  434. /// the expired lease.
  435. ///
  436. /// @param lease Pointer to lease.
  437. /// @return true if callout has been executed for the lease.
  438. static bool leaseCalloutExecuted(const LeasePtrType& lease) {
  439. return (std::find(callouts_.begin(), callouts_.end(), lease->addr_) !=
  440. callouts_.end());
  441. }
  442. /// @brief Lease algorithm checking if callout hasn't been executed for
  443. /// the expired lease.
  444. ///
  445. /// @param lease Pointer to lease.
  446. /// @return true if callout hasn't been executed for the lease.
  447. static bool leaseCalloutNotExecuted(const LeasePtrType& lease) {
  448. return (!leaseCalloutExecuted(lease));
  449. }
  450. /// @brief Implements "lease{4,6}_expire" callout.
  451. ///
  452. /// @param callout_handle Callout handle.
  453. /// @return Zero.
  454. static int leaseExpireCallout(CalloutHandle& callout_handle) {
  455. LeasePtrType lease;
  456. callout_handle.getArgument(callout_argument_name, lease);
  457. bool remove_lease = true;
  458. callout_handle.getArgument("remove_lease", remove_lease);
  459. // Check if the remove_lease is set to false and assume that the callout
  460. // has been successfully executed if it is. This is mainly to test
  461. // that the lease reclamation routine sets this value at all.
  462. if (!remove_lease) {
  463. callouts_.push_back(lease->addr_);
  464. }
  465. return (0);
  466. }
  467. /// @brief Implements "lease{4,6}_expire callout returning skip flag.
  468. ///
  469. /// @param callout_handle Callout handle.
  470. /// @return Zero.
  471. static int leaseExpireWithSkipCallout(CalloutHandle& callout_handle) {
  472. leaseExpireCallout(callout_handle);
  473. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  474. return (0);
  475. }
  476. /// @brief Implements "lease{4,6}_expire callout, which lasts at least
  477. /// 40ms.
  478. ///
  479. /// This callout is useful to test scenarios where the reclamation of the
  480. /// lease needs to take a known amount of time. If the callout is installed
  481. /// it will take at least 40ms for each lease. It is then possible to calculate
  482. /// the approximate time that the reclamation of all leases would take and
  483. /// test that the timeouts for the leases' reclamation work as expected.
  484. ///
  485. /// The value of 40ms is relatively high, but it has been selected to
  486. /// mitigate the problems with usleep on some virtual machines. On those
  487. /// machines the wakeup from usleep may take significant amount of time,
  488. /// i.e. usually around 10ms. Thus, the sleep time should be considerably
  489. /// higher than this delay.
  490. ///
  491. /// @param callout_handle Callout handle.
  492. /// @return Zero.
  493. static int leaseExpireWithDelayCallout(CalloutHandle& callout_handle) {
  494. leaseExpireCallout(callout_handle);
  495. // Delay the return from the callout by 40ms.
  496. usleep(40000);
  497. return (0);
  498. }
  499. /// @brief Returns removal name change request from the D2 client queue.
  500. ///
  501. /// @param lease Pointer to the lease to be matched with NCR.
  502. ///
  503. /// @return null pointer if no match found.
  504. static NameChangeRequestPtr getNCRForLease(const LeasePtrType& lease) {
  505. // Iterate over the generated name change requests and try
  506. // to find the match with our lease (using IP address). If
  507. D2ClientMgr& mgr = CfgMgr::instance().getD2ClientMgr();
  508. for (size_t i = 0; i < mgr.getQueueSize(); ++i) {
  509. const NameChangeRequestPtr& ncr = mgr.peekAt(i);
  510. // If match found, return true.
  511. if ((ncr->getIpAddress() == lease->addr_.toText()) &&
  512. (ncr->getChangeType() == CHG_REMOVE)) {
  513. return (ncr);
  514. }
  515. }
  516. return (NameChangeRequestPtr());
  517. }
  518. /// @brief Returns index of the lease from the address.
  519. ///
  520. /// This method assumes that leases are ordered from the smallest to
  521. /// the highest address, e.g. 10.0.0.0, 10.0.0.1, 10.0.0.2 etc. The
  522. /// last two bytes can be used to extract index.
  523. ///
  524. /// @param address Address.
  525. ///
  526. /// @return index
  527. static uint16_t getLeaseIndexFromAddress(const IOAddress& address) {
  528. std::vector<uint8_t> bytes = address.toBytes();
  529. std::vector<uint8_t>::reverse_iterator bytes_it = bytes.rbegin();
  530. uint16_t index = static_cast<uint16_t>(*bytes_it) |
  531. (static_cast<uint16_t>(*(bytes_it + 1)) << 8);
  532. return (index);
  533. }
  534. /// @brief Generates hostname for lease index.
  535. ///
  536. /// Generates hostname in the form of "hostXXXX.example.org", where
  537. /// XXXX is a lease index.
  538. ///
  539. /// @param index Lease index.
  540. ///
  541. /// @return Generated hostname.
  542. static std::string generateHostnameForLeaseIndex(const uint16_t index) {
  543. std::ostringstream hostname_s;
  544. hostname_s << "host" << std::setw(4) << std::setfill('0')
  545. << index << ".example.org";
  546. return (hostname_s.str());
  547. }
  548. /// @brief Test that leases can be reclaimed without being removed.
  549. void testReclaimExpiredLeasesUpdateState() {
  550. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  551. // Mark leases with even indexes as expired.
  552. if (evenLeaseIndex(i)) {
  553. // The higher the index, the more expired the lease.
  554. expire(i, 10 + i);
  555. }
  556. }
  557. // Run leases reclamation routine on all leases. This should result
  558. // in setting "expired-reclaimed" state for all leases with even
  559. // indexes.
  560. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  561. // Leases with even indexes should be marked as reclaimed.
  562. EXPECT_TRUE(testLeases(&leaseReclaimed, &evenLeaseIndex));
  563. // Leases with odd indexes shouldn't be marked as reclaimed.
  564. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &oddLeaseIndex));
  565. }
  566. /// @brief Test that the leases may be reclaimed by being deleted.
  567. void testReclaimExpiredLeasesDelete() {
  568. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  569. // Mark leases with even indexes as expired.
  570. if (evenLeaseIndex(i)) {
  571. // The higher the index, the more expired the lease.
  572. expire(i, 10 + i);
  573. }
  574. }
  575. // Run leases reclamation routine on all leases. This should result
  576. // in removal of all leases with even indexes.
  577. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, true));
  578. // Leases with odd indexes should be retained and their state
  579. // shouldn't be "expired-reclaimed".
  580. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &oddLeaseIndex));
  581. // Leases with even indexes should have been removed.
  582. EXPECT_TRUE(testLeases(&leaseDoesntExist, &evenLeaseIndex));
  583. }
  584. /// @brief Test that it is possible to specify the limit for the number
  585. /// of reclaimed leases.
  586. void testReclaimExpiredLeasesLimit() {
  587. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  588. // Mark all leaes as expired. The higher the index the less
  589. // expired the lease.
  590. expire(i, 1000 - i);
  591. }
  592. // We will be performing lease reclamation on lease groups of 10.
  593. // Hence, it is convenient if the number of test leases is a
  594. // multiple of 10.
  595. const size_t reclamation_group_size = 10;
  596. BOOST_STATIC_ASSERT(TEST_LEASES_NUM % reclamation_group_size == 0);
  597. // Leases will be reclaimed in groups of 10.
  598. for (unsigned int i = reclamation_group_size; i < TEST_LEASES_NUM;
  599. i += reclamation_group_size) {
  600. // Reclaim 10 most expired leases out of TEST_LEASES_NUM. Since
  601. // leases are ordered from the most expired to the least expired
  602. // this should reclaim leases between 0 and 9, then 10 and 19 etc.
  603. ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size,
  604. 0, false));
  605. // Check that leases having all indexes between 0 and 9, 19, 29 etc.
  606. // have been reclaimed.
  607. EXPECT_TRUE(testLeases(&leaseReclaimed, &allLeaseIndexes,
  608. LowerBound(0), UpperBound(i)))
  609. << "check failed for i = " << i;
  610. // Check that all remaining leases haven't been reclaimed.
  611. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes,
  612. LowerBound(i), UpperBound(TEST_LEASES_NUM)))
  613. << "check failed for i = " << i;
  614. }
  615. }
  616. /// @brief Test that DNS updates are generated for the leases for which
  617. /// the DNS records exist.
  618. void testReclaimExpiredLeasesWithDDNS() {
  619. // DNS must be started for the D2 client to accept NCRs.
  620. ASSERT_NO_THROW(enableDDNS());
  621. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  622. // Expire all leases with even indexes.
  623. if (evenLeaseIndex(i)) {
  624. // The higher the index, the more expired the lease.
  625. expire(i, 10 + i);
  626. }
  627. }
  628. // Reclaim all expired leases.
  629. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  630. // Leases with odd indexes shouldn't be reclaimed.
  631. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &oddLeaseIndex));
  632. // Leases with even indexes should be reclaimed.
  633. EXPECT_TRUE(testLeases(&leaseReclaimed, &evenLeaseIndex));
  634. // DNS updates (removal NCRs) should be generated for leases with even
  635. // indexes.
  636. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedForLease, &evenLeaseIndex));
  637. // DNS updates (removal NCRs) shouldn't be generated for leases with
  638. // odd indexes.
  639. EXPECT_TRUE(testLeases(&dnsUpdateNotGeneratedForLease, &oddLeaseIndex));
  640. }
  641. /// @brief Test that DNS updates are only generated for the reclaimed
  642. /// leases (not for all leases with hostname stored).
  643. void testReclaimExpiredLeasesWithDDNSAndLimit() {
  644. // DNS must be started for the D2 client to accept NCRs.
  645. ASSERT_NO_THROW(enableDDNS());
  646. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  647. // Expire only leases with even indexes.
  648. if (evenLeaseIndex(i)) {
  649. // The higher the index, the more expired the lease.
  650. expire(i, 10 + i);
  651. }
  652. }
  653. const size_t reclamation_group_size = 10;
  654. BOOST_STATIC_ASSERT(TEST_LEASES_NUM % reclamation_group_size == 0);
  655. // Leases will be reclaimed in groups of 10
  656. for (unsigned int i = 10; i < TEST_LEASES_NUM; i += reclamation_group_size) {
  657. // Reclaim 10 most expired leases. Note that the leases with the
  658. // higher index are more expired. For example, if the
  659. // TEST_LEASES_NUM is equal to 100, the most expired lease will
  660. // be 98, then 96, 94 etc.
  661. ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size, 0,
  662. false));
  663. // After the first iteration the lower bound is 80, because there
  664. // will be 10 the most expired leases in this group: 80, 82, 84,
  665. // 86, 88, 90, 92, 94, 96, 98. For subsequent iterations
  666. // accordingly.
  667. int reclaimed_lower_bound = TEST_LEASES_NUM - 2 * i;
  668. // At some point the lower bound will hit the negative value, which
  669. // must be corrected to 0.
  670. if (reclaimed_lower_bound < 0) {
  671. reclaimed_lower_bound = 0;
  672. }
  673. // Leases between the lower bound calculated above and the upper
  674. // bound of all leases, and having even indexes should have been
  675. // reclaimed.
  676. EXPECT_TRUE(testLeases(&leaseReclaimed, &evenLeaseIndex,
  677. LowerBound(reclaimed_lower_bound),
  678. UpperBound(TEST_LEASES_NUM)))
  679. << "check failed for i = " << i;
  680. // For the same leases we should have generated DNS updates
  681. // (removal NCRs).
  682. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedForLease, &evenLeaseIndex,
  683. LowerBound(reclaimed_lower_bound),
  684. UpperBound(TEST_LEASES_NUM)))
  685. << "check failed for i = " << i;
  686. // Leases with odd indexes (falling between the reclaimed ones)
  687. // shouldn't have been reclaimed, because they are not expired.
  688. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &oddLeaseIndex,
  689. LowerBound(reclaimed_lower_bound),
  690. UpperBound(TEST_LEASES_NUM)))
  691. << "check failed for i = " << i;
  692. EXPECT_TRUE(testLeases(&dnsUpdateNotGeneratedForLease,
  693. &oddLeaseIndex,
  694. LowerBound(reclaimed_lower_bound),
  695. UpperBound(TEST_LEASES_NUM)))
  696. << "check failed for i = " << i;
  697. // At early stages of iterations, there should be conitnuous
  698. // group of leases (expired and not expired) which haven't been
  699. // reclaimed.
  700. if (reclaimed_lower_bound > 0) {
  701. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes,
  702. LowerBound(0),
  703. UpperBound(reclaimed_lower_bound)))
  704. << "check failed for i = " << i;
  705. EXPECT_TRUE(testLeases(&dnsUpdateNotGeneratedForLease,
  706. &oddLeaseIndex,
  707. LowerBound(0),
  708. UpperBound(reclaimed_lower_bound)));
  709. }
  710. }
  711. }
  712. /// @brief This test verifies that reclamation routine continues if the
  713. /// DNS update has failed for some leases.
  714. void testReclaimExpiredLeasesInvalidHostname() {
  715. // DNS must be started for the D2 client to accept NCRs.
  716. ASSERT_NO_THROW(enableDDNS());
  717. for (size_t i = 0; i < TEST_LEASES_NUM; ++i) {
  718. // Generate invalid hostname for every other lease.
  719. if (evenLeaseIndex(i)) {
  720. // Hostname with two consecutive dots is invalid and may result
  721. // in exception if the reclamation routine doesn't protect
  722. // aginst such exceptions.
  723. std::ostringstream hostname_s;
  724. hostname_s << "invalid-host" << i << "..example.com";
  725. leases_[i]->hostname_ = hostname_s.str();
  726. ASSERT_NO_THROW(updateLease(i));
  727. }
  728. // Every lease is expired.
  729. expire(i, 10 + i);
  730. }
  731. // Although we know that some hostnames are broken we don't want the
  732. // reclamation process to break when it finds a broken record.
  733. // It should rather continue to process other leases.
  734. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  735. // All leases should have been reclaimed. Broken DNS entry doesn't
  736. // warrant that we don't reclaim the lease.
  737. EXPECT_TRUE(testLeases(&leaseReclaimed, &allLeaseIndexes));
  738. // The routine should not generate DNS updates for the leases with
  739. // broken hostname.
  740. EXPECT_TRUE(testLeases(&dnsUpdateNotGeneratedForLease,
  741. &evenLeaseIndex));
  742. // But it should generate DNS updates for the leases with the correct
  743. // hostname.
  744. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedForLease, &oddLeaseIndex));
  745. }
  746. /// @brief This test verfies that callouts are executed for each expired
  747. /// lease when installed.
  748. void testReclaimExpiredLeasesHooks() {
  749. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  750. if (evenLeaseIndex(i)) {
  751. expire(i, 1000 - i);
  752. }
  753. }
  754. HookLibsCollection libraries; // no libraries at this time
  755. HooksManager::loadLibraries(libraries);
  756. // Install a callout: lease4_expire or lease6_expire.
  757. std::ostringstream callout_name;
  758. callout_name << callout_argument_name << "_expire";
  759. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  760. callout_name.str(), leaseExpireCallout));
  761. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  762. // Callouts should be executed for leases with even indexes and these
  763. // leases should be reclaimed.
  764. EXPECT_TRUE(testLeases(&leaseCalloutExecuted, &evenLeaseIndex));
  765. EXPECT_TRUE(testLeases(&leaseReclaimed, &evenLeaseIndex));
  766. // Callouts should not be executed for leases with odd indexes and these
  767. // leases should not be reclaimed.
  768. EXPECT_TRUE(testLeases(&leaseCalloutNotExecuted, &oddLeaseIndex));
  769. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &oddLeaseIndex));
  770. }
  771. /// @brief This test verfies that callouts are executed for each expired
  772. /// lease and that the lease is not reclaimed when skip flag is set.
  773. void testReclaimExpiredLeasesHooksWithSkip() {
  774. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  775. if (evenLeaseIndex(i)) {
  776. expire(i, 1000 - i);
  777. }
  778. }
  779. HookLibsCollection libraries; // no libraries at this time
  780. HooksManager::loadLibraries(libraries);
  781. // Install a callout: lease4_expire or lease6_expire.
  782. std::ostringstream callout_name;
  783. callout_name << callout_argument_name << "_expire";
  784. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  785. callout_name.str(), leaseExpireWithSkipCallout));
  786. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  787. // Callouts should have been executed for leases with even indexes.
  788. EXPECT_TRUE(testLeases(&leaseCalloutExecuted, &evenLeaseIndex));
  789. // Callouts should not be executed for leases with odd indexes.
  790. EXPECT_TRUE(testLeases(&leaseCalloutNotExecuted, &oddLeaseIndex));
  791. // Leases shouldn't be reclaimed because the callout sets the
  792. // skip flag for each of them.
  793. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes));
  794. }
  795. /// @brief This test verifies that it is possible to set the timeout for
  796. /// the execution of the lease reclamation routine.
  797. void testReclaimExpiredLeasesTimeout(const uint16_t timeout) {
  798. // Leases are segregated from the most expired to the least expired.
  799. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  800. expire(i, 2000 - i);
  801. }
  802. HookLibsCollection libraries;
  803. HooksManager::loadLibraries(libraries);
  804. // Install a callout: lease4_expire or lease6_expire. Each callout
  805. // takes at least 40ms to run (it uses usleep).
  806. std::ostringstream callout_name;
  807. callout_name << callout_argument_name << "_expire";
  808. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  809. callout_name.str(), leaseExpireWithDelayCallout));
  810. // Reclaim leases with timeout.
  811. ASSERT_NO_THROW(reclaimExpiredLeases(0, timeout, false));
  812. // We reclaimed at most (timeout / 40ms) leases.
  813. const uint16_t theoretical_reclaimed = static_cast<uint16_t>(timeout / 40);
  814. // The actual number of leases reclaimed is likely to be lower than
  815. // the theoretical number. For low theoretical number the adjusted
  816. // number is always 1. For higher number, it will be 10 less than the
  817. // theoretical number.
  818. const uint16_t adjusted_reclaimed = (theoretical_reclaimed > 10 ?
  819. theoretical_reclaimed - 10 : 1);
  820. EXPECT_TRUE(testLeases(&leaseCalloutExecuted, &allLeaseIndexes,
  821. LowerBound(0), UpperBound(adjusted_reclaimed)));
  822. EXPECT_TRUE(testLeases(&leaseReclaimed, &allLeaseIndexes,
  823. LowerBound(0), UpperBound(adjusted_reclaimed)));
  824. EXPECT_TRUE(testLeases(&leaseCalloutNotExecuted, &allLeaseIndexes,
  825. LowerBound(theoretical_reclaimed + 1),
  826. UpperBound(TEST_LEASES_NUM)));
  827. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes,
  828. LowerBound(theoretical_reclaimed + 1),
  829. UpperBound(TEST_LEASES_NUM)));
  830. }
  831. /// @brief This test verifies that expired-reclaimed leases are removed
  832. /// from the lease database.
  833. void testDeleteExpiredReclaimedLeases() {
  834. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  835. // Mark leases with even indexes as expired.
  836. if (evenLeaseIndex(i)) {
  837. // The higher the index, the more expired the lease.
  838. reclaim(i, 10 + i);
  839. }
  840. }
  841. // Run leases reclamation routine on all leases. This should result
  842. // in removal of all leases with even indexes.
  843. ASSERT_NO_THROW(deleteExpiredReclaimedLeases(10));
  844. // Leases with odd indexes shouldn't be removed from the database.
  845. EXPECT_TRUE(testLeases(&leaseExists, &oddLeaseIndex));
  846. // Leases with even indexes should have been removed.
  847. EXPECT_TRUE(testLeases(&leaseDoesntExist, &evenLeaseIndex));
  848. }
  849. /// @brief Test that declined expired leases can be removed.
  850. ///
  851. /// This method allows controlling remove_leases parameter when calling
  852. /// @ref AllocEngine::reclaimExpiredLeases4 or
  853. /// @ref AllocEngine::reclaimExpiredLeases6. This should not matter, as
  854. /// the address affinity doesn't make sense for declined leases (they don't
  855. /// have any useful information in them anymore), so AllocEngine should
  856. /// remove them all the time.
  857. ///
  858. /// @param remove see description above
  859. void testReclaimDeclined(bool remove) {
  860. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  861. // Mark leases with even indexes as expired.
  862. if (evenLeaseIndex(i)) {
  863. // Mark lease as declined with 100 seconds of probation-period
  864. // (i.e. lease is supposed to be off limits for 100 seconds)
  865. decline(i, 100);
  866. // The higher the index, the more expired the lease.
  867. expire(i, 10 + i);
  868. }
  869. }
  870. // Run leases reclamation routine on all leases. This should result
  871. // in removing all leases with status = declined, i.e. all
  872. // even leases should be gone.
  873. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, remove));
  874. // Leases with even indexes should not exist in the DB
  875. EXPECT_TRUE(testLeases(&leaseDoesntExist, &evenLeaseIndex));
  876. }
  877. /// @brief Test that appropriate statistics are updated when
  878. /// declined expired leases are processed by AllocEngine.
  879. ///
  880. /// This method works for both v4 and v6. Just make sure the correct
  881. /// statistic name is passed. This is the name of the assigned addresses,
  882. /// that is expected to be decreased once the reclaimation procedure
  883. /// is complete.
  884. ///
  885. /// @param stat_name name of the statistic for assigned addresses statistic
  886. /// ("assgined-addresses" for both v4 and "assigned-nas" for v6)
  887. void testReclaimDeclinedStats(const std::string& stat_name) {
  888. // Leases by default all belong to subnet_id_ = 1. Let's count the
  889. // number of declined leases.
  890. int subnet1_cnt = 0;
  891. int subnet2_cnt = 0;
  892. // Let's move all leases to declined,expired state.
  893. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  894. // Move the lease to declined state
  895. decline(i, 100);
  896. // And expire it, so it will be reclaimed
  897. expire(i, 10 + 1);
  898. // Move every other lease to subnet-id = 2.
  899. if (evenLeaseIndex(i)) {
  900. subnet1_cnt++;
  901. } else {
  902. subnet2_cnt++;
  903. setSubnetId(i, 2);
  904. }
  905. }
  906. StatsMgr& stats_mgr = StatsMgr::instance();
  907. // Let's set the global statistic. Values are arbitrary and can
  908. // be used to easily detect whether a given stat was decreased or
  909. // increased. They are sufficiently high compared to number of leases
  910. // to avoid any chances of going into negative.
  911. stats_mgr.setValue("declined-addresses", static_cast<int64_t>(1000));
  912. // Let's set global the counter for reclaimed declined addresses.
  913. stats_mgr.setValue("reclaimed-declined-addresses",
  914. static_cast<int64_t>(2000));
  915. // And those subnet specific as well
  916. stats_mgr.setValue(stats_mgr.generateName("subnet", 1,
  917. stat_name), int64_t(1000));
  918. stats_mgr.setValue(stats_mgr.generateName("subnet", 2,
  919. stat_name), int64_t(2000));
  920. stats_mgr.setValue(stats_mgr.generateName("subnet", 1,
  921. "reclaimed-declined-addresses"), int64_t(10000));
  922. stats_mgr.setValue(stats_mgr.generateName("subnet", 2,
  923. "reclaimed-declined-addresses"), int64_t(20000));
  924. stats_mgr.setValue(stats_mgr.generateName("subnet", 1,
  925. "declined-addresses"), int64_t(100));
  926. stats_mgr.setValue(stats_mgr.generateName("subnet", 2,
  927. "declined-addresses"), int64_t(200));
  928. // Run leases reclamation routine on all leases. This should result
  929. // in removal of all leases with even indexes.
  930. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, true));
  931. // Declined-addresses should be decreased from its initial value (1000)
  932. // for both recovered addresses from subnet1 and subnet2.
  933. testStatistics("declined-addresses", 1000 - subnet1_cnt - subnet2_cnt);
  934. // The code should bump up global counter for reclaimed declined
  935. // addresses.
  936. testStatistics("reclaimed-declined-addresses", 2000 + subnet1_cnt + subnet2_cnt);
  937. // subnet[X].assigned-addresses should go down. Between the time
  938. // of DHCPDECLINE(v4)/DECLINE(v6) reception and declined expired lease
  939. // reclaimation, we count this address as assigned-addresses. We decrease
  940. // assigned-addresses(v4)/assgined-nas(v6) when we reclaim the lease,
  941. // not when the packet is received. For explanation, see Duplicate
  942. // Addresses (DHCPDECLINE support) (v4) or Duplicate Addresses (DECLINE
  943. // support) sections in the User's Guide or a comment in
  944. // Dhcpv4Srv::declineLease or Dhcpv6Srv::declineLease.
  945. testStatistics("subnet[1]." + stat_name, 1000 - subnet1_cnt);
  946. testStatistics("subnet[2]." + stat_name, 2000 - subnet2_cnt);
  947. testStatistics("subnet[1].declined-addresses", 100 - subnet1_cnt);
  948. testStatistics("subnet[2].declined-addresses", 200 - subnet2_cnt);
  949. // subnet[X].reclaimed-declined-addresses should go up in each subnet
  950. testStatistics("subnet[1].reclaimed-declined-addresses", 10000 + subnet1_cnt);
  951. testStatistics("subnet[2].reclaimed-declined-addresses", 20000 + subnet1_cnt);
  952. }
  953. /// @brief Collection of leases created at construction time.
  954. std::vector<LeasePtrType> leases_;
  955. /// @brief Allocation engine instance used for tests.
  956. AllocEnginePtr engine_;
  957. };
  958. /// @brief Specialization of the @c ExpirationAllocEngineTest class to test
  959. /// reclamation of the IPv6 leases.
  960. class ExpirationAllocEngine6Test : public ExpirationAllocEngineTest<Lease6Ptr> {
  961. public:
  962. /// @brief Class constructor.
  963. ///
  964. /// This constructor initializes @c TEST_LEASES_NUM leases and
  965. /// stores them in the lease manager.
  966. ExpirationAllocEngine6Test();
  967. /// @brief Virtual destructor.
  968. ///
  969. /// Clears up static fields that may be modified by hooks.
  970. virtual ~ExpirationAllocEngine6Test() {
  971. callout_lease_.reset();
  972. callout_name_ = string("");
  973. }
  974. /// @brief Creates collection of leases for a test.
  975. ///
  976. /// It is called internally at the construction time.
  977. void createLeases();
  978. /// @brief Updates lease in the lease database.
  979. ///
  980. /// @param lease_index Index of the lease.
  981. virtual void updateLease(const unsigned int lease_index) {
  982. LeaseMgrFactory::instance().updateLease6(leases_[lease_index]);
  983. }
  984. /// @brief Changes the owner of a lease.
  985. ///
  986. /// This method changes the owner of the lease by modifying the DUID.
  987. ///
  988. /// @param lease_index Lease index. Must be between 0 and
  989. /// @c TEST_LEASES_NUM.
  990. virtual void transferOwnership(const uint16_t lease_index);
  991. /// @brief Sets subnet id for a lease.
  992. ///
  993. /// It also updates statistics of assigned leases in the stats manager.
  994. ///
  995. /// @param lease_index Lease index.
  996. /// @param id New subnet id.
  997. virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id);
  998. /// @brief Sets type of a lease.
  999. ///
  1000. /// It also updates statistics of assigned leases in the stats manager.
  1001. ///
  1002. /// @param lease_index Lease index.
  1003. /// @param lease_type Lease type.
  1004. void setLeaseType(const uint16_t lease_index, const Lease6::Type& lease_type);
  1005. /// @brief Retrieves lease from the database.
  1006. ///
  1007. /// @param lease_index Index of the lease.
  1008. virtual Lease6Ptr getLease(const unsigned int lease_index) const {
  1009. return (LeaseMgrFactory::instance().getLease6(leases_[lease_index]->type_,
  1010. leases_[lease_index]->addr_));
  1011. }
  1012. /// @brief Wrapper method running lease reclamation routine.
  1013. ///
  1014. /// @param max_leases Maximum number of leases to be reclaimed.
  1015. /// @param timeout Maximum amount of time that the reclaimation routine
  1016. /// may be processing expired leases, expressed in seconds.
  1017. /// @param remove_lease A boolean value indicating if the lease should
  1018. /// be removed when it is reclaimed (if true) or it should be left in the
  1019. /// database in the "expired-reclaimed" state (if false).
  1020. virtual void reclaimExpiredLeases(const size_t max_leases,
  1021. const uint16_t timeout,
  1022. const bool remove_lease) {
  1023. engine_->reclaimExpiredLeases6(max_leases, timeout, remove_lease);
  1024. }
  1025. /// @brief Wrapper method for removing expired-reclaimed leases.
  1026. ///
  1027. /// @param secs The minimum amount of time, expressed in seconds,
  1028. /// for the lease to be left in the "expired-reclaimed" state
  1029. /// before it can be removed.
  1030. virtual void deleteExpiredReclaimedLeases(const uint32_t secs) {
  1031. engine_->deleteExpiredReclaimedLeases6(secs);
  1032. }
  1033. /// @brief Test that statistics is updated when leases are reclaimed.
  1034. void testReclaimExpiredLeasesStats();
  1035. /// @brief Test that expired leases are reclaimed before they are allocated.
  1036. ///
  1037. /// @param msg_type DHCPv6 message type.
  1038. /// @param use_reclaimed Boolean parameter indicating if the leases
  1039. /// stored in the lease database should be marked as 'expired-reclaimed'
  1040. /// or 'expired'. This allows to test whether the allocation engine can
  1041. /// determine that the lease has been reclaimed already and not reclaim
  1042. /// it the second time.
  1043. void testReclaimReusedLeases(const uint16_t msg_type, const bool use_reclaimed);
  1044. /// @brief Callout for lease6_recover
  1045. ///
  1046. /// This callout stores passed parameter into static fields.
  1047. ///
  1048. /// @param callout_handle will be provided by hooks framework
  1049. /// @return always 0
  1050. static int lease6RecoverCallout(CalloutHandle& callout_handle) {
  1051. callout_name_ = "lease6_recover";
  1052. callout_handle.getArgument("lease6", callout_lease_);
  1053. return (0);
  1054. }
  1055. /// @brief Callout for lease6_recover that sets status to SKIP
  1056. ///
  1057. /// This callout stores passed parameter into static fields.
  1058. ///
  1059. /// @param callout_handle will be provided by hooks framework
  1060. /// @return always 0
  1061. static int lease6RecoverSkipCallout(CalloutHandle& callout_handle) {
  1062. // Set the next step status to SKIP
  1063. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  1064. return (lease6RecoverCallout(callout_handle));
  1065. }
  1066. /// @brief Test install a hook callout, recovers declined leases
  1067. ///
  1068. /// This test: declines, then expires half of the leases, then
  1069. /// installs a callout on lease6_recover hook, then reclaims
  1070. /// expired leases and checks that:
  1071. /// - the callout was indeed called
  1072. /// - the parameter (lease6) was indeed passed as expected
  1073. /// - checks that the leases are removed (skip=false) or
  1074. /// - checks that the leases are still there (skip=true)
  1075. /// @param skip should the callout set the next step status to skip?
  1076. void
  1077. testReclaimDeclinedHook(bool skip);
  1078. /// The following parameters will be written by a callout
  1079. static std::string callout_name_; ///< Stores callout name
  1080. static Lease6Ptr callout_lease_; ///< Stores callout parameter
  1081. };
  1082. std::string ExpirationAllocEngine6Test::callout_name_;
  1083. Lease6Ptr ExpirationAllocEngine6Test::callout_lease_;
  1084. ExpirationAllocEngine6Test::ExpirationAllocEngine6Test()
  1085. : ExpirationAllocEngineTest<Lease6Ptr>("type=memfile universe=6 persist=false") {
  1086. createLeases();
  1087. callout_argument_name = "lease6";
  1088. // Let's clear any garbage previous test may have left in static fields.
  1089. callout_name_ = string("");
  1090. callout_lease_.reset();
  1091. }
  1092. void
  1093. ExpirationAllocEngine6Test::createLeases() {
  1094. // Create TEST_LEASES_NUM leases.
  1095. for (uint16_t i = 0; i < TEST_LEASES_NUM; ++i) {
  1096. // DUID
  1097. std::ostringstream duid_s;
  1098. duid_s << "01020304050607" << std::setw(4) << std::setfill('0') << i;
  1099. DuidPtr duid(new DUID(DUID::fromText(duid_s.str()).getDuid()));
  1100. // Address.
  1101. std::ostringstream address_s;
  1102. address_s << "2001:db8:1::" << std::setw(4) << std::setfill('0') << i;
  1103. IOAddress address(address_s.str());
  1104. // Create lease.
  1105. Lease6Ptr lease(new Lease6(Lease::TYPE_NA, address, duid, 1, 50, 60, 10,
  1106. 20, SubnetID(1), true, true,
  1107. generateHostnameForLeaseIndex(i)));
  1108. leases_.push_back(lease);
  1109. // Copy the lease before adding it to the lease manager. We want to
  1110. // make sure that modifications to the leases held in the leases_
  1111. // container doesn't affect the leases in the lease manager.
  1112. LeaseMgrFactory::instance().addLease(Lease6Ptr(new Lease6(*lease)));
  1113. // Note in the statistics that this lease has been added.
  1114. StatsMgr& stats_mgr = StatsMgr::instance();
  1115. std::string stat_name =
  1116. lease->type_ == Lease::TYPE_NA ? "assigned-nas" : "assigned-pds";
  1117. stats_mgr.addValue(stats_mgr.generateName("subnet", lease->subnet_id_, stat_name),
  1118. int64_t(1));
  1119. }
  1120. }
  1121. void
  1122. ExpirationAllocEngine6Test::transferOwnership(const uint16_t lease_index) {
  1123. ASSERT_GT(leases_.size(), lease_index);
  1124. std::vector<uint8_t> bytes = leases_[lease_index]->duid_->getDuid();
  1125. if (bytes.size() > 1) {
  1126. if (++bytes[0] == 0) {
  1127. ++bytes[1];
  1128. }
  1129. }
  1130. leases_[lease_index]->duid_.reset(new DUID(bytes));
  1131. }
  1132. void
  1133. ExpirationAllocEngine6Test::setSubnetId(const uint16_t lease_index, const SubnetID& id) {
  1134. ASSERT_GT(leases_.size(), lease_index);
  1135. if (leases_[lease_index]->subnet_id_ != id) {
  1136. StatsMgr& stats_mgr = StatsMgr::instance();
  1137. std::string stats_name = (leases_[lease_index]->type_ == Lease::TYPE_NA ?
  1138. "assigned-nas" : "assigned-pds");
  1139. stats_mgr.addValue(stats_mgr.generateName("subnet", id, stats_name),
  1140. int64_t(1));
  1141. stats_mgr.addValue(stats_mgr.generateName("subnet",
  1142. leases_[lease_index]->subnet_id_,
  1143. stats_name),
  1144. int64_t(-1));
  1145. leases_[lease_index]->subnet_id_ = id;
  1146. ASSERT_NO_THROW(updateLease(lease_index));
  1147. }
  1148. }
  1149. void
  1150. ExpirationAllocEngine6Test::setLeaseType(const uint16_t lease_index,
  1151. const Lease6::Type& lease_type) {
  1152. ASSERT_GT(leases_.size(), lease_index);
  1153. if (leases_[lease_index]->type_ != lease_type) {
  1154. StatsMgr& stats_mgr = StatsMgr::instance();
  1155. std::string stats_name = (lease_type == Lease::TYPE_NA ?
  1156. "assigned-nas" : "assigned-pds");
  1157. stats_mgr.addValue(stats_mgr.generateName("subnet",
  1158. leases_[lease_index]->subnet_id_,
  1159. stats_name),
  1160. int64_t(1));
  1161. stats_name = (leases_[lease_index]->type_ == Lease::TYPE_NA ?
  1162. "assigned-nas" : "assigned-pds");
  1163. stats_mgr.addValue(stats_mgr.generateName("subnet",
  1164. leases_[lease_index]->subnet_id_,
  1165. stats_name),
  1166. int64_t(-1));
  1167. leases_[lease_index]->type_ = lease_type;
  1168. ASSERT_NO_THROW(updateLease(lease_index));
  1169. }
  1170. }
  1171. void
  1172. ExpirationAllocEngine6Test::testReclaimExpiredLeasesStats() {
  1173. // This test requires that the number of leases is an even number.
  1174. BOOST_STATIC_ASSERT(TEST_LEASES_NUM % 2 == 0);
  1175. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1176. // Mark all leaes as expired. The higher the index the less
  1177. // expired the lease.
  1178. expire(i, 1000 - i);
  1179. // Modify subnet ids and lease types for some leases.
  1180. if (evenLeaseIndex(i)) {
  1181. setSubnetId(i, SubnetID(2));
  1182. setLeaseType(i, Lease::TYPE_PD);
  1183. }
  1184. }
  1185. // Leases will be reclaimed in groups of 8.
  1186. const size_t reclamation_group_size = 8;
  1187. for (unsigned int i = reclamation_group_size; i < TEST_LEASES_NUM;
  1188. i += reclamation_group_size) {
  1189. // Reclaim 8 most expired leases out of TEST_LEASES_NUM.
  1190. ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size,
  1191. 0, false));
  1192. // Number of reclaimed leases should increase as we loop.
  1193. EXPECT_TRUE(testStatistics("reclaimed-leases", i));
  1194. // Make sure that the number of reclaimed leases is also distributed
  1195. // across two subnets.
  1196. EXPECT_TRUE(testStatistics("subnet[1].reclaimed-leases", i / 2));
  1197. EXPECT_TRUE(testStatistics("subnet[2].reclaimed-leases", i / 2));
  1198. // Number of assigned leases should decrease as we reclaim them.
  1199. EXPECT_TRUE(testStatistics("subnet[1].assigned-nas",
  1200. (TEST_LEASES_NUM - i) / 2));
  1201. EXPECT_TRUE(testStatistics("subnet[2].assigned-pds",
  1202. (TEST_LEASES_NUM - i) / 2));
  1203. }
  1204. }
  1205. void
  1206. ExpirationAllocEngine6Test::testReclaimReusedLeases(const uint16_t msg_type,
  1207. const bool use_reclaimed) {
  1208. BOOST_STATIC_ASSERT(TEST_LEASES_NUM < 1000);
  1209. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1210. // Depending on the parameter, mark leases 'expired-reclaimed' or
  1211. // simply 'expired'.
  1212. if (use_reclaimed) {
  1213. reclaim(i, 1000 - i);
  1214. } else {
  1215. // Mark all leases as expired.
  1216. expire(i, 1000 - i);
  1217. }
  1218. // For the Renew case, we don't change the ownership of leases. We
  1219. // will let the lease owners renew them. For other cases, we modify
  1220. // the DUIDs to simulate reuse of expired leases.
  1221. if (msg_type != DHCPV6_RENEW) {
  1222. transferOwnership(i);
  1223. }
  1224. }
  1225. // Create subnet and the pool. This is required by the allocation process.
  1226. Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 50, 60,
  1227. SubnetID(1)));
  1228. ASSERT_NO_THROW(subnet->addPool(Pool6Ptr(new Pool6(Lease::TYPE_NA,
  1229. IOAddress("2001:db8:1::"),
  1230. IOAddress("2001:db8:1::FFFF")))));
  1231. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1232. // Build the context.
  1233. AllocEngine::ClientContext6 ctx(subnet, leases_[i]->duid_,
  1234. false, false,
  1235. leases_[i]->hostname_,
  1236. msg_type == DHCPV6_SOLICIT,
  1237. Pkt6Ptr(new Pkt6(msg_type, 0x1234)));
  1238. ctx.currentIA().iaid_ = 1;
  1239. ctx.currentIA().hints_.push_back(std::make_pair(leases_[i]->addr_, 128));
  1240. // Depending on the message type, we will call a different function.
  1241. if (msg_type == DHCPV6_RENEW) {
  1242. ASSERT_NO_THROW(engine_->renewLeases6(ctx));
  1243. } else {
  1244. ASSERT_NO_THROW(engine_->allocateLeases6(ctx));
  1245. }
  1246. }
  1247. // The Solicit should not trigger leases reclamation. The Renew and
  1248. // Request must trigger leases reclamation unless the lease is
  1249. // initially reclaimed.
  1250. if (use_reclaimed || (msg_type == DHCPV6_SOLICIT)) {
  1251. EXPECT_TRUE(testStatistics("reclaimed-leases", 0));
  1252. } else {
  1253. EXPECT_TRUE(testStatistics("reclaimed-leases", TEST_LEASES_NUM));
  1254. // Leases should have been updated in the lease database and their
  1255. // state should not be 'expired-reclaimed' anymore.
  1256. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes));
  1257. }
  1258. }
  1259. void
  1260. ExpirationAllocEngine6Test::testReclaimDeclinedHook(bool skip) {
  1261. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1262. // Mark leases with even indexes as expired.
  1263. if (evenLeaseIndex(i)) {
  1264. // Mark lease as declined with 100 seconds of probation-period
  1265. // (i.e. lease is supposed to be off limits for 100 seconds)
  1266. decline(i, 100);
  1267. // The higher the index, the more expired the lease.
  1268. expire(i, 10 + i);
  1269. }
  1270. }
  1271. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1272. "lease6_recover",
  1273. skip ? lease6RecoverSkipCallout : lease6RecoverCallout));
  1274. // Run leases reclamation routine on all leases.
  1275. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, true));
  1276. // Make sure that the callout really was called. It was supposed to modify
  1277. // the callout_name_ and store the lease in callout_lease_
  1278. EXPECT_EQ("lease6_recover", callout_name_);
  1279. EXPECT_TRUE(callout_lease_);
  1280. // Leases with even indexes should not exist in the DB
  1281. if (skip) {
  1282. // Skip status should have prevented removing the lease.
  1283. EXPECT_TRUE(testLeases(&leaseExists, &evenLeaseIndex));
  1284. } else {
  1285. // The hook hasn't modified next step status. The lease should be gone.
  1286. EXPECT_TRUE(testLeases(&leaseDoesntExist, &evenLeaseIndex));
  1287. }
  1288. };
  1289. // This test verifies that the leases can be reclaimed without being removed
  1290. // from the database. In such case, the leases' state is set to
  1291. // "expired-reclaimed".
  1292. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeases6UpdateState) {
  1293. testReclaimExpiredLeasesUpdateState();
  1294. }
  1295. // This test verifies that the reclaimed leases are deleted when requested.
  1296. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesDelete) {
  1297. testReclaimExpiredLeasesDelete();
  1298. }
  1299. // This test verifies that it is possible to specify the limit for the
  1300. // number of reclaimed leases.
  1301. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesLimit) {
  1302. testReclaimExpiredLeasesLimit();
  1303. }
  1304. // This test verifies that DNS updates are generated for the leases
  1305. // for which the DNS records exist.
  1306. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesWithDDNS) {
  1307. testReclaimExpiredLeasesWithDDNS();
  1308. }
  1309. // This test verifies that it is DNS updates are generated only for the
  1310. // reclaimed expired leases. In this case we limit the number of leases
  1311. // reclaimed during a single call to reclamation routine.
  1312. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesWithDDNSAndLimit) {
  1313. testReclaimExpiredLeasesWithDDNSAndLimit();
  1314. }
  1315. // This test verifies that if some leases have invalid hostnames, the
  1316. // lease reclamation routine continues with reclamation of leases anyway.
  1317. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesInvalidHostname) {
  1318. testReclaimExpiredLeasesInvalidHostname();
  1319. }
  1320. // This test verifies that statistics is correctly updated when the leases
  1321. // are reclaimed.
  1322. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesStats) {
  1323. testReclaimExpiredLeasesStats();
  1324. }
  1325. // This test verifies that callouts are executed for each expired lease.
  1326. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesHooks) {
  1327. testReclaimExpiredLeasesHooks();
  1328. }
  1329. // This test verifies that callouts are executed for each expired lease
  1330. // and that the lease is not reclaimed when the skip flag is set.
  1331. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesHooksWithSkip) {
  1332. testReclaimExpiredLeasesHooksWithSkip();
  1333. }
  1334. // This test verifies that it is possible to set the timeout for the
  1335. // execution of the lease reclamation routine.
  1336. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesTimeout) {
  1337. // This test needs at least 40 leases to make sense.
  1338. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 40);
  1339. // Run with timeout of 1.2s.
  1340. testReclaimExpiredLeasesTimeout(1200);
  1341. }
  1342. // This test verifies that at least one lease is reclaimed if the timeout
  1343. // for the lease reclamation routine is shorter than the time needed for
  1344. // the reclamation of a single lease. This prevents the situation when
  1345. // very short timeout (perhaps misconfigured) effectively precludes leases
  1346. // reclamation.
  1347. TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesShortTimeout) {
  1348. // We will most likely reclaim just one lease, so 5 is more than enough.
  1349. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 5);
  1350. // Reclaim leases with the 1ms timeout.
  1351. testReclaimExpiredLeasesTimeout(1);
  1352. }
  1353. // This test verifies that expired-reclaimed leases are removed from the
  1354. // lease database.
  1355. TEST_F(ExpirationAllocEngine6Test, deleteExpiredReclaimedLeases) {
  1356. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 10);
  1357. testDeleteExpiredReclaimedLeases();
  1358. }
  1359. /// This test verifies that @ref AllocEngine::reclaimExpiredLeases6 properly
  1360. /// handles declined leases that have expired in case when it is told to
  1361. /// remove leases.}
  1362. TEST_F(ExpirationAllocEngine6Test, reclaimDeclined1) {
  1363. testReclaimDeclined(true);
  1364. }
  1365. /// This test verifies that @ref AllocEngine::reclaimExpiredLeases6 properly
  1366. /// handles declined leases that have expired in case when it is told to
  1367. /// not remove leases. This flag should not matter and declined expired
  1368. /// leases should always be removed.
  1369. TEST_F(ExpirationAllocEngine6Test, reclaimDeclined2) {
  1370. testReclaimDeclined(false);
  1371. }
  1372. /// This test verifies that statistics are modified correctly after
  1373. /// reclaim expired leases is called.
  1374. TEST_F(ExpirationAllocEngine6Test, reclaimDeclinedStats) {
  1375. testReclaimDeclinedStats("assigned-nas");
  1376. }
  1377. // This test verifies that expired leases are reclaimed before they are
  1378. // allocated to another client sending a Request message.
  1379. TEST_F(ExpirationAllocEngine6Test, reclaimReusedLeases) {
  1380. testReclaimReusedLeases(DHCPV6_REQUEST, false);
  1381. }
  1382. // This test verifies that allocation engine detects that the expired
  1383. // lease has been reclaimed already when it reuses this lease.
  1384. TEST_F(ExpirationAllocEngine6Test, reclaimReusedLeasesAlreadyReclaimed) {
  1385. testReclaimReusedLeases(DHCPV6_REQUEST, true);
  1386. }
  1387. // This test verifies that expired leases are reclaimed before they
  1388. // are renewed.
  1389. TEST_F(ExpirationAllocEngine6Test, reclaimRenewedLeases) {
  1390. testReclaimReusedLeases(DHCPV6_RENEW, false);
  1391. }
  1392. // This test verifies that allocation engine detects that the expired
  1393. // lease has been reclaimed already when it renews the lease.
  1394. TEST_F(ExpirationAllocEngine6Test, reclaimRenewedLeasesAlreadyReclaimed) {
  1395. testReclaimReusedLeases(DHCPV6_RENEW, true);
  1396. }
  1397. // This test verifies that the expired leases are not reclaimed when the
  1398. // Solicit message is being processed.
  1399. TEST_F(ExpirationAllocEngine6Test, reclaimReusedLeasesSolicit) {
  1400. testReclaimReusedLeases(DHCPV6_SOLICIT, false);
  1401. }
  1402. // This test verifies that the 'expired-reclaimed' leases are not reclaimed
  1403. // again when the Solicit message is being processed.
  1404. TEST_F(ExpirationAllocEngine6Test, reclaimReusedLeasesSolicitAlreadyReclaimed) {
  1405. testReclaimReusedLeases(DHCPV6_SOLICIT, true);
  1406. }
  1407. // This test verifies if the hooks installed on lease6_recover are called
  1408. // when the lease expires.
  1409. TEST_F(ExpirationAllocEngine6Test, reclaimDeclinedHook1) {
  1410. testReclaimDeclinedHook(false); // false = don't use skip callout
  1411. }
  1412. // This test verifies if the hooks installed on lease6_recover are called
  1413. // when the lease expires and that the next step status set to SKIP
  1414. // causes the recovery to not be conducted.
  1415. TEST_F(ExpirationAllocEngine6Test, reclaimDeclinedHook2) {
  1416. testReclaimDeclinedHook(true); // true = use skip callout
  1417. }
  1418. // *******************************************************
  1419. //
  1420. // DHCPv4 lease reclamation routine tests start here!
  1421. //
  1422. // *******************************************************
  1423. /// @brief Specialization of the @c ExpirationAllocEngineTest class to test
  1424. /// reclamation of the IPv4 leases.
  1425. class ExpirationAllocEngine4Test : public ExpirationAllocEngineTest<Lease4Ptr> {
  1426. public:
  1427. /// @brief Class constructor.
  1428. ///
  1429. /// This constructor initializes @c TEST_LEASES_NUM leases and
  1430. /// stores them in the lease manager.
  1431. ExpirationAllocEngine4Test();
  1432. /// @brief Virtual destructor.
  1433. ///
  1434. /// Clears up static fields that may be modified by hooks.
  1435. virtual ~ExpirationAllocEngine4Test() {
  1436. callout_lease_.reset();
  1437. callout_name_ = string("");
  1438. }
  1439. /// @brief Creates collection of leases for a test.
  1440. ///
  1441. /// It is called internally at the construction time.
  1442. void createLeases();
  1443. /// @brief Generates unique client identifier from lease index.
  1444. ///
  1445. /// @param index lease index.
  1446. void setUniqueClientId(const uint16_t index);
  1447. /// @brief Updates lease in the lease database.
  1448. ///
  1449. /// @param lease_index Index of the lease.
  1450. virtual void updateLease(const unsigned int lease_index) {
  1451. LeaseMgrFactory::instance().updateLease4(leases_[lease_index]);
  1452. }
  1453. /// @brief Changes the owner of a lease.
  1454. ///
  1455. /// This method changes the owner of the lease by updating the client
  1456. /// identifier (if present) or HW address.
  1457. ///
  1458. /// @param lease_index Lease index. Must be between 0 and
  1459. /// @c TEST_LEASES_NUM.
  1460. virtual void transferOwnership(const uint16_t lease_index);
  1461. /// @brief Retrieves lease from the database.
  1462. ///
  1463. /// @param lease_index Index of the lease.
  1464. virtual Lease4Ptr getLease(const unsigned int lease_index) const {
  1465. return (LeaseMgrFactory::instance().getLease4(leases_[lease_index]->addr_));
  1466. }
  1467. /// @brief Sets subnet id for a lease.
  1468. ///
  1469. /// It also updates statistics of assigned leases in the stats manager.
  1470. ///
  1471. /// @param lease_index Lease index.
  1472. /// @param id New subnet id.
  1473. virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id);
  1474. /// @brief Wrapper method running lease reclamation routine.
  1475. ///
  1476. /// @param max_leases Maximum number of leases to be reclaimed.
  1477. /// @param timeout Maximum amount of time that the reclaimation routine
  1478. /// may be processing expired leases, expressed in seconds.
  1479. /// @param remove_lease A boolean value indicating if the lease should
  1480. /// be removed when it is reclaimed (if true) or it should be left in the
  1481. /// database in the "expired-reclaimed" state (if false).
  1482. virtual void reclaimExpiredLeases(const size_t max_leases,
  1483. const uint16_t timeout,
  1484. const bool remove_lease) {
  1485. engine_->reclaimExpiredLeases4(max_leases, timeout, remove_lease);
  1486. }
  1487. /// @brief Wrapper method for removing expired-reclaimed leases.
  1488. ///
  1489. /// @param secs The minimum amount of time, expressed in seconds,
  1490. /// for the lease to be left in the "expired-reclaimed" state
  1491. /// before it can be removed.
  1492. virtual void deleteExpiredReclaimedLeases(const uint32_t secs) {
  1493. engine_->deleteExpiredReclaimedLeases4(secs);
  1494. }
  1495. /// @brief Lease algorithm checking if NCR has been generated from client
  1496. /// identifier.
  1497. ///
  1498. /// @param lease Pointer to the lease for which the NCR needs to be checked.
  1499. static bool dnsUpdateGeneratedFromClientId(const Lease4Ptr& lease);
  1500. /// @brief Lease algorithm checking if NCR has been generated from
  1501. /// HW address.
  1502. static bool dnsUpdateGeneratedFromHWAddress(const Lease4Ptr& lease);
  1503. /// @brief Test that DNS updates are properly generated when the
  1504. /// reclaimed leases contain client identifier.
  1505. void testReclaimExpiredLeasesWithDDNSAndClientId();
  1506. /// @brief Test that statistics is updated when leases are reclaimed..
  1507. void testReclaimExpiredLeasesStats();
  1508. /// @brief Test that the lease is reclaimed before it is renewed or
  1509. /// reused.
  1510. ///
  1511. /// @param msg_type DHCPv4 message type, i.e. DHCPDISCOVER or DHCPREQUEST.
  1512. /// @param client_renews A boolean value which indicates if the test should
  1513. /// simulate renewals of leases (if true) or reusing expired leases which
  1514. /// belong to different clients (if false).
  1515. /// @param use_reclaimed Boolean parameter indicating if the leases being
  1516. /// reused should initially be reclaimed.
  1517. void testReclaimReusedLeases(const uint8_t msg_type, const bool client_renews,
  1518. const bool use_reclaimed);
  1519. /// @brief Callout for lease4_recover
  1520. ///
  1521. /// This callout stores passed parameter into static fields.
  1522. ///
  1523. /// @param callout_handle will be provided by hooks framework
  1524. /// @return always 0
  1525. static int lease4RecoverCallout(CalloutHandle& callout_handle) {
  1526. callout_name_ = "lease4_recover";
  1527. callout_handle.getArgument("lease4", callout_lease_);
  1528. return (0);
  1529. }
  1530. /// @brief Callout for lease4_recover that sets status to SKIP
  1531. ///
  1532. /// This callout stores passed parameter into static fields.
  1533. ///
  1534. /// @param callout_handle will be provided by hooks framework
  1535. /// @return always 0
  1536. static int lease4RecoverSkipCallout(CalloutHandle& callout_handle) {
  1537. // Set the next step status to SKIP
  1538. callout_handle.setStatus(CalloutHandle::NEXT_STEP_SKIP);
  1539. return (lease4RecoverCallout(callout_handle));
  1540. }
  1541. /// @brief Test install a hook callout, recovers declined leases
  1542. ///
  1543. /// This test: declines, then expires half of the leases, then
  1544. /// installs a callout on lease4_recover hook, then reclaims
  1545. /// expired leases and checks that:
  1546. /// - the callout was indeed called
  1547. /// - the parameter (lease4) was indeed passed as expected
  1548. /// - checks that the leases are removed (skip=false) or
  1549. /// - checks that the leases are still there (skip=true)
  1550. /// @param skip should the callout set the next step status to skip?
  1551. void
  1552. testReclaimDeclinedHook(bool skip);
  1553. /// The following parameters will be written by a callout
  1554. static std::string callout_name_; ///< Stores callout name
  1555. static Lease4Ptr callout_lease_; ///< Stores callout parameter
  1556. };
  1557. std::string ExpirationAllocEngine4Test::callout_name_;
  1558. Lease4Ptr ExpirationAllocEngine4Test::callout_lease_;
  1559. ExpirationAllocEngine4Test::ExpirationAllocEngine4Test()
  1560. : ExpirationAllocEngineTest<Lease4Ptr>("type=memfile universe=4 persist=false") {
  1561. createLeases();
  1562. callout_argument_name = "lease4";
  1563. // Let's clear any garbage previous test may have left in static fields.
  1564. callout_name_ = string("");
  1565. callout_lease_.reset();
  1566. }
  1567. void
  1568. ExpirationAllocEngine4Test::createLeases() {
  1569. // Create TEST_LEASES_NUM leases.
  1570. for (uint16_t i = 0; i < TEST_LEASES_NUM; ++i) {
  1571. // HW address
  1572. std::ostringstream hwaddr_s;
  1573. hwaddr_s << "01:02:03:04:" << std::setw(2) << std::setfill('0')
  1574. << (i >> 8) << ":" << std::setw(2) << std::setfill('0')
  1575. << (i & 0x00FF);
  1576. HWAddrPtr hwaddr(new HWAddr(HWAddr::fromText(hwaddr_s.str(),
  1577. HTYPE_ETHER)));
  1578. // Address.
  1579. std::ostringstream address_s;
  1580. address_s << "10.0." << (i >> 8) << "." << (i & 0x00FF);
  1581. IOAddress address(address_s.str());
  1582. // Create lease.
  1583. Lease4Ptr lease(new Lease4(address, hwaddr, ClientIdPtr(), 60, 10, 20,
  1584. time(NULL), SubnetID(1), true, true,
  1585. generateHostnameForLeaseIndex(i)));
  1586. leases_.push_back(lease);
  1587. // Copy the lease before adding it to the lease manager. We want to
  1588. // make sure that modifications to the leases held in the leases_
  1589. // container doesn't affect the leases in the lease manager.
  1590. LeaseMgrFactory::instance().addLease(Lease4Ptr(new Lease4(*lease)));
  1591. // Note in the statistics that this lease has been added.
  1592. StatsMgr& stats_mgr = StatsMgr::instance();
  1593. std::string stat_name = "assigned-addresses";
  1594. stats_mgr.addValue(stats_mgr.generateName("subnet", lease->subnet_id_, stat_name),
  1595. int64_t(1));
  1596. }
  1597. }
  1598. void
  1599. ExpirationAllocEngine4Test::setUniqueClientId(const uint16_t index) {
  1600. std::ostringstream clientid_s;
  1601. clientid_s << "AA:BB:" << std::setw(2) << std::setfill('0')
  1602. << (index >> 8) << ":" << std::setw(2) << std::setfill('0')
  1603. << (index & 0x00FF);
  1604. ClientIdPtr client_id(ClientId::fromText(clientid_s.str()));
  1605. leases_[index]->client_id_ = client_id;
  1606. LeaseMgrFactory::instance().updateLease4(leases_[index]);
  1607. }
  1608. void
  1609. ExpirationAllocEngine4Test::setSubnetId(const uint16_t lease_index, const SubnetID& id) {
  1610. ASSERT_GT(leases_.size(), lease_index);
  1611. if (leases_[lease_index]->subnet_id_ != id) {
  1612. StatsMgr& stats_mgr = StatsMgr::instance();
  1613. stats_mgr.addValue(stats_mgr.generateName("subnet", id, "assigned-addresses"),
  1614. int64_t(1));
  1615. stats_mgr.addValue(stats_mgr.generateName("subnet",
  1616. leases_[lease_index]->subnet_id_,
  1617. "assigned-addresses"),
  1618. int64_t(-1));
  1619. leases_[lease_index]->subnet_id_ = id;
  1620. ASSERT_NO_THROW(updateLease(lease_index));
  1621. }
  1622. }
  1623. void
  1624. ExpirationAllocEngine4Test::transferOwnership(const uint16_t lease_index) {
  1625. ASSERT_GT(leases_.size(), lease_index);
  1626. std::vector<uint8_t> bytes;
  1627. if (leases_[lease_index]->client_id_) {
  1628. bytes = leases_[lease_index]->client_id_->getClientId();
  1629. } else {
  1630. bytes = leases_[lease_index]->hwaddr_->hwaddr_;
  1631. }
  1632. if (!bytes.empty()) {
  1633. if (++bytes[0] == 0) {
  1634. ++bytes[1];
  1635. }
  1636. }
  1637. if (leases_[lease_index]->client_id_) {
  1638. leases_[lease_index]->client_id_.reset(new ClientId(bytes));
  1639. } else {
  1640. leases_[lease_index]->hwaddr_.reset(new HWAddr(bytes, HTYPE_ETHER));
  1641. }
  1642. }
  1643. bool
  1644. ExpirationAllocEngine4Test::dnsUpdateGeneratedFromClientId(const Lease4Ptr& lease) {
  1645. try {
  1646. NameChangeRequestPtr ncr = getNCRForLease(lease);
  1647. if (ncr) {
  1648. if (lease->client_id_) {
  1649. // Generate hostname for this lease. Note that the lease
  1650. // in the database doesn't have the hostname because it
  1651. // has been removed by the lease reclamation routine.
  1652. std::string hostname = generateHostnameForLeaseIndex(
  1653. getLeaseIndexFromAddress(lease->addr_));
  1654. // Get DHCID from NCR.
  1655. const D2Dhcid& dhcid = ncr->getDhcid();
  1656. // Generate reference DHCID to compare with the one from
  1657. // the NCR.
  1658. std::vector<uint8_t> fqdn_wire;
  1659. OptionDataTypeUtil::writeFqdn(hostname, fqdn_wire, true);
  1660. D2Dhcid clientid_dhcid(lease->client_id_->getClientId(),
  1661. fqdn_wire);
  1662. // Return true if they match.
  1663. return (dhcid == clientid_dhcid);
  1664. }
  1665. }
  1666. } catch (...) {
  1667. // If error occurred, treat it as no match.
  1668. return (false);
  1669. }
  1670. // All leases checked - no match.
  1671. return (false);
  1672. }
  1673. bool
  1674. ExpirationAllocEngine4Test::dnsUpdateGeneratedFromHWAddress(const Lease4Ptr& lease) {
  1675. try {
  1676. NameChangeRequestPtr ncr = getNCRForLease(lease);
  1677. if (ncr) {
  1678. if (lease->hwaddr_) {
  1679. // Generate hostname for this lease. Note that the lease
  1680. // in the database doesn't have the hostname because it
  1681. // has been removed by the lease reclamation routine.
  1682. std::string hostname = generateHostnameForLeaseIndex(
  1683. getLeaseIndexFromAddress(lease->addr_));
  1684. // Get DHCID from NCR.
  1685. const D2Dhcid& dhcid = ncr->getDhcid();
  1686. // Generate reference DHCID to compare with the one from
  1687. // the NCR.
  1688. std::vector<uint8_t> fqdn_wire;
  1689. OptionDataTypeUtil::writeFqdn(hostname, fqdn_wire, true);
  1690. D2Dhcid hwaddr_dhcid(lease->hwaddr_, fqdn_wire);
  1691. // Return true if they match.
  1692. return (dhcid == hwaddr_dhcid);
  1693. }
  1694. }
  1695. } catch (...) {
  1696. // If error occurred, treat it as no match.
  1697. return (false);
  1698. }
  1699. // All leases checked - no match.
  1700. return (false);
  1701. }
  1702. void
  1703. ExpirationAllocEngine4Test::testReclaimExpiredLeasesWithDDNSAndClientId() {
  1704. // DNS must be started for the D2 client to accept NCRs.
  1705. ASSERT_NO_THROW(enableDDNS());
  1706. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1707. // Set client identifiers for leases with even indexes only.
  1708. if (evenLeaseIndex(i)) {
  1709. setUniqueClientId(i);
  1710. }
  1711. // Expire all leases. The higher the index, the more expired the lease.
  1712. expire(i, 10 + i);
  1713. }
  1714. // Reclaim all expired leases.
  1715. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, false));
  1716. // Leases with even indexes should be reclaimed.
  1717. EXPECT_TRUE(testLeases(&leaseReclaimed, &evenLeaseIndex));
  1718. // DNS updates (removal NCRs) should be generated for all leases.
  1719. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedForLease, &allLeaseIndexes));
  1720. // Leases with even indexes include client identifiers so the DHCID should
  1721. // be generated from the client identifiers.
  1722. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedFromClientId, &evenLeaseIndex));
  1723. // Leases with odd indexes do not include client identifiers so their
  1724. // DHCID should be generated from the HW address.
  1725. EXPECT_TRUE(testLeases(&dnsUpdateGeneratedFromHWAddress, &oddLeaseIndex));
  1726. }
  1727. void
  1728. ExpirationAllocEngine4Test::testReclaimExpiredLeasesStats() {
  1729. // This test requires that the number of leases is an even number.
  1730. BOOST_STATIC_ASSERT(TEST_LEASES_NUM % 2 == 0);
  1731. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1732. // Mark all leaes as expired. The higher the index the less
  1733. // expired the lease.
  1734. expire(i, 1000 - i);
  1735. // Modify subnet ids of some leases.
  1736. if (evenLeaseIndex(i)) {
  1737. setSubnetId(i, 2);
  1738. }
  1739. }
  1740. // Leases will be reclaimed in groups of 8.
  1741. const size_t reclamation_group_size = 8;
  1742. for (unsigned int i = reclamation_group_size; i < TEST_LEASES_NUM;
  1743. i += reclamation_group_size) {
  1744. // Reclaim 8 most expired leases out of TEST_LEASES_NUM.
  1745. ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size,
  1746. 0, false));
  1747. // Number of reclaimed leases should increase as we loop.
  1748. EXPECT_TRUE(testStatistics("reclaimed-leases", i));
  1749. // Make sure that the number of reclaimed leases is also distributed
  1750. // across two subnets.
  1751. EXPECT_TRUE(testStatistics("subnet[1].reclaimed-leases", i / 2));
  1752. EXPECT_TRUE(testStatistics("subnet[2].reclaimed-leases", i / 2));
  1753. // Number of assigned leases should decrease as we reclaim them.
  1754. EXPECT_TRUE(testStatistics("subnet[1].assigned-addresses",
  1755. (TEST_LEASES_NUM - i) / 2));
  1756. EXPECT_TRUE(testStatistics("subnet[2].assigned-addresses",
  1757. (TEST_LEASES_NUM - i) / 2));
  1758. }
  1759. }
  1760. void
  1761. ExpirationAllocEngine4Test::testReclaimReusedLeases(const uint8_t msg_type,
  1762. const bool client_renews,
  1763. const bool use_reclaimed) {
  1764. // Let's restrict the number of leases.
  1765. BOOST_STATIC_ASSERT(TEST_LEASES_NUM < 1000);
  1766. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1767. // Depending on the parameter, mark leases 'expired-reclaimed' or
  1768. // simply 'expired'.
  1769. if (use_reclaimed) {
  1770. reclaim(i, 1000 - i);
  1771. } else {
  1772. // Mark all leases as expired.
  1773. expire(i, 1000 - i);
  1774. }
  1775. // Check if we're simulating renewals or reusing leases. If this is
  1776. // about reusing leases, we should be using different MAC addresses
  1777. // or client identifiers for the leases than those stored presently
  1778. // in the database.
  1779. if (!client_renews) {
  1780. // This function modifies the MAC address or the client identifier
  1781. // of the test lease to make sure it doesn't match the one we
  1782. // have in the database.
  1783. transferOwnership(i);
  1784. }
  1785. }
  1786. // The call to AllocEngine::allocateLease4 requires the subnet selection.
  1787. // The pool must be present within a subnet for the allocation engine to
  1788. // hand out address from.
  1789. Subnet4Ptr subnet(new Subnet4(IOAddress("10.0.0.0"), 16, 10, 20, 60, SubnetID(1)));
  1790. ASSERT_NO_THROW(subnet->addPool(Pool4Ptr(new Pool4(IOAddress("10.0.0.0"),
  1791. IOAddress("10.0.255.255")))));
  1792. // Re-allocate leases (reuse or renew).
  1793. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1794. // Build the context.
  1795. AllocEngine::ClientContext4 ctx(subnet, leases_[i]->client_id_,
  1796. leases_[i]->hwaddr_,
  1797. leases_[i]->addr_, false, false,
  1798. leases_[i]->hostname_,
  1799. msg_type == DHCPDISCOVER);
  1800. // Query is needed for logging purposes.
  1801. ctx.query_.reset(new Pkt4(msg_type, 0x1234));
  1802. // Re-allocate a lease. Note that the iterative will pick addresses
  1803. // starting from the beginning of the pool. This matches exactly
  1804. // the set of addresses we have allocated and stored in the database.
  1805. // Since all leases are marked expired the allocation engine will
  1806. // reuse them or renew them as appropriate.
  1807. ASSERT_NO_THROW(engine_->allocateLease4(ctx));
  1808. }
  1809. // If DHCPDISCOVER is being processed, the leases should not be reclaimed.
  1810. // Also, the leases should not be reclaimed if they are already in the
  1811. // 'expired-reclaimed' state.
  1812. if (use_reclaimed || (msg_type == DHCPDISCOVER)) {
  1813. EXPECT_TRUE(testStatistics("reclaimed-leases", 0));
  1814. } else if (msg_type == DHCPREQUEST) {
  1815. // Re-allocation of expired leases should result in reclamations.
  1816. EXPECT_TRUE(testStatistics("reclaimed-leases", TEST_LEASES_NUM));
  1817. // Leases should have been updated in the lease database and their
  1818. // state should not be 'expired-reclaimed' anymore.
  1819. EXPECT_TRUE(testLeases(&leaseNotReclaimed, &allLeaseIndexes));
  1820. }
  1821. }
  1822. void
  1823. ExpirationAllocEngine4Test::testReclaimDeclinedHook(bool skip) {
  1824. for (unsigned int i = 0; i < TEST_LEASES_NUM; ++i) {
  1825. // Mark leases with even indexes as expired.
  1826. if (evenLeaseIndex(i)) {
  1827. // Mark lease as declined with 100 seconds of probation-period
  1828. // (i.e. lease is supposed to be off limits for 100 seconds)
  1829. decline(i, 100);
  1830. // The higher the index, the more expired the lease.
  1831. expire(i, 10 + i);
  1832. }
  1833. }
  1834. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  1835. "lease4_recover",
  1836. skip ? lease4RecoverSkipCallout : lease4RecoverCallout));
  1837. // Run leases reclamation routine on all leases.
  1838. ASSERT_NO_THROW(reclaimExpiredLeases(0, 0, true));
  1839. // Make sure that the callout really was called. It was supposed to modify
  1840. // the callout_name_ and store the lease in callout_lease_
  1841. EXPECT_EQ("lease4_recover", callout_name_);
  1842. EXPECT_TRUE(callout_lease_);
  1843. // Leases with even indexes should not exist in the DB
  1844. if (skip) {
  1845. // Skip status should have prevented removing the lease.
  1846. EXPECT_TRUE(testLeases(&leaseExists, &evenLeaseIndex));
  1847. } else {
  1848. // The hook hasn't modified next step status. The lease should be gone.
  1849. EXPECT_TRUE(testLeases(&leaseDoesntExist, &evenLeaseIndex));
  1850. }
  1851. };
  1852. // This test verifies that the leases can be reclaimed without being removed
  1853. // from the database. In such case, the leases' state is set to
  1854. // "expired-reclaimed".
  1855. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesUpdateState) {
  1856. testReclaimExpiredLeasesUpdateState();
  1857. }
  1858. // This test verifies that the reclaimed leases are deleted when requested.
  1859. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesDelete) {
  1860. testReclaimExpiredLeasesDelete();
  1861. }
  1862. // This test verifies that it is possible to specify the limit for the
  1863. // number of reclaimed leases.
  1864. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesLimit) {
  1865. testReclaimExpiredLeasesLimit();
  1866. }
  1867. // This test verifies that DNS updates are generated for the leases
  1868. // for which the DNS records exist.
  1869. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesWithDDNS) {
  1870. testReclaimExpiredLeasesWithDDNS();
  1871. }
  1872. // This test verifies that it is DNS updates are generated only for the
  1873. // reclaimed expired leases. In this case we limit the number of leases
  1874. // reclaimed during a single call to reclamation routine.
  1875. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesWithDDNSAndLimit) {
  1876. testReclaimExpiredLeasesWithDDNSAndLimit();
  1877. }
  1878. // This test verifies that if some leases have invalid hostnames, the
  1879. // lease reclamation routine continues with reclamation of leases anyway.
  1880. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesInvalidHostname) {
  1881. testReclaimExpiredLeasesInvalidHostname();
  1882. }
  1883. // This test verifies that DNS updates are properly generated when the
  1884. // client id is used as a primary identifier in the lease.
  1885. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesWithDDNSAndClientId) {
  1886. testReclaimExpiredLeasesWithDDNSAndClientId();
  1887. }
  1888. // This test verifies that statistics is correctly updated when the leases
  1889. // are reclaimed.
  1890. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesStats) {
  1891. testReclaimExpiredLeasesStats();
  1892. }
  1893. // This test verifies that callouts are executed for each expired lease.
  1894. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesHooks) {
  1895. testReclaimExpiredLeasesHooks();
  1896. }
  1897. // This test verifies that callouts are executed for each expired lease
  1898. // and that the lease is not reclaimed when the skip flag is set.
  1899. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesHooksWithSkip) {
  1900. testReclaimExpiredLeasesHooksWithSkip();
  1901. }
  1902. // This test verifies that it is possible to set the timeout for the
  1903. // execution of the lease reclamation routine.
  1904. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesTimeout) {
  1905. // This test needs at least 40 leases to make sense.
  1906. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 40);
  1907. // Run with timeout of 1.2s.
  1908. testReclaimExpiredLeasesTimeout(1200);
  1909. }
  1910. // This test verifies that at least one lease is reclaimed if the timeout
  1911. // for the lease reclamation routine is shorter than the time needed for
  1912. // the reclamation of a single lease. This prevents the situation when
  1913. // very short timeout (perhaps misconfigured) effectively precludes leases
  1914. // reclamation.
  1915. TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesShortTimeout) {
  1916. // We will most likely reclaim just one lease, so 5 is more than enough.
  1917. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 5);
  1918. // Reclaim leases with the 1ms timeout.
  1919. testReclaimExpiredLeasesTimeout(1);
  1920. }
  1921. // This test verifies that expired-reclaimed leases are removed from the
  1922. // lease database.
  1923. TEST_F(ExpirationAllocEngine4Test, deleteExpiredReclaimedLeases) {
  1924. BOOST_STATIC_ASSERT(TEST_LEASES_NUM >= 10);
  1925. testDeleteExpiredReclaimedLeases();
  1926. }
  1927. /// This test verifies that @ref AllocEngine::reclaimExpiredLeases4 properly
  1928. /// handles declined leases that have expired in case when it is told to
  1929. /// remove leases.
  1930. TEST_F(ExpirationAllocEngine4Test, reclaimDeclined1) {
  1931. testReclaimDeclined(true);
  1932. }
  1933. /// This test verifies that @ref AllocEngine::reclaimExpiredLeases4 properly
  1934. /// handles declined leases that have expired in case when it is told to
  1935. /// not remove leases. This flag should not matter and declined expired
  1936. /// leases should always be removed.
  1937. TEST_F(ExpirationAllocEngine4Test, reclaimDeclined2) {
  1938. testReclaimDeclined(false);
  1939. }
  1940. /// This test verifies that statistics are modified correctly after
  1941. /// reclaim expired leases is called.
  1942. TEST_F(ExpirationAllocEngine4Test, reclaimDeclinedStats) {
  1943. testReclaimDeclinedStats("assigned-addresses");
  1944. }
  1945. // This test verifies that the lease is reclaimed before it is reused.
  1946. TEST_F(ExpirationAllocEngine4Test, reclaimReusedLeases) {
  1947. // First false value indicates that the leases will be reused.
  1948. // Second false value indicates that the lease will not be
  1949. // initially reclaimed.
  1950. testReclaimReusedLeases(DHCPREQUEST, false, false);
  1951. }
  1952. // This test verifies that the lease is not reclaimed when it is
  1953. // reused and if its state indicates that it has been already reclaimed.
  1954. TEST_F(ExpirationAllocEngine4Test, reclaimReusedLeasesAlreadyReclaimed) {
  1955. // false value indicates that the leases will be reused
  1956. // true value indicates that the lease will be initially reclaimed.
  1957. testReclaimReusedLeases(DHCPREQUEST, false, true);
  1958. }
  1959. // This test verifies that the expired lease is reclaimed before it
  1960. // is renewed.
  1961. TEST_F(ExpirationAllocEngine4Test, reclaimRenewedLeases) {
  1962. // true value indicates that the leases will be renewed.
  1963. // false value indicates that the lease will not be initially
  1964. // reclaimed.
  1965. testReclaimReusedLeases(DHCPREQUEST, true, false);
  1966. }
  1967. // This test verifies that the lease is not reclaimed upon renewal
  1968. // if its state indicates that it has been already reclaimed.
  1969. TEST_F(ExpirationAllocEngine4Test, reclaimRenewedLeasesAlreadyReclaimed) {
  1970. // First true value indicates that the leases will be renewed.
  1971. // Second true value indicates that the lease will be initially
  1972. // reclaimed.
  1973. testReclaimReusedLeases(DHCPREQUEST, true, true);
  1974. }
  1975. // This test verifies that the reused lease is not reclaimed when the
  1976. // processed message is a DHCPDISCOVER.
  1977. TEST_F(ExpirationAllocEngine4Test, reclaimReusedLeasesDiscover) {
  1978. testReclaimReusedLeases(DHCPDISCOVER, false, false);
  1979. }
  1980. // This test verifies that the lease being in the 'expired-reclaimed'
  1981. // state is not reclaimed again when processing the DHCPDISCOVER
  1982. // message.
  1983. TEST_F(ExpirationAllocEngine4Test, reclaimRenewedLeasesDiscoverAlreadyReclaimed) {
  1984. testReclaimReusedLeases(DHCPDISCOVER, false, true);
  1985. }
  1986. // This test verifies if the hooks installed on lease4_recover are called
  1987. // when the lease expires.
  1988. TEST_F(ExpirationAllocEngine4Test, reclaimDeclinedHook1) {
  1989. testReclaimDeclinedHook(false); // false = don't use skip callout
  1990. }
  1991. // This test verifies if the hooks installed on lease4_recover are called
  1992. // when the lease expires and that the next step status set to SKIP
  1993. // causes the recovery to not be conducted.
  1994. TEST_F(ExpirationAllocEngine4Test, reclaimDeclinedHook2) {
  1995. testReclaimDeclinedHook(true); // true = use skip callout
  1996. }
  1997. }; // end of anonymous namespace