alloc_engine_utils.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. // Copyright (C) 2012-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 <dhcp/duid.h>
  16. #include <dhcp/dhcp4.h>
  17. #include <dhcp/dhcp6.h>
  18. #include <dhcp/pkt4.h>
  19. #include <dhcp/pkt6.h>
  20. #include <dhcpsrv/host_mgr.h>
  21. #include <dhcpsrv/lease_mgr.h>
  22. #include <dhcpsrv/memfile_lease_mgr.h>
  23. #include <dhcpsrv/tests/test_utils.h>
  24. #include <dhcpsrv/tests/alloc_engine_utils.h>
  25. #include <hooks/hooks_manager.h>
  26. #include <boost/shared_ptr.hpp>
  27. #include <boost/scoped_ptr.hpp>
  28. #include <iostream>
  29. #include <sstream>
  30. #include <algorithm>
  31. #include <set>
  32. #include <time.h>
  33. using namespace std;
  34. using namespace isc::hooks;
  35. using namespace isc::asiolink;
  36. namespace isc {
  37. namespace dhcp {
  38. namespace test {
  39. AllocEngine6Test::AllocEngine6Test() {
  40. CfgMgr::instance().clear();
  41. duid_ = DuidPtr(new DUID(std::vector<uint8_t>(8, 0x42)));
  42. iaid_ = 42;
  43. // Let's use odd hardware type to check if there is no Ethernet
  44. // hardcoded anywhere.
  45. const uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
  46. hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
  47. // Initialize a subnet and short address pool.
  48. initSubnet(IOAddress("2001:db8:1::"),
  49. IOAddress("2001:db8:1::10"),
  50. IOAddress("2001:db8:1::20"));
  51. initFqdn("", false, false);
  52. factory_.create("type=memfile universe=6 persist=false");
  53. }
  54. void
  55. AllocEngine6Test::initSubnet(const asiolink::IOAddress& subnet,
  56. const asiolink::IOAddress& pool_start,
  57. const asiolink::IOAddress& pool_end) {
  58. CfgMgr& cfg_mgr = CfgMgr::instance();
  59. subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
  60. pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
  61. subnet_->addPool(pool_);
  62. pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, subnet, 56, 64));
  63. subnet_->addPool(pd_pool_);
  64. cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
  65. cfg_mgr.commit();
  66. }
  67. void
  68. AllocEngine6Test::findReservation(AllocEngine& engine,
  69. AllocEngine::ClientContext6& ctx) {
  70. engine.findReservation(ctx);
  71. // Let's check whether there's a hostname specified in the reservation
  72. if (ctx.host_) {
  73. std::string hostname = ctx.host_->getHostname();
  74. // If there is, let's use it
  75. if (!hostname.empty()) {
  76. ctx.hostname_ = hostname;
  77. }
  78. }
  79. }
  80. HostPtr
  81. AllocEngine6Test::createHost6HWAddr(bool add_to_host_mgr, IPv6Resrv::Type type,
  82. HWAddrPtr& hwaddr, const asiolink::IOAddress& addr,
  83. uint8_t prefix_len) {
  84. HostPtr host(new Host(&hwaddr->hwaddr_[0], hwaddr->hwaddr_.size(),
  85. Host::IDENT_HWADDR, SubnetID(0), subnet_->getID(),
  86. asiolink::IOAddress("0.0.0.0")));
  87. IPv6Resrv resv(type, addr, prefix_len);
  88. host->addReservation(resv);
  89. if (add_to_host_mgr) {
  90. CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
  91. CfgMgr::instance().commit();
  92. }
  93. return (host);
  94. }
  95. Lease6Collection
  96. AllocEngine6Test::allocateTest(AllocEngine& engine, const Pool6Ptr& pool,
  97. const asiolink::IOAddress& hint, bool fake,
  98. bool in_pool) {
  99. Lease::Type type = pool->getType();
  100. uint8_t expected_len = pool->getLength();
  101. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type,
  102. false, false, "", fake);
  103. ctx.query_.reset(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234));
  104. Lease6Collection leases;
  105. findReservation(engine, ctx);
  106. EXPECT_NO_THROW(leases = engine.allocateLeases6(ctx));
  107. for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
  108. // Do all checks on the lease
  109. checkLease6(*it, type, expected_len, in_pool, in_pool);
  110. // Check that the lease is indeed in LeaseMgr
  111. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
  112. (*it)->addr_);
  113. if (!fake) {
  114. // This is a real (REQUEST) allocation, the lease must be in the DB
  115. EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
  116. << " returned by allocateLeases6(), "
  117. << "but was not present in LeaseMgr";
  118. if (!from_mgr) {
  119. return (leases);
  120. }
  121. // Now check that the lease in LeaseMgr has the same parameters
  122. detailCompareLease(*it, from_mgr);
  123. } else {
  124. // This is a fake (SOLICIT) allocation, the lease must not be in DB
  125. EXPECT_FALSE(from_mgr) << "Lease " << from_mgr->addr_.toText()
  126. << " returned by allocateLeases6(), "
  127. << "was present in LeaseMgr (expected to be"
  128. << " not present)";
  129. if (from_mgr) {
  130. return (leases);
  131. }
  132. }
  133. }
  134. return (leases);
  135. }
  136. Lease6Ptr
  137. AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
  138. bool fake, bool in_pool) {
  139. Lease::Type type = pool->getType();
  140. uint8_t expected_len = pool->getLength();
  141. boost::scoped_ptr<AllocEngine> engine;
  142. EXPECT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
  143. 100)));
  144. // We can't use ASSERT macros in non-void methods
  145. EXPECT_TRUE(engine);
  146. if (!engine) {
  147. return (Lease6Ptr());
  148. }
  149. Lease6Ptr lease;
  150. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type,
  151. false, false, "", fake);
  152. ctx.hwaddr_ = hwaddr_;
  153. ctx.query_.reset(new Pkt6(fake ? DHCPV6_SOLICIT : DHCPV6_REQUEST, 1234));
  154. findReservation(*engine, ctx);
  155. EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
  156. // Check that we got a lease
  157. EXPECT_TRUE(lease);
  158. if (!lease) {
  159. return (Lease6Ptr());
  160. }
  161. // Do all checks on the lease
  162. checkLease6(lease, type, expected_len, in_pool, in_pool);
  163. // Check that the lease is indeed in LeaseMgr
  164. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type, lease->addr_);
  165. if (!fake) {
  166. // This is a real (REQUEST) allocation, the lease must be in the DB
  167. EXPECT_TRUE(from_mgr);
  168. if (!from_mgr) {
  169. return (Lease6Ptr());
  170. }
  171. // Now check that the lease in LeaseMgr has the same parameters
  172. detailCompareLease(lease, from_mgr);
  173. } else {
  174. // This is a fake (SOLICIT) allocation, the lease must not be in DB
  175. EXPECT_FALSE(from_mgr);
  176. if (from_mgr) {
  177. return (Lease6Ptr());
  178. }
  179. }
  180. return (lease);
  181. }
  182. Lease6Collection
  183. AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
  184. AllocEngine::HintContainer& hints,
  185. bool allow_new_leases_in_renewal,
  186. bool in_pool) {
  187. Lease::Type type = pool->getType();
  188. uint8_t expected_len = pool->getLength();
  189. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
  190. type, false, false, "", false);
  191. ctx.hints_ = hints;
  192. ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 123));
  193. ctx.allow_new_leases_in_renewals_ = allow_new_leases_in_renewal;
  194. ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 1234));
  195. findReservation(engine, ctx);
  196. Lease6Collection leases = engine.renewLeases6(ctx);
  197. for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
  198. // Do all checks on the lease
  199. checkLease6(*it, type, expected_len, in_pool, in_pool);
  200. // Check that the lease is indeed in LeaseMgr
  201. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
  202. (*it)->addr_);
  203. // This is a real (REQUEST) allocation, the lease must be in the DB
  204. EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
  205. << " returned by allocateLeases6(), "
  206. << "but was not present in LeaseMgr";
  207. if (!from_mgr) {
  208. return (leases);
  209. }
  210. // Now check that the lease in LeaseMgr has the same parameters
  211. detailCompareLease(*it, from_mgr);
  212. }
  213. return (leases);
  214. }
  215. void
  216. AllocEngine6Test::allocWithUsedHintTest(Lease::Type type, IOAddress used_addr,
  217. IOAddress requested,
  218. uint8_t expected_pd_len) {
  219. boost::scoped_ptr<AllocEngine> engine;
  220. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  221. ASSERT_TRUE(engine);
  222. // Let's create a lease and put it in the LeaseMgr
  223. DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
  224. time_t now = time(NULL);
  225. Lease6Ptr used(new Lease6(type, used_addr,
  226. duid2, 1, 2, 3, 4, now, subnet_->getID()));
  227. ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
  228. // Another client comes in and request an address that is in pool, but
  229. // unfortunately it is used already. The same address must not be allocated
  230. // twice.
  231. Lease6Ptr lease;
  232. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, requested, type,
  233. false, false, "", false);
  234. ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234));
  235. EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
  236. // Check that we got a lease
  237. ASSERT_TRUE(lease);
  238. // Allocated address must be different
  239. EXPECT_NE(used_addr, lease->addr_);
  240. // We should NOT get what we asked for, because it is used already
  241. EXPECT_NE(requested, lease->addr_);
  242. // Do all checks on the lease
  243. checkLease6(lease, type, expected_pd_len);
  244. // Check that the lease is indeed in LeaseMgr
  245. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
  246. lease->addr_);
  247. ASSERT_TRUE(from_mgr);
  248. // Now check that the lease in LeaseMgr has the same parameters
  249. detailCompareLease(lease, from_mgr);
  250. }
  251. void
  252. AllocEngine6Test::allocBogusHint6(Lease::Type type, asiolink::IOAddress hint,
  253. uint8_t expected_pd_len) {
  254. boost::scoped_ptr<AllocEngine> engine;
  255. ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
  256. ASSERT_TRUE(engine);
  257. // Client would like to get a 3000::abc lease, which does not belong to any
  258. // supported lease. Allocation engine should ignore it and carry on
  259. // with the normal allocation
  260. Lease6Ptr lease;
  261. AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, false,
  262. false, "", false);
  263. ctx.query_.reset(new Pkt6(DHCPV6_REQUEST, 1234));
  264. EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
  265. // Check that we got a lease
  266. ASSERT_TRUE(lease);
  267. // We should NOT get what we asked for, because it is used already
  268. EXPECT_NE(hint, lease->addr_);
  269. // Do all checks on the lease
  270. checkLease6(lease, type, expected_pd_len);
  271. // Check that the lease is indeed in LeaseMgr
  272. Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
  273. lease->addr_);
  274. ASSERT_TRUE(from_mgr);
  275. // Now check that the lease in LeaseMgr has the same parameters
  276. detailCompareLease(lease, from_mgr);
  277. }
  278. void
  279. AllocEngine4Test::initSubnet(const asiolink::IOAddress& pool_start,
  280. const asiolink::IOAddress& pool_end) {
  281. CfgMgr& cfg_mgr = CfgMgr::instance();
  282. subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
  283. pool_ = Pool4Ptr(new Pool4(pool_start, pool_end));
  284. subnet_->addPool(pool_);
  285. cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
  286. }
  287. AllocEngine4Test::AllocEngine4Test() {
  288. // Create fresh instance of the HostMgr, and drop any previous HostMgr state.
  289. HostMgr::instance().create();
  290. clientid_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x44)));
  291. clientid2_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x56)));
  292. uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
  293. // Let's use odd hardware type to check if there is no Ethernet
  294. // hardcoded anywhere.
  295. hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
  296. // Allocate different MAC address for the tests that require two
  297. // different MAC addresses.
  298. ++mac[sizeof(mac) - 1];
  299. hwaddr2_ = HWAddrPtr(new HWAddr(mac, sizeof (mac), HTYPE_FDDI));
  300. // instantiate cfg_mgr
  301. CfgMgr& cfg_mgr = CfgMgr::instance();
  302. initSubnet(IOAddress("192.0.2.100"), IOAddress("192.0.2.109"));
  303. cfg_mgr.commit();
  304. factory_.create("type=memfile universe=4 persist=false");
  305. // Create a default context. Note that remaining parameters must be
  306. // assigned when needed.
  307. ctx_.subnet_ = subnet_;
  308. ctx_.clientid_ = clientid_;
  309. ctx_.hwaddr_ = hwaddr_;
  310. ctx_.callout_handle_ = HooksManager::createCalloutHandle();
  311. ctx_.query_.reset(new Pkt4(DHCPREQUEST, 1234));
  312. }
  313. }; // namespace test
  314. }; // namespace dhcp
  315. }; // namespace isc