alloc_engine.cc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  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 <dhcpsrv/alloc_engine.h>
  15. #include <dhcpsrv/dhcpsrv_log.h>
  16. #include <dhcpsrv/host_mgr.h>
  17. #include <dhcpsrv/lease_mgr_factory.h>
  18. #include <hooks/server_hooks.h>
  19. #include <hooks/hooks_manager.h>
  20. #include <cstring>
  21. #include <limits>
  22. #include <vector>
  23. #include <string.h>
  24. using namespace isc::asiolink;
  25. using namespace isc::hooks;
  26. namespace {
  27. /// Structure that holds registered hook indexes
  28. struct AllocEngineHooks {
  29. int hook_index_lease4_select_; ///< index for "lease4_receive" hook point
  30. int hook_index_lease4_renew_; ///< index for "lease4_renew" hook point
  31. int hook_index_lease6_select_; ///< index for "lease6_receive" hook point
  32. /// Constructor that registers hook points for AllocationEngine
  33. AllocEngineHooks() {
  34. hook_index_lease4_select_ = HooksManager::registerHook("lease4_select");
  35. hook_index_lease4_renew_ = HooksManager::registerHook("lease4_renew");
  36. hook_index_lease6_select_ = HooksManager::registerHook("lease6_select");
  37. }
  38. };
  39. // Declare a Hooks object. As this is outside any function or method, it
  40. // will be instantiated (and the constructor run) when the module is loaded.
  41. // As a result, the hook indexes will be defined before any method in this
  42. // module is called.
  43. AllocEngineHooks Hooks;
  44. }; // anonymous namespace
  45. namespace isc {
  46. namespace dhcp {
  47. AllocEngine::IterativeAllocator::IterativeAllocator(Lease::Type lease_type)
  48. :Allocator(lease_type) {
  49. }
  50. isc::asiolink::IOAddress
  51. AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& addr) {
  52. // Get a buffer holding an address.
  53. const std::vector<uint8_t>& vec = addr.toBytes();
  54. // Get the address length.
  55. const int len = vec.size();
  56. // Since the same array will be used to hold the IPv4 and IPv6
  57. // address we have to make sure that the size of the array
  58. // we allocate will work for both types of address.
  59. BOOST_STATIC_ASSERT(V4ADDRESS_LEN <= V6ADDRESS_LEN);
  60. uint8_t packed[V6ADDRESS_LEN];
  61. // Copy the address. It can be either V4 or V6.
  62. std::memcpy(packed, &vec[0], len);
  63. // Start increasing the least significant byte
  64. for (int i = len - 1; i >= 0; --i) {
  65. ++packed[i];
  66. // if we haven't overflowed (0xff -> 0x0), than we are done
  67. if (packed[i] != 0) {
  68. break;
  69. }
  70. }
  71. return (IOAddress::fromBytes(addr.getFamily(), packed));
  72. }
  73. isc::asiolink::IOAddress
  74. AllocEngine::IterativeAllocator::increasePrefix(const isc::asiolink::IOAddress& prefix,
  75. const uint8_t prefix_len) {
  76. if (!prefix.isV6()) {
  77. isc_throw(BadValue, "Prefix operations are for IPv6 only (attempted to "
  78. "increase prefix " << prefix << ")");
  79. }
  80. // Get a buffer holding an address.
  81. const std::vector<uint8_t>& vec = prefix.toBytes();
  82. if (prefix_len < 1 || prefix_len > 128) {
  83. isc_throw(BadValue, "Cannot increase prefix: invalid prefix length: "
  84. << prefix_len);
  85. }
  86. // Brief explanation what happens here:
  87. // http://www.youtube.com/watch?v=NFQCYpIHLNQ
  88. uint8_t n_bytes = (prefix_len - 1)/8;
  89. uint8_t n_bits = 8 - (prefix_len - n_bytes*8);
  90. uint8_t mask = 1 << n_bits;
  91. // Longer explanation: n_bytes specifies number of full bytes that are
  92. // in-prefix. They can also be used as an offset for the first byte that
  93. // is not in prefix. n_bits specifies number of bits on the last byte that
  94. // is (often partially) in prefix. For example for a /125 prefix, the values
  95. // are 15 and 3, respectively. Mask is a bitmask that has the least
  96. // significant bit from the prefix set.
  97. uint8_t packed[V6ADDRESS_LEN];
  98. // Copy the address. It must be V6, but we already checked that.
  99. std::memcpy(packed, &vec[0], V6ADDRESS_LEN);
  100. // Can we safely increase only the last byte in prefix without overflow?
  101. if (packed[n_bytes] + uint16_t(mask) < 256u) {
  102. packed[n_bytes] += mask;
  103. return (IOAddress::fromBytes(AF_INET6, packed));
  104. }
  105. // Overflow (done on uint8_t, but the sum is greater than 255)
  106. packed[n_bytes] += mask;
  107. // Deal with the overflow. Start increasing the least significant byte
  108. for (int i = n_bytes - 1; i >= 0; --i) {
  109. ++packed[i];
  110. // If we haven't overflowed (0xff->0x0) the next byte, then we are done
  111. if (packed[i] != 0) {
  112. break;
  113. }
  114. }
  115. return (IOAddress::fromBytes(AF_INET6, packed));
  116. }
  117. isc::asiolink::IOAddress
  118. AllocEngine::IterativeAllocator::pickAddress(const SubnetPtr& subnet,
  119. const DuidPtr&,
  120. const IOAddress&) {
  121. // Is this prefix allocation?
  122. bool prefix = pool_type_ == Lease::TYPE_PD;
  123. // Let's get the last allocated address. It is usually set correctly,
  124. // but there are times when it won't be (like after removing a pool or
  125. // perhaps restarting the server).
  126. IOAddress last = subnet->getLastAllocated(pool_type_);
  127. const PoolCollection& pools = subnet->getPools(pool_type_);
  128. if (pools.empty()) {
  129. isc_throw(AllocFailed, "No pools defined in selected subnet");
  130. }
  131. // first we need to find a pool the last address belongs to.
  132. PoolCollection::const_iterator it;
  133. for (it = pools.begin(); it != pools.end(); ++it) {
  134. if ((*it)->inRange(last)) {
  135. break;
  136. }
  137. }
  138. // last one was bogus for one of several reasons:
  139. // - we just booted up and that's the first address we're allocating
  140. // - a subnet was removed or other reconfiguration just completed
  141. // - perhaps allocation algorithm was changed
  142. if (it == pools.end()) {
  143. // ok to access first element directly. We checked that pools is non-empty
  144. IOAddress next = pools[0]->getFirstAddress();
  145. subnet->setLastAllocated(pool_type_, next);
  146. return (next);
  147. }
  148. // Ok, we have a pool that the last address belonged to, let's use it.
  149. IOAddress next("::");
  150. if (!prefix) {
  151. next = increaseAddress(last); // basically addr++
  152. } else {
  153. Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
  154. if (!pool6) {
  155. // Something is gravely wrong here
  156. isc_throw(Unexpected, "Wrong type of pool: " << (*it)->toText()
  157. << " is not Pool6");
  158. }
  159. // Get the next prefix
  160. next = increasePrefix(last, pool6->getLength());
  161. }
  162. if ((*it)->inRange(next)) {
  163. // the next one is in the pool as well, so we haven't hit pool boundary yet
  164. subnet->setLastAllocated(pool_type_, next);
  165. return (next);
  166. }
  167. // We hit pool boundary, let's try to jump to the next pool and try again
  168. ++it;
  169. if (it == pools.end()) {
  170. // Really out of luck today. That was the last pool. Let's rewind
  171. // to the beginning.
  172. next = pools[0]->getFirstAddress();
  173. subnet->setLastAllocated(pool_type_, next);
  174. return (next);
  175. }
  176. // there is a next pool, let's try first address from it
  177. next = (*it)->getFirstAddress();
  178. subnet->setLastAllocated(pool_type_, next);
  179. return (next);
  180. }
  181. AllocEngine::HashedAllocator::HashedAllocator(Lease::Type lease_type)
  182. :Allocator(lease_type) {
  183. isc_throw(NotImplemented, "Hashed allocator is not implemented");
  184. }
  185. isc::asiolink::IOAddress
  186. AllocEngine::HashedAllocator::pickAddress(const SubnetPtr&,
  187. const DuidPtr&,
  188. const IOAddress&) {
  189. isc_throw(NotImplemented, "Hashed allocator is not implemented");
  190. }
  191. AllocEngine::RandomAllocator::RandomAllocator(Lease::Type lease_type)
  192. :Allocator(lease_type) {
  193. isc_throw(NotImplemented, "Random allocator is not implemented");
  194. }
  195. isc::asiolink::IOAddress
  196. AllocEngine::RandomAllocator::pickAddress(const SubnetPtr&,
  197. const DuidPtr&,
  198. const IOAddress&) {
  199. isc_throw(NotImplemented, "Random allocator is not implemented");
  200. }
  201. AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts,
  202. bool ipv6)
  203. :attempts_(attempts) {
  204. // Choose the basic (normal address) lease type
  205. Lease::Type basic_type = ipv6 ? Lease::TYPE_NA : Lease::TYPE_V4;
  206. // Initalize normal address allocators
  207. switch (engine_type) {
  208. case ALLOC_ITERATIVE:
  209. allocators_[basic_type] = AllocatorPtr(new IterativeAllocator(basic_type));
  210. break;
  211. case ALLOC_HASHED:
  212. allocators_[basic_type] = AllocatorPtr(new HashedAllocator(basic_type));
  213. break;
  214. case ALLOC_RANDOM:
  215. allocators_[basic_type] = AllocatorPtr(new RandomAllocator(basic_type));
  216. break;
  217. default:
  218. isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
  219. }
  220. // If this is IPv6 allocation engine, initalize also temporary addrs
  221. // and prefixes
  222. if (ipv6) {
  223. switch (engine_type) {
  224. case ALLOC_ITERATIVE:
  225. allocators_[Lease::TYPE_TA] = AllocatorPtr(new IterativeAllocator(Lease::TYPE_TA));
  226. allocators_[Lease::TYPE_PD] = AllocatorPtr(new IterativeAllocator(Lease::TYPE_PD));
  227. break;
  228. case ALLOC_HASHED:
  229. allocators_[Lease::TYPE_TA] = AllocatorPtr(new HashedAllocator(Lease::TYPE_TA));
  230. allocators_[Lease::TYPE_PD] = AllocatorPtr(new HashedAllocator(Lease::TYPE_PD));
  231. break;
  232. case ALLOC_RANDOM:
  233. allocators_[Lease::TYPE_TA] = AllocatorPtr(new RandomAllocator(Lease::TYPE_TA));
  234. allocators_[Lease::TYPE_PD] = AllocatorPtr(new RandomAllocator(Lease::TYPE_PD));
  235. break;
  236. default:
  237. isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
  238. }
  239. }
  240. // Register hook points
  241. hook_index_lease4_select_ = Hooks.hook_index_lease4_select_;
  242. hook_index_lease6_select_ = Hooks.hook_index_lease6_select_;
  243. }
  244. Lease6Collection
  245. AllocEngine::allocateLeases6(const Subnet6Ptr& subnet, const DuidPtr& duid,
  246. const uint32_t iaid, const IOAddress& hint,
  247. Lease::Type type, const bool fwd_dns_update,
  248. const bool rev_dns_update,
  249. const std::string& hostname, bool fake_allocation,
  250. const isc::hooks::CalloutHandlePtr& callout_handle,
  251. Lease6Collection& old_leases, const HWAddrPtr& hwaddr) {
  252. try {
  253. AllocatorPtr allocator = getAllocator(type);
  254. if (!allocator) {
  255. isc_throw(InvalidOperation, "No allocator specified for "
  256. << Lease6::typeToText(type));
  257. }
  258. if (!subnet) {
  259. isc_throw(InvalidOperation, "Subnet is required for allocation");
  260. }
  261. if (!duid) {
  262. isc_throw(InvalidOperation, "DUID is mandatory for allocation");
  263. }
  264. // Check if there's existing lease for that subnet/duid/iaid
  265. // combination.
  266. /// @todo: Make this generic (cover temp. addrs and prefixes)
  267. Lease6Collection existing = LeaseMgrFactory::instance().getLeases6(type,
  268. *duid, iaid, subnet->getID());
  269. // There is at least one lease for this client. We will return these
  270. // leases for the client, but we may need to update FQDN information.
  271. if (!existing.empty()) {
  272. // Return old leases so the server can see what has changed.
  273. old_leases = existing;
  274. return (updateFqdnData(existing, fwd_dns_update, rev_dns_update,
  275. hostname, fake_allocation));
  276. }
  277. // check if the hint is in pool and is available
  278. // This is equivalent of subnet->inPool(hint), but returns the pool
  279. Pool6Ptr pool = boost::dynamic_pointer_cast<
  280. Pool6>(subnet->getPool(type, hint, false));
  281. if (pool) {
  282. /// @todo: We support only one hint for now
  283. Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(type, hint);
  284. if (!lease) {
  285. /// @todo: check if the hint is reserved once we have host
  286. /// support implemented
  287. // The hint is valid and not currently used, let's create a
  288. // lease for it
  289. lease = createLease6(subnet, duid, iaid, hint,
  290. pool->getLength(), type,
  291. fwd_dns_update, rev_dns_update,
  292. hostname, hwaddr, callout_handle, fake_allocation);
  293. // It can happen that the lease allocation failed (we could
  294. // have lost the race condition. That means that the hint is
  295. // lo longer usable and we need to continue the regular
  296. // allocation path.
  297. if (lease) {
  298. // We are allocating a new lease (not renewing). So, the
  299. // old lease should be NULL.
  300. old_leases.push_back(Lease6Ptr());
  301. /// @todo: We support only one lease per ia for now
  302. Lease6Collection collection;
  303. collection.push_back(lease);
  304. return (collection);
  305. }
  306. } else {
  307. if (lease->expired()) {
  308. // Copy an existing, expired lease so as it can be returned
  309. // to the caller.
  310. Lease6Ptr old_lease(new Lease6(*lease));
  311. old_leases.push_back(old_lease);
  312. /// We found a lease and it is expired, so we can reuse it
  313. lease = reuseExpiredLease(lease, subnet, duid, iaid,
  314. pool->getLength(),
  315. fwd_dns_update, rev_dns_update,
  316. hostname, callout_handle,
  317. fake_allocation);
  318. /// @todo: We support only one lease per ia for now
  319. Lease6Collection collection;
  320. collection.push_back(lease);
  321. return (collection);
  322. }
  323. }
  324. }
  325. // Hint is in the pool but is not available. Search the pool until first of
  326. // the following occurs:
  327. // - we find a free address
  328. // - we find an address for which the lease has expired
  329. // - we exhaust number of tries
  330. //
  331. // @todo: Current code does not handle pool exhaustion well. It will be
  332. // improved. Current problems:
  333. // 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
  334. // 10 addresses), we will iterate over it 100 times before giving up
  335. // 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
  336. // 3. the whole concept of infinite attempts is just asking for infinite loop
  337. // We may consider some form or reference counting (this pool has X addresses
  338. // left), but this has one major problem. We exactly control allocation
  339. // moment, but we currently do not control expiration time at all
  340. // Initialize the maximum number of attempts to pick and allocate an
  341. // address. The value of 0 means "infinite", which is maximum uint32_t
  342. // value.
  343. uint32_t max_attempts = (attempts_ == 0) ?
  344. std::numeric_limits<uint32_t>::max() : attempts_;
  345. for (uint32_t i = 0; i < max_attempts; ++i) {
  346. IOAddress candidate = allocator->pickAddress(subnet, duid, hint);
  347. /// @todo: check if the address is reserved once we have host support
  348. /// implemented
  349. // The first step is to find out prefix length. It is 128 for
  350. // non-PD leases.
  351. uint8_t prefix_len = 128;
  352. if (type == Lease::TYPE_PD) {
  353. Pool6Ptr pool = boost::dynamic_pointer_cast<Pool6>(
  354. subnet->getPool(type, candidate, false));
  355. prefix_len = pool->getLength();
  356. }
  357. Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(type,
  358. candidate);
  359. if (!existing) {
  360. // there's no existing lease for selected candidate, so it is
  361. // free. Let's allocate it.
  362. Lease6Ptr lease = createLease6(subnet, duid, iaid, candidate,
  363. prefix_len, type, fwd_dns_update,
  364. rev_dns_update, hostname, hwaddr,
  365. callout_handle, fake_allocation);
  366. if (lease) {
  367. // We are allocating a new lease (not renewing). So, the
  368. // old lease should be NULL.
  369. old_leases.push_back(Lease6Ptr());
  370. Lease6Collection collection;
  371. collection.push_back(lease);
  372. return (collection);
  373. }
  374. // Although the address was free just microseconds ago, it may have
  375. // been taken just now. If the lease insertion fails, we continue
  376. // allocation attempts.
  377. } else {
  378. if (existing->expired()) {
  379. // Copy an existing, expired lease so as it can be returned
  380. // to the caller.
  381. Lease6Ptr old_lease(new Lease6(*existing));
  382. old_leases.push_back(old_lease);
  383. existing = reuseExpiredLease(existing, subnet, duid, iaid,
  384. prefix_len, fwd_dns_update,
  385. rev_dns_update, hostname,
  386. callout_handle, fake_allocation);
  387. Lease6Collection collection;
  388. collection.push_back(existing);
  389. return (collection);
  390. }
  391. }
  392. }
  393. // Unable to allocate an address, return an empty lease.
  394. LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_FAIL).arg(attempts_);
  395. } catch (const isc::Exception& e) {
  396. // Some other error, return an empty lease.
  397. LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS6_ALLOC_ERROR).arg(e.what());
  398. }
  399. return (Lease6Collection());
  400. }
  401. Lease4Ptr
  402. AllocEngine::allocateLease4(const SubnetPtr& subnet, const ClientIdPtr& clientid,
  403. const HWAddrPtr& hwaddr, const IOAddress& hint,
  404. const bool fwd_dns_update, const bool rev_dns_update,
  405. const std::string& hostname, bool fake_allocation,
  406. const isc::hooks::CalloutHandlePtr& callout_handle,
  407. Lease4Ptr& old_lease) {
  408. // The NULL pointer indicates that the old lease didn't exist. It may
  409. // be later set to non NULL value if existing lease is found in the
  410. // database.
  411. old_lease.reset();
  412. try {
  413. // Set allocator.
  414. AllocatorPtr allocator = getAllocator(Lease::TYPE_V4);
  415. if (!subnet) {
  416. isc_throw(BadValue, "Can't allocate IPv4 address without subnet");
  417. }
  418. if (!hwaddr) {
  419. isc_throw(BadValue, "HWAddr must be defined");
  420. }
  421. /// @todo The context for lease allocation should really be created
  422. /// by the DHCPv4 server and passed to this function. The reason for
  423. /// this is that the server should retrieve the Host object for the
  424. /// client because the Host object contains the data not only useful
  425. /// for the address allocation but also hostname and DHCP options
  426. /// for the client. The Host object should be passed in the context.
  427. /// Making this change would require a change to the allocateLease4
  428. /// API which would in turn require lots of changes in unit tests.
  429. /// The ticket introducing a context and host reservation in the
  430. /// allocation engine is complex enough by itself to warrant that
  431. /// the API change is done with a separate ticket.
  432. ClientContext4 ctx;
  433. ctx.subnet_ = subnet;
  434. ctx.clientid_ = clientid;
  435. ctx.hwaddr_ = hwaddr;
  436. ctx.requested_address_ = hint;
  437. ctx.fwd_dns_update_ = fwd_dns_update;
  438. ctx.rev_dns_update_ = rev_dns_update;
  439. ctx.hostname_ = hostname;
  440. ctx.fake_allocation_ = fake_allocation;
  441. ctx.callout_handle_ = callout_handle;
  442. ctx.old_lease_ = old_lease;
  443. ctx.host_ = HostMgr::instance().get4(subnet->getID(), hwaddr);
  444. // If there is a reservation for this client we want to allocate the
  445. // reserved address to the client, rather than any other address.
  446. if (ctx.host_) {
  447. // In some cases the client doesn't supply any address, e.g. when
  448. // it sends a DHCPDISCOVER. In such cases, we use the reserved
  449. // address as a hint.
  450. if (ctx.requested_address_ == IOAddress("0.0.0.0")) {
  451. ctx.requested_address_ = ctx.host_->getIPv4Reservation();
  452. // If the client supplied an address we have to check if this
  453. // address is reserved for this client. If not, we will send
  454. // DHCPNAK to inform the client that we were not able to
  455. // assign a requested address. The fake allocation (DHCPDISCOVER
  456. // case) is an exception. In such case we treat the address
  457. // supplied by the client as a hint, but we may offer address
  458. // other than desired by the client. So, we don't return an
  459. // empty lease.
  460. } else if (!ctx.fake_allocation_ &&
  461. (ctx.requested_address_ != ctx.host_->getIPv4Reservation())) {
  462. return (Lease4Ptr());
  463. }
  464. }
  465. // Check if the client has any leases in the lease database, using HW
  466. // address or client identifier.
  467. LeaseMgr& lease_mgr = LeaseMgrFactory::instance();
  468. Lease4Ptr existing = lease_mgr.getLease4(*hwaddr, ctx.subnet_->getID());
  469. if (!existing && clientid) {
  470. existing = lease_mgr.getLease4(*clientid, ctx.subnet_->getID());
  471. }
  472. // If client has a lease there are two choices. The server may need
  473. // to renew (no address change) the lease. Or, the server may need
  474. // to replace the lease with a different one. This is the case when
  475. // the server has a dynamically assigned lease but an administrator
  476. // has made a new reservation for the client for a different address.
  477. if (existing) {
  478. existing = reallocateClientLease(existing, ctx);
  479. // The interrupt_processing_ flag indicates that the lease
  480. // reallocation was not successful and that the allocation
  481. // engine should cease allocation process for this client.
  482. // This may occur when the client is trying to renew the
  483. // lease which is reserved for someone else. The server should
  484. // send DHCPNAK to indicate that the client should try to
  485. // start over the allocation process.
  486. if (ctx.interrupt_processing_) {
  487. old_lease = ctx.old_lease_;
  488. return (Lease4Ptr());
  489. // If we tried to reallocate the reserved lease we return
  490. // at this point regardless if reallocation failed or passed.
  491. // We also return when allocation passed, no matter if this
  492. // was a reserved address or not.
  493. } else if (ctx.host_ || existing) {
  494. old_lease = ctx.old_lease_;
  495. return (existing);
  496. }
  497. }
  498. // There is no lease in the database for this client, so we will
  499. // proceed with a new allocation. We will try to allocate a
  500. // reserved address or an address from a dynamic pool if there is
  501. // no reservation.
  502. if (ctx.host_ || subnet->inPool(Lease::TYPE_V4, ctx.requested_address_)) {
  503. // If a client is requesting specific IP address, but the
  504. // reservation was made for a different address the server returns
  505. // NAK to the client. By returning NULL lease here we indicate to
  506. // the server that we're not able to fulfil client's request for the
  507. // particular IP address. We don't return NULL lease in case of the
  508. // fake allocation (DHCPDISCOVER) because in this case the address
  509. // supplied by the client is only a hint.
  510. if (!ctx.fake_allocation_ && ctx.host_ &&
  511. (ctx.requested_address_ != IOAddress("0.0.0.0")) &&
  512. (ctx.host_->getIPv4Reservation() != ctx.requested_address_)) {
  513. return (Lease4Ptr());
  514. }
  515. // The reserved address always takes precedence over an address
  516. // supplied by the client (renewed address or requested).
  517. const IOAddress& candidate = ctx.host_ ?
  518. ctx.host_->getIPv4Reservation() : ctx.requested_address_;
  519. // Once we picked an address we want to allocate, we have to check
  520. // if this address is available.
  521. existing = LeaseMgrFactory::instance().getLease4(candidate);
  522. if (!existing) {
  523. // The candidate address is currently unused. Let's create a
  524. // lease for it.
  525. Lease4Ptr lease = createLease4(subnet, clientid, hwaddr,
  526. candidate, fwd_dns_update,
  527. rev_dns_update,
  528. hostname, callout_handle,
  529. fake_allocation);
  530. // If we have allocated the lease let's return it. Also,
  531. // always return when tried to allocate reserved address,
  532. // regardless if allocation was successful or not. If it
  533. // was not successful, we will return a NULL pointer which
  534. // indicates to the server that it should send NAK to the
  535. // client.
  536. if (lease || ctx.host_) {
  537. return (lease);
  538. }
  539. // There is a lease for this address in the lease database but
  540. // it is possible that the lease has expired, in which case
  541. // we will be able to reuse it.
  542. } else {
  543. if (existing->expired()) {
  544. // Save the old lease, before reusing it.
  545. old_lease.reset(new Lease4(*existing));
  546. return (reuseExpiredLease(existing, ctx));
  547. // The existing lease is not expired (is in use by some
  548. // other client). If we are trying to get this lease because
  549. // the address has been reserved for the client we have no
  550. // choice but to return a NULL lease to indicate that the
  551. // allocation has failed.
  552. } else if (ctx.host_) {
  553. return (Lease4Ptr());
  554. }
  555. }
  556. }
  557. // No address was requested, requested address was not in pool or the
  558. // allocation was not successful so far. Let's try to find a different
  559. // address for the client. Search the pool until first of the following
  560. // occurs:
  561. // - we find a free address
  562. // - we find an address for which the lease has expired
  563. // - we exhaust the number of tries
  564. //
  565. /// @todo: Current code does not handle pool exhaustion well. It will be
  566. /// improved. Current problems:
  567. /// 1. with attempts set to too large value (e.g. 1000) and a small pool (e.g.
  568. /// 10 addresses), we will iterate over it 100 times before giving up
  569. /// 2. attempts 0 mean unlimited (this is really UINT_MAX, not infinite)
  570. /// 3. the whole concept of infinite attempts is just asking for infinite loop
  571. /// We may consider some form or reference counting (this pool has X addresses
  572. /// left), but this has one major problem. We exactly control allocation
  573. /// moment, but we currently do not control expiration time at all
  574. unsigned int i = attempts_;
  575. do {
  576. // Decrease the number of remaining attempts here so as we guarantee
  577. // that it is decreased when the code below uses "continue".
  578. --i;
  579. IOAddress candidate = allocator->pickAddress(subnet, clientid,
  580. ctx.requested_address_);
  581. // Check if this address is reserved. There is no need to check for
  582. // whom it is reserved, because if it has been reserved for us we would
  583. // have already allocated a lease.
  584. if (HostMgr::instance().get4(subnet->getID(), candidate)) {
  585. // Don't allocate a reserved address.
  586. continue;
  587. }
  588. Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(candidate);
  589. if (!existing) {
  590. // there's no existing lease for selected candidate, so it is
  591. // free. Let's allocate it.
  592. Lease4Ptr lease = createLease4(subnet, clientid, hwaddr,
  593. candidate, fwd_dns_update,
  594. rev_dns_update, hostname,
  595. callout_handle, fake_allocation);
  596. if (lease) {
  597. return (lease);
  598. }
  599. // Although the address was free just microseconds ago, it may have
  600. // been taken just now. If the lease insertion fails, we continue
  601. // allocation attempts.
  602. } else {
  603. if (existing->expired()) {
  604. // Save old lease before reusing it.
  605. old_lease.reset(new Lease4(*existing));
  606. return (reuseExpiredLease(existing, ctx));
  607. }
  608. }
  609. // Continue trying allocation until we run out of attempts
  610. // (or attempts are set to 0, which means infinite)
  611. } while ((i > 0) || !attempts_);
  612. // Unable to allocate an address, return an empty lease.
  613. LOG_WARN(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_FAIL).arg(attempts_);
  614. } catch (const isc::Exception& e) {
  615. // Some other error, return an empty lease.
  616. LOG_ERROR(dhcpsrv_logger, DHCPSRV_ADDRESS4_ALLOC_ERROR).arg(e.what());
  617. }
  618. return (Lease4Ptr());
  619. }
  620. Lease4Ptr
  621. AllocEngine::renewLease4(const Lease4Ptr& lease,
  622. AllocEngine::ClientContext4& ctx) {
  623. if (!lease) {
  624. isc_throw(BadValue, "null lease specified for renewLease4");
  625. }
  626. // The ctx.host_ possibly contains a reservation for the client for which
  627. // we are renewing a lease. If this reservation exists, we assume that
  628. // there is no conflict in assigning the address to this client. Note
  629. // that the reallocateClientLease checks if the address reserved for
  630. // the client matches the address in the lease we're renewing here.
  631. if (!ctx.host_) {
  632. ConstHostPtr host = HostMgr::instance().get4(ctx.subnet_->getID(),
  633. lease->addr_);
  634. // Do not renew the lease if:
  635. // - If address is reserved for someone else or ...
  636. // - renewed address doesn't belong to a pool.
  637. if ((host && ctx.hwaddr_ && (*host->getHWAddress() != *ctx.hwaddr_)) ||
  638. (!ctx.subnet_->inPool(Lease::TYPE_V4, lease->addr_))) {
  639. ctx.interrupt_processing_ = !ctx.fake_allocation_;
  640. return (Lease4Ptr());
  641. }
  642. }
  643. // Let's keep the old data. This is essential if we are using memfile
  644. // (the lease returned points directly to the lease4 object in the database)
  645. // We'll need it if we want to skip update (i.e. roll back renewal)
  646. /// @todo: remove this once #3083 is implemented
  647. Lease4 old_values = *lease;
  648. // Update the lease with the information from the context.
  649. updateLease4Information(lease, ctx);
  650. bool skip = false;
  651. // Execute all callouts registered for lease4_renew.
  652. if (HooksManager::getHooksManager().
  653. calloutsPresent(Hooks.hook_index_lease4_renew_)) {
  654. // Delete all previous arguments
  655. ctx.callout_handle_->deleteAllArguments();
  656. // Subnet from which we do the allocation. Convert the general subnet
  657. // pointer to a pointer to a Subnet4. Note that because we are using
  658. // boost smart pointers here, we need to do the cast using the boost
  659. // version of dynamic_pointer_cast.
  660. Subnet4Ptr subnet4 = boost::dynamic_pointer_cast<Subnet4>(ctx.subnet_);
  661. // Pass the parameters
  662. ctx.callout_handle_->setArgument("subnet4", subnet4);
  663. ctx.callout_handle_->setArgument("clientid", ctx.clientid_);
  664. ctx.callout_handle_->setArgument("hwaddr", ctx.hwaddr_);
  665. // Pass the lease to be updated
  666. ctx.callout_handle_->setArgument("lease4", lease);
  667. // Call all installed callouts
  668. HooksManager::callCallouts(Hooks.hook_index_lease4_renew_,
  669. *ctx.callout_handle_);
  670. // Callouts decided to skip the next processing step. The next
  671. // processing step would to actually renew the lease, so skip at this
  672. // stage means "keep the old lease as it is".
  673. if (ctx.callout_handle_->getSkip()) {
  674. skip = true;
  675. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS,
  676. DHCPSRV_HOOK_LEASE4_RENEW_SKIP);
  677. }
  678. }
  679. if (!ctx.fake_allocation_ && !skip) {
  680. // for REQUEST we do update the lease
  681. LeaseMgrFactory::instance().updateLease4(lease);
  682. }
  683. if (skip) {
  684. // Rollback changes (really useful only for memfile)
  685. /// @todo: remove this once #3083 is implemented
  686. *lease = old_values;
  687. }
  688. return (lease);
  689. }
  690. Lease6Ptr AllocEngine::reuseExpiredLease(Lease6Ptr& expired,
  691. const Subnet6Ptr& subnet,
  692. const DuidPtr& duid,
  693. const uint32_t iaid,
  694. uint8_t prefix_len,
  695. const bool fwd_dns_update,
  696. const bool rev_dns_update,
  697. const std::string& hostname,
  698. const isc::hooks::CalloutHandlePtr& callout_handle,
  699. bool fake_allocation /*= false */ ) {
  700. if (!expired->expired()) {
  701. isc_throw(BadValue, "Attempt to recycle lease that is still valid");
  702. }
  703. if (expired->type_ != Lease::TYPE_PD) {
  704. prefix_len = 128; // non-PD lease types must be always /128
  705. }
  706. // address, lease type and prefixlen (0) stay the same
  707. expired->iaid_ = iaid;
  708. expired->duid_ = duid;
  709. expired->preferred_lft_ = subnet->getPreferred();
  710. expired->valid_lft_ = subnet->getValid();
  711. expired->t1_ = subnet->getT1();
  712. expired->t2_ = subnet->getT2();
  713. expired->cltt_ = time(NULL);
  714. expired->subnet_id_ = subnet->getID();
  715. expired->fixed_ = false;
  716. expired->hostname_ = hostname;
  717. expired->fqdn_fwd_ = fwd_dns_update;
  718. expired->fqdn_rev_ = rev_dns_update;
  719. expired->prefixlen_ = prefix_len;
  720. /// @todo: log here that the lease was reused (there's ticket #2524 for
  721. /// logging in libdhcpsrv)
  722. // Let's execute all callouts registered for lease6_select
  723. if (callout_handle &&
  724. HooksManager::getHooksManager().calloutsPresent(hook_index_lease6_select_)) {
  725. // Delete all previous arguments
  726. callout_handle->deleteAllArguments();
  727. // Pass necessary arguments
  728. // Subnet from which we do the allocation
  729. callout_handle->setArgument("subnet6", subnet);
  730. // Is this solicit (fake = true) or request (fake = false)
  731. callout_handle->setArgument("fake_allocation", fake_allocation);
  732. // The lease that will be assigned to a client
  733. callout_handle->setArgument("lease6", expired);
  734. // Call the callouts
  735. HooksManager::callCallouts(hook_index_lease6_select_, *callout_handle);
  736. // Callouts decided to skip the action. This means that the lease is not
  737. // assigned, so the client will get NoAddrAvail as a result. The lease
  738. // won't be inserted into the database.
  739. if (callout_handle->getSkip()) {
  740. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS, DHCPSRV_HOOK_LEASE6_SELECT_SKIP);
  741. return (Lease6Ptr());
  742. }
  743. // Let's use whatever callout returned. Hopefully it is the same lease
  744. // we handled to it.
  745. callout_handle->getArgument("lease6", expired);
  746. }
  747. if (!fake_allocation) {
  748. // for REQUEST we do update the lease
  749. LeaseMgrFactory::instance().updateLease6(expired);
  750. }
  751. // We do nothing for SOLICIT. We'll just update database when
  752. // the client gets back to us with REQUEST message.
  753. // it's not really expired at this stage anymore - let's return it as
  754. // an updated lease
  755. return (expired);
  756. }
  757. Lease4Ptr
  758. AllocEngine::reuseExpiredLease(Lease4Ptr& expired,
  759. AllocEngine::ClientContext4& ctx) {
  760. if (!expired) {
  761. isc_throw(BadValue, "null lease specified for reuseExpiredLease");
  762. }
  763. if (!ctx.subnet_) {
  764. isc_throw(BadValue, "null subnet specified for the reuseExpiredLease");
  765. }
  766. updateLease4Information(expired, ctx);
  767. expired->fixed_ = false;
  768. /// @todo: log here that the lease was reused (there's ticket #2524 for
  769. /// logging in libdhcpsrv)
  770. // Let's execute all callouts registered for lease4_select
  771. if (ctx.callout_handle_ && HooksManager::getHooksManager()
  772. .calloutsPresent(hook_index_lease4_select_)) {
  773. // Delete all previous arguments
  774. ctx.callout_handle_->deleteAllArguments();
  775. // Pass necessary arguments
  776. // Subnet from which we do the allocation. Convert the general subnet
  777. // pointer to a pointer to a Subnet4. Note that because we are using
  778. // boost smart pointers here, we need to do the cast using the boost
  779. // version of dynamic_pointer_cast.
  780. Subnet4Ptr subnet4 = boost::dynamic_pointer_cast<Subnet4>(ctx.subnet_);
  781. ctx.callout_handle_->setArgument("subnet4", subnet4);
  782. // Is this solicit (fake = true) or request (fake = false)
  783. ctx.callout_handle_->setArgument("fake_allocation",
  784. ctx.fake_allocation_);
  785. // The lease that will be assigned to a client
  786. ctx.callout_handle_->setArgument("lease4", expired);
  787. // Call the callouts
  788. HooksManager::callCallouts(hook_index_lease4_select_, *ctx.callout_handle_);
  789. // Callouts decided to skip the action. This means that the lease is not
  790. // assigned, so the client will get NoAddrAvail as a result. The lease
  791. // won't be inserted into the database.
  792. if (ctx.callout_handle_->getSkip()) {
  793. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS,
  794. DHCPSRV_HOOK_LEASE4_SELECT_SKIP);
  795. return (Lease4Ptr());
  796. }
  797. // Let's use whatever callout returned. Hopefully it is the same lease
  798. // we handled to it.
  799. ctx.callout_handle_->getArgument("lease4", expired);
  800. }
  801. if (!ctx.fake_allocation_) {
  802. // for REQUEST we do update the lease
  803. LeaseMgrFactory::instance().updateLease4(expired);
  804. }
  805. // We do nothing for SOLICIT. We'll just update database when
  806. // the client gets back to us with REQUEST message.
  807. // it's not really expired at this stage anymore - let's return it as
  808. // an updated lease
  809. return (expired);
  810. }
  811. Lease4Ptr
  812. AllocEngine::replaceClientLease(Lease4Ptr& lease, ClientContext4& ctx) {
  813. if (!lease) {
  814. isc_throw(BadValue, "null lease specified for replaceClientLease");
  815. }
  816. if (!ctx.subnet_) {
  817. isc_throw(BadValue, "null subnet specified for replaceClientLease");
  818. }
  819. if (ctx.requested_address_ == IOAddress("0.0.0.0")) {
  820. isc_throw(BadValue, "zero address specified for the"
  821. " replaceClientLease");
  822. }
  823. // Remember the previous address for this lease.
  824. IOAddress prev_address = lease->addr_;
  825. if (!ctx.host_) {
  826. ConstHostPtr host = HostMgr::instance().get4(ctx.subnet_->getID(),
  827. ctx.requested_address_);
  828. // If there is a reservation for the new address and the reservation
  829. // is made for another client, do not use this address.
  830. if (host && ctx.hwaddr_ && (*host->getHWAddress() != *ctx.hwaddr_)) {
  831. ctx.interrupt_processing_ = true;
  832. return (Lease4Ptr());
  833. }
  834. lease->addr_ = ctx.requested_address_;
  835. } else {
  836. lease->addr_ = ctx.host_->getIPv4Reservation();
  837. }
  838. updateLease4Information(lease, ctx);
  839. bool skip = false;
  840. // Execute callouts registered for lease4_select.
  841. if (ctx.callout_handle_ && HooksManager::getHooksManager()
  842. .calloutsPresent(hook_index_lease4_select_)) {
  843. // Delete all previous arguments.
  844. ctx.callout_handle_->deleteAllArguments();
  845. // Pass arguments.
  846. Subnet4Ptr subnet4 = boost::dynamic_pointer_cast<Subnet4>(ctx.subnet_);
  847. ctx.callout_handle_->setArgument("subnet4", subnet4);
  848. ctx.callout_handle_->setArgument("fake_allocation",
  849. ctx.fake_allocation_);
  850. ctx.callout_handle_->setArgument("lease4", lease);
  851. HooksManager::callCallouts(hook_index_lease4_select_,
  852. *ctx.callout_handle_);
  853. if (ctx.callout_handle_->getSkip()) {
  854. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS,
  855. DHCPSRV_HOOK_LEASE4_SELECT_SKIP);
  856. return (Lease4Ptr());
  857. }
  858. // Let's use whatever callout returned.
  859. ctx.callout_handle_->getArgument("lease4", lease);
  860. // Callouts decided to skip the next processing step. The next
  861. // processing step would to actually renew the lease, so skip at this
  862. // stage means "keep the old lease as it is".
  863. if (ctx.callout_handle_->getSkip()) {
  864. skip = true;
  865. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS,
  866. DHCPSRV_HOOK_LEASE4_SELECT_SKIP);
  867. }
  868. }
  869. /// @todo There should be a callout for a deletion of an old lease.
  870. /// The lease4_release callout is in appropriate, because by definition
  871. /// it is invoked when DHCPRELEASE packet is received.
  872. if (!ctx.fake_allocation_ && !skip) {
  873. // We can't use LeaseMgr::updateLease because it identifies the
  874. // lease by an IP address. Instead, we have to delete an old
  875. // lease and add a new one.
  876. LeaseMgrFactory::instance().deleteLease(prev_address);
  877. LeaseMgrFactory::instance().addLease(lease);
  878. }
  879. return (lease);
  880. }
  881. Lease4Ptr
  882. AllocEngine::reallocateClientLease(Lease4Ptr& lease,
  883. AllocEngine::ClientContext4& ctx) {
  884. // Save the old lease, before renewal.
  885. ctx.old_lease_.reset(new Lease4(*lease));
  886. /// The client's address will need to be modified in case if:
  887. /// - There is a reservation for the client (likely new one) and
  888. /// the currently used address is different.
  889. /// - Client requested some IP address and the requested address
  890. /// is different than the currently used one. Note that if this
  891. /// is a DHCPDISCOVER the requested IP address is ignored when
  892. /// it doesn't match the one in use.
  893. if ((ctx.host_ && (ctx.host_->getIPv4Reservation() != lease->addr_)) ||
  894. (!ctx.fake_allocation_ &&
  895. (ctx.requested_address_ != IOAddress("0.0.0.0")) &&
  896. (lease->addr_ != ctx.requested_address_))) {
  897. lease = replaceClientLease(lease, ctx);
  898. return (lease);
  899. } else {
  900. lease = renewLease4(lease, ctx);
  901. if (lease) {
  902. return (lease);
  903. }
  904. }
  905. return (Lease4Ptr());
  906. }
  907. Lease6Ptr AllocEngine::createLease6(const Subnet6Ptr& subnet,
  908. const DuidPtr& duid,
  909. const uint32_t iaid,
  910. const IOAddress& addr,
  911. uint8_t prefix_len,
  912. const Lease::Type type,
  913. const bool fwd_dns_update,
  914. const bool rev_dns_update,
  915. const std::string& hostname,
  916. const HWAddrPtr& hwaddr,
  917. const isc::hooks::CalloutHandlePtr& callout_handle,
  918. bool fake_allocation /*= false */ ) {
  919. if (type != Lease::TYPE_PD) {
  920. prefix_len = 128; // non-PD lease types must be always /128
  921. }
  922. Lease6Ptr lease(new Lease6(type, addr, duid, iaid,
  923. subnet->getPreferred(), subnet->getValid(),
  924. subnet->getT1(), subnet->getT2(), subnet->getID(),
  925. hwaddr, prefix_len));
  926. lease->fqdn_fwd_ = fwd_dns_update;
  927. lease->fqdn_rev_ = rev_dns_update;
  928. lease->hostname_ = hostname;
  929. // Let's execute all callouts registered for lease6_select
  930. if (callout_handle &&
  931. HooksManager::getHooksManager().calloutsPresent(hook_index_lease6_select_)) {
  932. // Delete all previous arguments
  933. callout_handle->deleteAllArguments();
  934. // Pass necessary arguments
  935. // Subnet from which we do the allocation
  936. callout_handle->setArgument("subnet6", subnet);
  937. // Is this solicit (fake = true) or request (fake = false)
  938. callout_handle->setArgument("fake_allocation", fake_allocation);
  939. callout_handle->setArgument("lease6", lease);
  940. // This is the first callout, so no need to clear any arguments
  941. HooksManager::callCallouts(hook_index_lease6_select_, *callout_handle);
  942. // Callouts decided to skip the action. This means that the lease is not
  943. // assigned, so the client will get NoAddrAvail as a result. The lease
  944. // won't be inserted into the database.
  945. if (callout_handle->getSkip()) {
  946. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS, DHCPSRV_HOOK_LEASE6_SELECT_SKIP);
  947. return (Lease6Ptr());
  948. }
  949. // Let's use whatever callout returned. Hopefully it is the same lease
  950. // we handled to it.
  951. callout_handle->getArgument("lease6", lease);
  952. }
  953. if (!fake_allocation) {
  954. // That is a real (REQUEST) allocation
  955. bool status = LeaseMgrFactory::instance().addLease(lease);
  956. if (status) {
  957. return (lease);
  958. } else {
  959. // One of many failures with LeaseMgr (e.g. lost connection to the
  960. // database, database failed etc.). One notable case for that
  961. // is that we are working in multi-process mode and we lost a race
  962. // (some other process got that address first)
  963. return (Lease6Ptr());
  964. }
  965. } else {
  966. // That is only fake (SOLICIT without rapid-commit) allocation
  967. // It is for advertise only. We should not insert the lease into LeaseMgr,
  968. // but rather check that we could have inserted it.
  969. Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(
  970. Lease::TYPE_NA, addr);
  971. if (!existing) {
  972. return (lease);
  973. } else {
  974. return (Lease6Ptr());
  975. }
  976. }
  977. }
  978. Lease4Ptr AllocEngine::createLease4(const SubnetPtr& subnet,
  979. const DuidPtr& clientid,
  980. const HWAddrPtr& hwaddr,
  981. const IOAddress& addr,
  982. const bool fwd_dns_update,
  983. const bool rev_dns_update,
  984. const std::string& hostname,
  985. const isc::hooks::CalloutHandlePtr& callout_handle,
  986. bool fake_allocation /*= false */ ) {
  987. if (!hwaddr) {
  988. isc_throw(BadValue, "Can't create a lease with NULL HW address");
  989. }
  990. time_t now = time(NULL);
  991. // @todo: remove this kludge after ticket #2590 is implemented
  992. std::vector<uint8_t> local_copy;
  993. if (clientid) {
  994. local_copy = clientid->getDuid();
  995. }
  996. Lease4Ptr lease(new Lease4(addr, hwaddr, &local_copy[0], local_copy.size(),
  997. subnet->getValid(), subnet->getT1(), subnet->getT2(),
  998. now, subnet->getID()));
  999. // Set FQDN specific lease parameters.
  1000. lease->fqdn_fwd_ = fwd_dns_update;
  1001. lease->fqdn_rev_ = rev_dns_update;
  1002. lease->hostname_ = hostname;
  1003. // Let's execute all callouts registered for lease4_select
  1004. if (callout_handle &&
  1005. HooksManager::getHooksManager().calloutsPresent(hook_index_lease4_select_)) {
  1006. // Delete all previous arguments
  1007. callout_handle->deleteAllArguments();
  1008. // Pass necessary arguments
  1009. // Subnet from which we do the allocation (That's as far as we can go
  1010. // with using SubnetPtr to point to Subnet4 object. Users should not
  1011. // be confused with dynamic_pointer_casts. They should get a concrete
  1012. // pointer (Subnet4Ptr) pointing to a Subnet4 object.
  1013. Subnet4Ptr subnet4 = boost::dynamic_pointer_cast<Subnet4>(subnet);
  1014. callout_handle->setArgument("subnet4", subnet4);
  1015. // Is this solicit (fake = true) or request (fake = false)
  1016. callout_handle->setArgument("fake_allocation", fake_allocation);
  1017. // Pass the intended lease as well
  1018. callout_handle->setArgument("lease4", lease);
  1019. // This is the first callout, so no need to clear any arguments
  1020. HooksManager::callCallouts(hook_index_lease4_select_, *callout_handle);
  1021. // Callouts decided to skip the action. This means that the lease is not
  1022. // assigned, so the client will get NoAddrAvail as a result. The lease
  1023. // won't be inserted into the database.
  1024. if (callout_handle->getSkip()) {
  1025. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_HOOKS, DHCPSRV_HOOK_LEASE4_SELECT_SKIP);
  1026. return (Lease4Ptr());
  1027. }
  1028. // Let's use whatever callout returned. Hopefully it is the same lease
  1029. // we handled to it.
  1030. callout_handle->getArgument("lease4", lease);
  1031. }
  1032. if (!fake_allocation) {
  1033. // That is a real (REQUEST) allocation
  1034. bool status = LeaseMgrFactory::instance().addLease(lease);
  1035. if (status) {
  1036. return (lease);
  1037. } else {
  1038. // One of many failures with LeaseMgr (e.g. lost connection to the
  1039. // database, database failed etc.). One notable case for that
  1040. // is that we are working in multi-process mode and we lost a race
  1041. // (some other process got that address first)
  1042. return (Lease4Ptr());
  1043. }
  1044. } else {
  1045. // That is only fake (DISCOVER) allocation
  1046. // It is for OFFER only. We should not insert the lease into LeaseMgr,
  1047. // but rather check that we could have inserted it.
  1048. Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(addr);
  1049. if (!existing) {
  1050. return (lease);
  1051. } else {
  1052. return (Lease4Ptr());
  1053. }
  1054. }
  1055. }
  1056. void
  1057. AllocEngine::updateLease4Information(const Lease4Ptr& lease,
  1058. AllocEngine::ClientContext4& ctx) const {
  1059. // This should not happen in theory.
  1060. if (!lease) {
  1061. isc_throw(BadValue, "null lease specified for updateLease4Information");
  1062. }
  1063. if (!ctx.subnet_) {
  1064. isc_throw(BadValue, "null subnet specified for"
  1065. " updateLease4Information");
  1066. }
  1067. lease->subnet_id_ = ctx.subnet_->getID();
  1068. lease->hwaddr_ = ctx.hwaddr_;
  1069. lease->client_id_ = ctx.clientid_;
  1070. lease->cltt_ = time(NULL);
  1071. lease->t1_ = ctx.subnet_->getT1();
  1072. lease->t2_ = ctx.subnet_->getT2();
  1073. lease->valid_lft_ = ctx.subnet_->getValid();
  1074. lease->fqdn_fwd_ = ctx.fwd_dns_update_;
  1075. lease->fqdn_rev_ = ctx.rev_dns_update_;
  1076. lease->hostname_ = ctx.hostname_;
  1077. }
  1078. Lease6Collection
  1079. AllocEngine::updateFqdnData(const Lease6Collection& leases,
  1080. const bool fwd_dns_update,
  1081. const bool rev_dns_update,
  1082. const std::string& hostname,
  1083. const bool fake_allocation) {
  1084. Lease6Collection updated_leases;
  1085. for (Lease6Collection::const_iterator lease_it = leases.begin();
  1086. lease_it != leases.end(); ++lease_it) {
  1087. Lease6Ptr lease(new Lease6(**lease_it));
  1088. lease->fqdn_fwd_ = fwd_dns_update;
  1089. lease->fqdn_rev_ = rev_dns_update;
  1090. lease->hostname_ = hostname;
  1091. if (!fake_allocation &&
  1092. ((lease->fqdn_fwd_ != (*lease_it)->fqdn_fwd_) ||
  1093. (lease->fqdn_rev_ != (*lease_it)->fqdn_rev_) ||
  1094. (lease->hostname_ != (*lease_it)->hostname_))) {
  1095. LeaseMgrFactory::instance().updateLease6(lease);
  1096. }
  1097. updated_leases.push_back(lease);
  1098. }
  1099. return (updated_leases);
  1100. }
  1101. AllocEngine::AllocatorPtr AllocEngine::getAllocator(Lease::Type type) {
  1102. std::map<Lease::Type, AllocatorPtr>::const_iterator alloc = allocators_.find(type);
  1103. if (alloc == allocators_.end()) {
  1104. isc_throw(BadValue, "No allocator initialized for pool type "
  1105. << Lease::typeToText(type));
  1106. }
  1107. return (alloc->second);
  1108. }
  1109. AllocEngine::~AllocEngine() {
  1110. // no need to delete allocator. smart_ptr will do the trick for us
  1111. }
  1112. }; // end of isc::dhcp namespace
  1113. }; // end of isc namespace