alloc_engine_hooks_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcpsrv/tests/alloc_engine_utils.h>
  16. #include <dhcpsrv/tests/test_utils.h>
  17. #include <hooks/server_hooks.h>
  18. #include <hooks/callout_manager.h>
  19. #include <hooks/hooks_manager.h>
  20. using namespace std;
  21. using namespace isc::hooks;
  22. using namespace isc::asiolink;
  23. namespace isc {
  24. namespace dhcp {
  25. namespace test {
  26. /// @brief helper class used in Hooks testing in AllocEngine6
  27. ///
  28. /// It features a couple of callout functions and buffers to store
  29. /// the data that is accessible via callouts.
  30. class HookAllocEngine6Test : public AllocEngine6Test {
  31. public:
  32. HookAllocEngine6Test() {
  33. resetCalloutBuffers();
  34. }
  35. virtual ~HookAllocEngine6Test() {
  36. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
  37. "lease6_select");
  38. }
  39. /// @brief clears out buffers, so callouts can store received arguments
  40. void resetCalloutBuffers() {
  41. callback_name_ = string("");
  42. callback_subnet6_.reset();
  43. callback_fake_allocation_ = false;
  44. callback_lease6_.reset();
  45. callback_argument_names_.clear();
  46. callback_addr_original_ = IOAddress("::");
  47. callback_addr_updated_ = IOAddress("::");
  48. }
  49. /// callback that stores received callout name and received values
  50. static int
  51. lease6_select_callout(CalloutHandle& callout_handle) {
  52. callback_name_ = string("lease6_select");
  53. callout_handle.getArgument("subnet6", callback_subnet6_);
  54. callout_handle.getArgument("fake_allocation", callback_fake_allocation_);
  55. callout_handle.getArgument("lease6", callback_lease6_);
  56. callback_addr_original_ = callback_lease6_->addr_;
  57. callback_argument_names_ = callout_handle.getArgumentNames();
  58. return (0);
  59. }
  60. /// callback that overrides the lease with different values
  61. static int
  62. lease6_select_different_callout(CalloutHandle& callout_handle) {
  63. // Let's call the basic callout, so it can record all parameters
  64. lease6_select_callout(callout_handle);
  65. // Now we need to tweak the least a bit
  66. Lease6Ptr lease;
  67. callout_handle.getArgument("lease6", lease);
  68. callback_addr_updated_ = addr_override_;
  69. lease->addr_ = callback_addr_updated_;
  70. lease->t1_ = t1_override_;
  71. lease->t2_ = t2_override_;
  72. lease->preferred_lft_ = pref_override_;
  73. lease->valid_lft_ = valid_override_;
  74. return (0);
  75. }
  76. // Values to be used in callout to override lease6 content
  77. static const IOAddress addr_override_;
  78. static const uint32_t t1_override_;
  79. static const uint32_t t2_override_;
  80. static const uint32_t pref_override_;
  81. static const uint32_t valid_override_;
  82. // Callback will store original and overridden values here
  83. static IOAddress callback_addr_original_;
  84. static IOAddress callback_addr_updated_;
  85. // Buffers (callback will store received values here)
  86. static string callback_name_;
  87. static Subnet6Ptr callback_subnet6_;
  88. static Lease6Ptr callback_lease6_;
  89. static bool callback_fake_allocation_;
  90. static vector<string> callback_argument_names_;
  91. };
  92. // For some reason intialization within a class makes the linker confused.
  93. // linker complains about undefined references if they are defined within
  94. // the class declaration.
  95. const IOAddress HookAllocEngine6Test::addr_override_("2001:db8::abcd");
  96. const uint32_t HookAllocEngine6Test::t1_override_ = 6000;
  97. const uint32_t HookAllocEngine6Test::t2_override_ = 7000;
  98. const uint32_t HookAllocEngine6Test::pref_override_ = 8000;
  99. const uint32_t HookAllocEngine6Test::valid_override_ = 9000;
  100. IOAddress HookAllocEngine6Test::callback_addr_original_("::");
  101. IOAddress HookAllocEngine6Test::callback_addr_updated_("::");
  102. string HookAllocEngine6Test::callback_name_;
  103. Subnet6Ptr HookAllocEngine6Test::callback_subnet6_;
  104. Lease6Ptr HookAllocEngine6Test::callback_lease6_;
  105. bool HookAllocEngine6Test::callback_fake_allocation_;
  106. vector<string> HookAllocEngine6Test::callback_argument_names_;
  107. // This test checks if the lease6_select callout is executed and expected
  108. // parameters as passed.
  109. TEST_F(HookAllocEngine6Test, lease6_select) {
  110. // Note: The following order is working as expected:
  111. // 1. create AllocEngine (that register hook points)
  112. // 2. call loadLibraries()
  113. //
  114. // This order, however, causes segfault in HooksManager
  115. // 1. call loadLibraries()
  116. // 2. create AllocEngine (that register hook points)
  117. // Create allocation engine (hook names are registered in its ctor)
  118. boost::scoped_ptr<AllocEngine> engine;
  119. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  120. ASSERT_TRUE(engine);
  121. // Initialize Hooks Manager
  122. vector<string> libraries; // no libraries at this time
  123. HooksManager::loadLibraries(libraries);
  124. // Install pkt6_receive_callout
  125. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  126. "lease6_select", lease6_select_callout));
  127. CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
  128. Lease6Ptr lease;
  129. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
  130. Lease::TYPE_NA, false, false, "", false);
  131. ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234));
  132. ctx.callout_handle_ = callout_handle;
  133. EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
  134. // Check that we got a lease
  135. ASSERT_TRUE(lease);
  136. // Do all checks on the lease
  137. checkLease6(lease, Lease::TYPE_NA, 128);
  138. // Check that the lease is indeed in LeaseMgr
  139. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
  140. lease->addr_);
  141. ASSERT_TRUE(from_mgr);
  142. // Check that callouts were indeed called
  143. EXPECT_EQ("lease6_select", callback_name_);
  144. // Now check that the lease in LeaseMgr has the same parameters
  145. ASSERT_TRUE(callback_lease6_);
  146. detailCompareLease(callback_lease6_, from_mgr);
  147. ASSERT_TRUE(callback_subnet6_);
  148. EXPECT_EQ(subnet_->toText(), callback_subnet6_->toText());
  149. EXPECT_FALSE(callback_fake_allocation_);
  150. // Check if all expected parameters are reported. It's a bit tricky, because
  151. // order may be different. If the test starts failing, because someone tweaked
  152. // hooks engine, we'll have to implement proper vector matching (ignoring order)
  153. vector<string> expected_argument_names;
  154. expected_argument_names.push_back("fake_allocation");
  155. expected_argument_names.push_back("lease6");
  156. expected_argument_names.push_back("subnet6");
  157. sort(callback_argument_names_.begin(), callback_argument_names_.end());
  158. sort(expected_argument_names.begin(), expected_argument_names.end());
  159. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  160. }
  161. // This test checks if lease6_select callout is able to override the values
  162. // in a lease6.
  163. TEST_F(HookAllocEngine6Test, change_lease6_select) {
  164. // Make sure that the overridden values are different than the ones from
  165. // subnet originally used to create the lease
  166. ASSERT_NE(t1_override_, subnet_->getT1());
  167. ASSERT_NE(t2_override_, subnet_->getT2());
  168. ASSERT_NE(pref_override_, subnet_->getPreferred());
  169. ASSERT_NE(valid_override_, subnet_->getValid());
  170. ASSERT_FALSE(subnet_->inRange(addr_override_));
  171. // Create allocation engine (hook names are registered in its ctor)
  172. boost::scoped_ptr<AllocEngine> engine;
  173. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  174. ASSERT_TRUE(engine);
  175. // Initialize Hooks Manager
  176. vector<string> libraries; // no libraries at this time
  177. HooksManager::loadLibraries(libraries);
  178. // Install a callout
  179. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  180. "lease6_select", lease6_select_different_callout));
  181. // Normally, dhcpv6_srv would passed the handle when calling allocateLeases6,
  182. // but in tests we need to create it on our own.
  183. CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
  184. // Call allocateLeases6. Callouts should be triggered here.
  185. Lease6Ptr lease;
  186. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
  187. Lease::TYPE_NA, false, false, "", false);
  188. ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234));
  189. ctx.callout_handle_ = callout_handle;
  190. EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
  191. // Check that we got a lease
  192. ASSERT_TRUE(lease);
  193. // See if the values overridden by callout are there
  194. EXPECT_TRUE(lease->addr_.equals(addr_override_));
  195. EXPECT_EQ(t1_override_, lease->t1_);
  196. EXPECT_EQ(t2_override_, lease->t2_);
  197. EXPECT_EQ(pref_override_, lease->preferred_lft_);
  198. EXPECT_EQ(valid_override_, lease->valid_lft_);
  199. // Now check if the lease is in the database
  200. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
  201. lease->addr_);
  202. ASSERT_TRUE(from_mgr);
  203. // Check if values in the database are overridden
  204. EXPECT_TRUE(from_mgr->addr_.equals(addr_override_));
  205. EXPECT_EQ(t1_override_, from_mgr->t1_);
  206. EXPECT_EQ(t2_override_, from_mgr->t2_);
  207. EXPECT_EQ(pref_override_, from_mgr->preferred_lft_);
  208. EXPECT_EQ(valid_override_, from_mgr->valid_lft_);
  209. }
  210. /// @brief helper class used in Hooks testing in AllocEngine4
  211. ///
  212. /// It features a couple of callout functions and buffers to store
  213. /// the data that is accessible via callouts.
  214. ///
  215. /// Note: lease4_renew callout is tested from DHCPv4 server.
  216. /// See HooksDhcpv4SrvTest.basic_lease4_renew in
  217. /// src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
  218. class HookAllocEngine4Test : public AllocEngine4Test {
  219. public:
  220. HookAllocEngine4Test() {
  221. resetCalloutBuffers();
  222. }
  223. virtual ~HookAllocEngine4Test() {
  224. HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
  225. "lease4_select");
  226. }
  227. /// @brief clears out buffers, so callouts can store received arguments
  228. void resetCalloutBuffers() {
  229. callback_name_ = string("");
  230. callback_subnet4_.reset();
  231. callback_fake_allocation_ = false;
  232. callback_lease4_.reset();
  233. callback_argument_names_.clear();
  234. callback_addr_original_ = IOAddress("::");
  235. callback_addr_updated_ = IOAddress("::");
  236. }
  237. /// callback that stores received callout name and received values
  238. static int
  239. lease4_select_callout(CalloutHandle& callout_handle) {
  240. callback_name_ = string("lease4_select");
  241. callout_handle.getArgument("subnet4", callback_subnet4_);
  242. callout_handle.getArgument("fake_allocation", callback_fake_allocation_);
  243. callout_handle.getArgument("lease4", callback_lease4_);
  244. callback_addr_original_ = callback_lease4_->addr_;
  245. callback_argument_names_ = callout_handle.getArgumentNames();
  246. return (0);
  247. }
  248. /// callback that overrides the lease with different values
  249. static int
  250. lease4_select_different_callout(CalloutHandle& callout_handle) {
  251. // Let's call the basic callout, so it can record all parameters
  252. lease4_select_callout(callout_handle);
  253. // Now we need to tweak the least a bit
  254. Lease4Ptr lease;
  255. callout_handle.getArgument("lease4", lease);
  256. callback_addr_updated_ = addr_override_;
  257. lease->addr_ = callback_addr_updated_;
  258. lease->t1_ = t1_override_;
  259. lease->t2_ = t2_override_;
  260. lease->valid_lft_ = valid_override_;
  261. return (0);
  262. }
  263. // Values to be used in callout to override lease4 content
  264. static const IOAddress addr_override_;
  265. static const uint32_t t1_override_;
  266. static const uint32_t t2_override_;
  267. static const uint32_t valid_override_;
  268. // Callback will store original and overridden values here
  269. static IOAddress callback_addr_original_;
  270. static IOAddress callback_addr_updated_;
  271. // Buffers (callback will store received values here)
  272. static string callback_name_;
  273. static Subnet4Ptr callback_subnet4_;
  274. static Lease4Ptr callback_lease4_;
  275. static bool callback_fake_allocation_;
  276. static vector<string> callback_argument_names_;
  277. };
  278. // For some reason intialization within a class makes the linker confused.
  279. // linker complains about undefined references if they are defined within
  280. // the class declaration.
  281. const IOAddress HookAllocEngine4Test::addr_override_("192.0.3.1");
  282. const uint32_t HookAllocEngine4Test::t1_override_ = 4000;
  283. const uint32_t HookAllocEngine4Test::t2_override_ = 7000;
  284. const uint32_t HookAllocEngine4Test::valid_override_ = 9000;
  285. IOAddress HookAllocEngine4Test::callback_addr_original_("::");
  286. IOAddress HookAllocEngine4Test::callback_addr_updated_("::");
  287. string HookAllocEngine4Test::callback_name_;
  288. Subnet4Ptr HookAllocEngine4Test::callback_subnet4_;
  289. Lease4Ptr HookAllocEngine4Test::callback_lease4_;
  290. bool HookAllocEngine4Test::callback_fake_allocation_;
  291. vector<string> HookAllocEngine4Test::callback_argument_names_;
  292. // This test checks if the lease4_select callout is executed and expected
  293. // parameters as passed.
  294. TEST_F(HookAllocEngine4Test, lease4_select) {
  295. // Note: The following order is working as expected:
  296. // 1. create AllocEngine (that register hook points)
  297. // 2. call loadLibraries()
  298. //
  299. // This order, however, causes segfault in HooksManager
  300. // 1. call loadLibraries()
  301. // 2. create AllocEngine (that register hook points)
  302. // Create allocation engine (hook names are registered in its ctor)
  303. boost::scoped_ptr<AllocEngine> engine;
  304. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
  305. 100, false)));
  306. ASSERT_TRUE(engine);
  307. // Initialize Hooks Manager
  308. vector<string> libraries; // no libraries at this time
  309. HooksManager::loadLibraries(libraries);
  310. // Install pkt4_receive_callout
  311. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  312. "lease4_select", lease4_select_callout));
  313. CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
  314. AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_,
  315. IOAddress("0.0.0.0"),
  316. false, false, "", false);
  317. ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
  318. ctx.callout_handle_ = callout_handle;
  319. Lease4Ptr lease = engine->allocateLease4(ctx);
  320. // Check that we got a lease
  321. ASSERT_TRUE(lease);
  322. // Do all checks on the lease
  323. checkLease4(lease);
  324. // Check that the lease is indeed in LeaseMgr
  325. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  326. ASSERT_TRUE(from_mgr);
  327. // Check that callouts were indeed called
  328. EXPECT_EQ("lease4_select", callback_name_);
  329. // Now check that the lease in LeaseMgr has the same parameters
  330. ASSERT_TRUE(callback_lease4_);
  331. detailCompareLease(callback_lease4_, from_mgr);
  332. ASSERT_TRUE(callback_subnet4_);
  333. EXPECT_EQ(subnet_->toText(), callback_subnet4_->toText());
  334. EXPECT_EQ(callback_fake_allocation_, false);
  335. // Check if all expected parameters are reported. It's a bit tricky, because
  336. // order may be different. If the test starts failing, because someone tweaked
  337. // hooks engine, we'll have to implement proper vector matching (ignoring order)
  338. vector<string> expected_argument_names;
  339. expected_argument_names.push_back("fake_allocation");
  340. expected_argument_names.push_back("lease4");
  341. expected_argument_names.push_back("subnet4");
  342. EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
  343. }
  344. // This test checks if lease4_select callout is able to override the values
  345. // in a lease4.
  346. TEST_F(HookAllocEngine4Test, change_lease4_select) {
  347. // Make sure that the overridden values are different than the ones from
  348. // subnet originally used to create the lease
  349. ASSERT_NE(t1_override_, subnet_->getT1());
  350. ASSERT_NE(t2_override_, subnet_->getT2());
  351. ASSERT_NE(valid_override_, subnet_->getValid());
  352. ASSERT_FALSE(subnet_->inRange(addr_override_));
  353. // Create allocation engine (hook names are registered in its ctor)
  354. boost::scoped_ptr<AllocEngine> engine;
  355. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
  356. 100, false)));
  357. ASSERT_TRUE(engine);
  358. // Initialize Hooks Manager
  359. vector<string> libraries; // no libraries at this time
  360. HooksManager::loadLibraries(libraries);
  361. // Install a callout
  362. EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
  363. "lease4_select", lease4_select_different_callout));
  364. // Normally, dhcpv4_srv would passed the handle when calling allocateLease4,
  365. // but in tests we need to create it on our own.
  366. CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
  367. AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
  368. false, true, "somehost.example.com.", false);
  369. ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
  370. ctx.callout_handle_ = callout_handle;
  371. // Call allocateLease4. Callouts should be triggered here.
  372. Lease4Ptr lease = engine->allocateLease4(ctx);
  373. // Check that we got a lease
  374. ASSERT_TRUE(lease);
  375. // See if the values overridden by callout are there
  376. EXPECT_TRUE(lease->addr_.equals(addr_override_));
  377. EXPECT_EQ(t1_override_, lease->t1_);
  378. EXPECT_EQ(t2_override_, lease->t2_);
  379. EXPECT_EQ(valid_override_, lease->valid_lft_);
  380. // Now check if the lease is in the database
  381. Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
  382. ASSERT_TRUE(from_mgr);
  383. // Check if values in the database are overridden
  384. EXPECT_TRUE(from_mgr->addr_.equals(addr_override_));
  385. EXPECT_EQ(t1_override_, from_mgr->t1_);
  386. EXPECT_EQ(t2_override_, from_mgr->t2_);
  387. EXPECT_EQ(valid_override_, from_mgr->valid_lft_);
  388. }
  389. }; // namespace test
  390. }; // namespace dhcp
  391. }; // namespace isc