alloc_engine_hooks_unittest.cc 18 KB

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