memfile_lease_mgr.cc 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. // Copyright (C) 2012-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/cfgmgr.h>
  8. #include <dhcpsrv/dhcpsrv_log.h>
  9. #include <dhcpsrv/lease_file_loader.h>
  10. #include <dhcpsrv/memfile_lease_mgr.h>
  11. #include <dhcpsrv/timer_mgr.h>
  12. #include <dhcpsrv/database_connection.h>
  13. #include <exceptions/exceptions.h>
  14. #include <util/pid_file.h>
  15. #include <util/process_spawn.h>
  16. #include <util/signal_set.h>
  17. #include <cstdio>
  18. #include <cstring>
  19. #include <errno.h>
  20. #include <iostream>
  21. #include <limits>
  22. #include <sstream>
  23. namespace {
  24. /// @brief Maximum number of errors to read the leases from the lease file.
  25. const uint32_t MAX_LEASE_ERRORS = 100;
  26. /// @brief A name of the environmental variable specifying the kea-lfc
  27. /// program location.
  28. ///
  29. /// This variable can be set by tests to point to the location of the
  30. /// kea-lfc program within a build directory. If this variable is not
  31. /// set, the backend will use the location of the kea-lfc in the
  32. /// Kea installation directory.
  33. const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";
  34. } // end of anonymous namespace
  35. using namespace isc::util;
  36. namespace isc {
  37. namespace dhcp {
  38. /// @brief Represents a configuration for Lease File Cleanup.
  39. ///
  40. /// This class is solely used by the @c Memfile_LeaseMgr as a configuration
  41. /// information storage for %Lease File Cleanup. Internally, it creates
  42. /// the interval timer and assigns a callback function (pointer to which is
  43. /// passed in the constructor), which will be called at the specified
  44. /// intervals to perform the cleanup. It is also responsible for creating
  45. /// and maintaing the object which is used to spawn the new process which
  46. /// executes the @c kea-lfc program.
  47. ///
  48. /// This functionality is enclosed in a separate class so as the implementation
  49. /// details are not exposed in the @c Memfile_LeaseMgr header file and
  50. /// to maintain a single place with the LFC configuration, instead of multiple
  51. /// members and functions scattered in the @c Memfile_LeaseMgr class.
  52. class LFCSetup {
  53. public:
  54. /// @brief Constructor.
  55. ///
  56. /// Assigns a pointer to the function triggered to perform the cleanup.
  57. /// This pointer should point to the appropriate method of the
  58. /// @c Memfile_LeaseMgr class.
  59. ///
  60. /// @param callback A pointer to the callback function.
  61. LFCSetup(asiolink::IntervalTimer::Callback callback);
  62. /// @brief Destructor.
  63. ///
  64. /// Unregisters LFC timer.
  65. ~LFCSetup();
  66. /// @brief Sets the new configuration for the %Lease File Cleanup.
  67. ///
  68. /// @param lfc_interval An interval in seconds at which the cleanup should
  69. /// be performed.
  70. /// @param lease_file4 A pointer to the DHCPv4 lease file to be cleaned up
  71. /// or NULL. If this is NULL, the @c lease_file6 must be non-null.
  72. /// @param lease_file6 A pointer to the DHCPv6 lease file to be cleaned up
  73. /// or NULL. If this is NULL, the @c lease_file4 must be non-null.
  74. /// @param run_once_now A flag that causes LFC to be invoked immediately,
  75. /// regardless of the value of lfc_interval. This is primarily used to
  76. /// cause lease file schema upgrades upon startup.
  77. void setup(const uint32_t lfc_interval,
  78. const boost::shared_ptr<CSVLeaseFile4>& lease_file4,
  79. const boost::shared_ptr<CSVLeaseFile6>& lease_file6,
  80. bool run_once_now = false);
  81. /// @brief Spawns a new process.
  82. void execute();
  83. /// @brief Checks if the lease file cleanup is in progress.
  84. ///
  85. /// @return true if the lease file cleanup is being executed.
  86. bool isRunning() const;
  87. /// @brief Returns exit code of the last completed cleanup.
  88. int getExitStatus() const;
  89. private:
  90. /// @brief A pointer to the @c ProcessSpawn object used to execute
  91. /// the LFC.
  92. boost::scoped_ptr<util::ProcessSpawn> process_;
  93. /// @brief A pointer to the callback function executed by the timer.
  94. asiolink::IntervalTimer::Callback callback_;
  95. /// @brief A PID of the last executed LFC process.
  96. pid_t pid_;
  97. /// @brief Pointer to the timer manager.
  98. ///
  99. /// We have to hold this pointer here to make sure that the timer
  100. /// manager is not destroyed before the lease manager.
  101. TimerMgrPtr timer_mgr_;
  102. };
  103. LFCSetup::LFCSetup(asiolink::IntervalTimer::Callback callback)
  104. : process_(), callback_(callback), pid_(0),
  105. timer_mgr_(TimerMgr::instance()) {
  106. }
  107. LFCSetup::~LFCSetup() {
  108. try {
  109. // If we're here it means that either the process is terminating
  110. // or we're reconfiguring the server. In both cases the thread has
  111. // probably been stopped already, but we make sure by calling
  112. // stopThread explicitly here.
  113. timer_mgr_->stopThread();
  114. // Remove the timer. This will throw an exception if the timer does not
  115. // exist. There are several possible reasons for this:
  116. // a) It hasn't been registered (although if the LFC Setup instance
  117. // exists it means that the timer must have been registered or that
  118. // such registration has been attempted).
  119. // b) The registration may fail if the duplicate timer exists or if the
  120. // TimerMgr's worker thread is running but if this happens it is a
  121. // programming error.
  122. // c) The program is shutting down and the timer has been removed by
  123. // another component.
  124. timer_mgr_->unregisterTimer("memfile-lfc");
  125. } catch (const std::exception& ex) {
  126. // We don't want exceptions being thrown from the destructor so we just
  127. // log a message here. The message is logged at debug severity as
  128. // we don't want an error message output during shutdown.
  129. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
  130. DHCPSRV_MEMFILE_LFC_UNREGISTER_TIMER_FAILED).arg(ex.what());
  131. }
  132. }
  133. void
  134. LFCSetup::setup(const uint32_t lfc_interval,
  135. const boost::shared_ptr<CSVLeaseFile4>& lease_file4,
  136. const boost::shared_ptr<CSVLeaseFile6>& lease_file6,
  137. bool run_once_now) {
  138. // If to nothing to do, punt
  139. if (lfc_interval == 0 && !run_once_now) {
  140. return;
  141. }
  142. // Start preparing the command line for kea-lfc.
  143. std::string executable;
  144. char* c_executable = getenv(KEA_LFC_EXECUTABLE_ENV_NAME);
  145. if (c_executable == NULL) {
  146. executable = KEA_LFC_EXECUTABLE;
  147. } else {
  148. executable = c_executable;
  149. }
  150. // Gather the base file name.
  151. std::string lease_file = lease_file4 ? lease_file4->getFilename() :
  152. lease_file6->getFilename();
  153. // Create the other names by appending suffixes to the base name.
  154. util::ProcessArgs args;
  155. // Universe: v4 or v6.
  156. args.push_back(lease_file4 ? "-4" : "-6");
  157. // Previous file.
  158. args.push_back("-x");
  159. args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
  160. Memfile_LeaseMgr::FILE_PREVIOUS));
  161. // Input file.
  162. args.push_back("-i");
  163. args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
  164. Memfile_LeaseMgr::FILE_INPUT));
  165. // Output file.
  166. args.push_back("-o");
  167. args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
  168. Memfile_LeaseMgr::FILE_OUTPUT));
  169. // Finish file.
  170. args.push_back("-f");
  171. args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
  172. Memfile_LeaseMgr::FILE_FINISH));
  173. // PID file.
  174. args.push_back("-p");
  175. args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
  176. Memfile_LeaseMgr::FILE_PID));
  177. // The configuration file is currently unused.
  178. args.push_back("-c");
  179. args.push_back("ignored-path");
  180. // Create the process (do not start it yet).
  181. process_.reset(new util::ProcessSpawn(executable, args));
  182. // If we've been told to run it once now, invoke the callback directly.
  183. if (run_once_now) {
  184. callback_();
  185. }
  186. // If it's suposed to run periodically, setup that now.
  187. if (lfc_interval > 0) {
  188. // Set the timer to call callback function periodically.
  189. LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SETUP).arg(lfc_interval);
  190. // Multiple the lfc_interval value by 1000 as this value specifies
  191. // a timeout in seconds, whereas the setup() method expects the
  192. // timeout in milliseconds.
  193. timer_mgr_->registerTimer("memfile-lfc", callback_, lfc_interval * 1000,
  194. asiolink::IntervalTimer::REPEATING);
  195. timer_mgr_->setup("memfile-lfc");
  196. }
  197. }
  198. void
  199. LFCSetup::execute() {
  200. try {
  201. LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_EXECUTE)
  202. .arg(process_->getCommandLine());
  203. pid_ = process_->spawn();
  204. } catch (const ProcessSpawnError&) {
  205. LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SPAWN_FAIL);
  206. }
  207. }
  208. bool
  209. LFCSetup::isRunning() const {
  210. return (process_ && process_->isRunning(pid_));
  211. }
  212. int
  213. LFCSetup::getExitStatus() const {
  214. if (!process_) {
  215. isc_throw(InvalidOperation, "unable to obtain LFC process exit code: "
  216. " the process is NULL");
  217. }
  218. return (process_->getExitStatus(pid_));
  219. }
  220. /// @brief Memfile derivation of the IPv4 statistical lease data query
  221. ///
  222. /// This class is used to recalculate IPv4 lease statistics for Memfile
  223. /// lease storage. It does so by iterating over the given storage,
  224. /// accumulating counts of leases in each of the monitored lease states
  225. /// for each subnet and storing these counts in an internal collection.
  226. /// The populated result set will contain one entry per monitored state
  227. /// per subnet.
  228. ///
  229. class MemfileAddressStatsQuery4 : public AddressStatsQuery4 {
  230. public:
  231. /// @brief Constructor
  232. ///
  233. /// @param storage4 A pointer to the v4 lease storage to be counted
  234. MemfileAddressStatsQuery4(Lease4Storage& storage4);
  235. /// @brief Destructor
  236. virtual ~MemfileAddressStatsQuery4() {};
  237. /// @brief Creates the IPv4 lease statistical data result set
  238. ///
  239. /// The result is populated by iterating over the IPv4 leases in storage,
  240. /// in ascending order by subnet ID, accumulating the lease state counts.
  241. /// At the completion of all entries for a given subnet, the counts are
  242. /// used to create AddressStatsRow4 instances which are appended to an
  243. /// internal vector. The process results in a vector containing one entry
  244. /// per state per subnet.
  245. ///
  246. /// Currently the states counted are:
  247. ///
  248. /// - Lease::STATE_DEFAULT (i.e. assigned)
  249. /// - Lease::STATE_DECLINED
  250. virtual void start();
  251. /// @brief Fetches the next row in the result set
  252. ///
  253. /// Once the internal result set has been populated by invoking the
  254. /// the start() method, this method is used to iterate over the
  255. /// result set rows. Once the last row has been fetched, subsequent
  256. /// calls will return false.
  257. /// @param row Storage for the fetched row
  258. ///
  259. /// @return True if the fetch succeeded, false if there are no more
  260. /// rows to fetch.
  261. virtual bool getNextRow(AddressStatsRow4& row);
  262. /// @brief Returns the number of rows in the result set
  263. /// @todo, should this be a virtual member of the base class?
  264. int getRowCount();
  265. private:
  266. /// @brief The Memfile storage containing the IPv4 leases to analyze
  267. Lease4Storage& storage4_;
  268. /// @brief A vector containing the "result set"
  269. std::vector<AddressStatsRow4> rows_;
  270. /// @brief An iterator for accessing the next row within the result set
  271. std::vector<AddressStatsRow4>::iterator next_pos_;
  272. };
  273. MemfileAddressStatsQuery4::MemfileAddressStatsQuery4(Lease4Storage& storage4)
  274. : storage4_(storage4), rows_(0), next_pos_(rows_.end()) {};
  275. void
  276. MemfileAddressStatsQuery4::start() {
  277. // Get the subnet_id index
  278. const Lease4StorageSubnetIdIndex& idx = storage4_.get<SubnetIdIndexTag>();
  279. // Iterate over the leases in order by subnet, accumulating per
  280. // subnet counts for each state of interest. As we finish each
  281. // subnet, add the appropriate rows to our result set.
  282. SubnetID cur_id = 0;
  283. int64_t assigned = 0;
  284. int64_t declined = 0;
  285. for(Lease4StorageSubnetIdIndex::const_iterator lease = idx.begin();
  286. lease != idx.end(); ++lease) {
  287. // If we've hit the next subnet, add rows for the current subnet
  288. // and wipe the accumulators
  289. if ((*lease)->subnet_id_ > cur_id) {
  290. if (cur_id > 0) {
  291. rows_.push_back(AddressStatsRow4(cur_id,Lease::STATE_DEFAULT,
  292. assigned));
  293. assigned = 0;
  294. rows_.push_back(AddressStatsRow4(cur_id, Lease::STATE_DECLINED,
  295. declined));
  296. declined = 0;
  297. }
  298. // Update current subnet id
  299. cur_id = (*lease)->subnet_id_;
  300. }
  301. // Bump the appropriate accumulator
  302. switch ((*lease)->state_) {
  303. case Lease::STATE_DEFAULT:
  304. ++assigned;
  305. break;
  306. case Lease::STATE_DECLINED:
  307. ++declined;
  308. break;
  309. default:
  310. // Not one we're tracking.
  311. break;
  312. }
  313. }
  314. // Make the rows for last subnet, unless there were no rows
  315. if (idx.begin() != idx.end()) {
  316. rows_.push_back(AddressStatsRow4(cur_id, Lease::STATE_DEFAULT,
  317. assigned));
  318. rows_.push_back(AddressStatsRow4(cur_id, Lease::STATE_DECLINED,
  319. declined));
  320. }
  321. // Set the next row position to the beginning of the rows.
  322. next_pos_ = rows_.begin();
  323. }
  324. bool
  325. MemfileAddressStatsQuery4::getNextRow(AddressStatsRow4& row) {
  326. if (next_pos_ == rows_.end()) {
  327. return (false);
  328. }
  329. row = *next_pos_;
  330. ++next_pos_;
  331. return (true);
  332. }
  333. int
  334. MemfileAddressStatsQuery4::getRowCount() {
  335. return (rows_.size());
  336. }
  337. // Explicit definition of class static constants. Values are given in the
  338. // declaration so they're not needed here.
  339. const int Memfile_LeaseMgr::MAJOR_VERSION;
  340. const int Memfile_LeaseMgr::MINOR_VERSION;
  341. Memfile_LeaseMgr::Memfile_LeaseMgr(const DatabaseConnection::ParameterMap& parameters)
  342. : LeaseMgr(), lfc_setup_(), conn_(parameters)
  343. {
  344. bool conversion_needed = false;
  345. // Check the universe and use v4 file or v6 file.
  346. std::string universe = conn_.getParameter("universe");
  347. if (universe == "4") {
  348. std::string file4 = initLeaseFilePath(V4);
  349. if (!file4.empty()) {
  350. conversion_needed = loadLeasesFromFiles<Lease4,
  351. CSVLeaseFile4>(file4,
  352. lease_file4_,
  353. storage4_);
  354. }
  355. } else {
  356. std::string file6 = initLeaseFilePath(V6);
  357. if (!file6.empty()) {
  358. conversion_needed = loadLeasesFromFiles<Lease6,
  359. CSVLeaseFile6>(file6,
  360. lease_file6_,
  361. storage6_);
  362. }
  363. }
  364. // If lease persistence have been disabled for both v4 and v6,
  365. // issue a warning. It is ok not to write leases to disk when
  366. // doing testing, but it should not be done in normal server
  367. // operation.
  368. if (!persistLeases(V4) && !persistLeases(V6)) {
  369. LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
  370. } else {
  371. if (conversion_needed) {
  372. LOG_WARN(dhcpsrv_logger, DHCPRSV_MEMFILE_CONVERTING_LEASE_FILES)
  373. .arg(MAJOR_VERSION).arg(MINOR_VERSION);
  374. }
  375. lfcSetup(conversion_needed);
  376. }
  377. }
  378. Memfile_LeaseMgr::~Memfile_LeaseMgr() {
  379. if (lease_file4_) {
  380. lease_file4_->close();
  381. lease_file4_.reset();
  382. }
  383. if (lease_file6_) {
  384. lease_file6_->close();
  385. lease_file6_.reset();
  386. }
  387. }
  388. std::string
  389. Memfile_LeaseMgr::getDBVersion() {
  390. std::stringstream tmp;
  391. tmp << "Memfile backend " << MAJOR_VERSION;
  392. tmp << "." << MINOR_VERSION;
  393. return (tmp.str());
  394. }
  395. bool
  396. Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
  397. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  398. DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
  399. if (getLease4(lease->addr_)) {
  400. // there is a lease with specified address already
  401. return (false);
  402. }
  403. // Try to write a lease to disk first. If this fails, the lease will
  404. // not be inserted to the memory and the disk and in-memory data will
  405. // remain consistent.
  406. if (persistLeases(V4)) {
  407. lease_file4_->append(*lease);
  408. }
  409. storage4_.insert(lease);
  410. return (true);
  411. }
  412. bool
  413. Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
  414. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  415. DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
  416. if (getLease6(lease->type_, lease->addr_)) {
  417. // there is a lease with specified address already
  418. return (false);
  419. }
  420. // Try to write a lease to disk first. If this fails, the lease will
  421. // not be inserted to the memory and the disk and in-memory data will
  422. // remain consistent.
  423. if (persistLeases(V6)) {
  424. lease_file6_->append(*lease);
  425. }
  426. storage6_.insert(lease);
  427. return (true);
  428. }
  429. Lease4Ptr
  430. Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
  431. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  432. DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
  433. const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
  434. Lease4StorageAddressIndex::iterator l = idx.find(addr);
  435. if (l == idx.end()) {
  436. return (Lease4Ptr());
  437. } else {
  438. return (Lease4Ptr(new Lease4(**l)));
  439. }
  440. }
  441. Lease4Collection
  442. Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
  443. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  444. DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
  445. Lease4Collection collection;
  446. const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
  447. for(Lease4StorageAddressIndex::const_iterator lease = idx.begin();
  448. lease != idx.end(); ++lease) {
  449. // Every Lease4 has a hardware address, so we can compare it
  450. if ( (*(*lease)->hwaddr_) == hwaddr) {
  451. collection.push_back((*lease));
  452. }
  453. }
  454. return (collection);
  455. }
  456. Lease4Ptr
  457. Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
  458. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  459. DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
  460. .arg(hwaddr.toText());
  461. // Get the index by HW Address and Subnet Identifier.
  462. const Lease4StorageHWAddressSubnetIdIndex& idx =
  463. storage4_.get<HWAddressSubnetIdIndexTag>();
  464. // Try to find the lease using HWAddr and subnet id.
  465. Lease4StorageHWAddressSubnetIdIndex::const_iterator lease =
  466. idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
  467. // Lease was not found. Return empty pointer to the caller.
  468. if (lease == idx.end()) {
  469. return (Lease4Ptr());
  470. }
  471. // Lease was found. Return it to the caller.
  472. return (Lease4Ptr(new Lease4(**lease)));
  473. }
  474. Lease4Collection
  475. Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
  476. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  477. DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
  478. Lease4Collection collection;
  479. const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
  480. for(Lease4StorageAddressIndex::const_iterator lease = idx.begin();
  481. lease != idx.end(); ++ lease) {
  482. // client-id is not mandatory in DHCPv4. There can be a lease that does
  483. // not have a client-id. Dereferencing null pointer would be a bad thing
  484. if((*lease)->client_id_ && *(*lease)->client_id_ == client_id) {
  485. collection.push_back((*lease));
  486. }
  487. }
  488. return (collection);
  489. }
  490. Lease4Ptr
  491. Memfile_LeaseMgr::getLease4(const ClientId& client_id,
  492. const HWAddr& hwaddr,
  493. SubnetID subnet_id) const {
  494. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  495. DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
  496. .arg(hwaddr.toText())
  497. .arg(subnet_id);
  498. // Get the index by client id, HW address and subnet id.
  499. const Lease4StorageClientIdHWAddressSubnetIdIndex& idx =
  500. storage4_.get<ClientIdHWAddressSubnetIdIndexTag>();
  501. // Try to get the lease using client id, hardware address and subnet id.
  502. Lease4StorageClientIdHWAddressSubnetIdIndex::const_iterator lease =
  503. idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
  504. subnet_id));
  505. if (lease == idx.end()) {
  506. // Lease was not found. Return empty pointer to the caller.
  507. return (Lease4Ptr());
  508. }
  509. // Lease was found. Return it to the caller.
  510. return (*lease);
  511. }
  512. Lease4Ptr
  513. Memfile_LeaseMgr::getLease4(const ClientId& client_id,
  514. SubnetID subnet_id) const {
  515. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  516. DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
  517. .arg(client_id.toText());
  518. // Get the index by client and subnet id.
  519. const Lease4StorageClientIdSubnetIdIndex& idx =
  520. storage4_.get<ClientIdSubnetIdIndexTag>();
  521. // Try to get the lease using client id and subnet id.
  522. Lease4StorageClientIdSubnetIdIndex::const_iterator lease =
  523. idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
  524. // Lease was not found. Return empty pointer to the caller.
  525. if (lease == idx.end()) {
  526. return (Lease4Ptr());
  527. }
  528. // Lease was found. Return it to the caller.
  529. return (Lease4Ptr(new Lease4(**lease)));
  530. }
  531. Lease6Ptr
  532. Memfile_LeaseMgr::getLease6(Lease::Type type,
  533. const isc::asiolink::IOAddress& addr) const {
  534. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  535. DHCPSRV_MEMFILE_GET_ADDR6)
  536. .arg(addr.toText())
  537. .arg(Lease::typeToText(type));
  538. Lease6Storage::iterator l = storage6_.find(addr);
  539. if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
  540. return (Lease6Ptr());
  541. } else {
  542. return (Lease6Ptr(new Lease6(**l)));
  543. }
  544. }
  545. Lease6Collection
  546. Memfile_LeaseMgr::getLeases6(Lease::Type type,
  547. const DUID& duid, uint32_t iaid) const {
  548. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  549. DHCPSRV_MEMFILE_GET_IAID_DUID)
  550. .arg(iaid)
  551. .arg(duid.toText())
  552. .arg(Lease::typeToText(type));
  553. // Get the index by DUID, IAID, lease type.
  554. const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
  555. // Try to get the lease using the DUID, IAID and lease type.
  556. std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
  557. Lease6StorageDuidIaidTypeIndex::const_iterator> l =
  558. idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
  559. Lease6Collection collection;
  560. for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
  561. l.first; lease != l.second; ++lease) {
  562. collection.push_back(Lease6Ptr(new Lease6(**lease)));
  563. }
  564. return (collection);
  565. }
  566. Lease6Collection
  567. Memfile_LeaseMgr::getLeases6(Lease::Type type,
  568. const DUID& duid, uint32_t iaid,
  569. SubnetID subnet_id) const {
  570. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  571. DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
  572. .arg(iaid)
  573. .arg(subnet_id)
  574. .arg(duid.toText())
  575. .arg(Lease::typeToText(type));
  576. // Get the index by DUID, IAID, lease type.
  577. const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
  578. // Try to get the lease using the DUID, IAID and lease type.
  579. std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
  580. Lease6StorageDuidIaidTypeIndex::const_iterator> l =
  581. idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
  582. Lease6Collection collection;
  583. for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
  584. l.first; lease != l.second; ++lease) {
  585. // Filter out the leases which subnet id doesn't match.
  586. if((*lease)->subnet_id_ == subnet_id) {
  587. collection.push_back(Lease6Ptr(new Lease6(**lease)));
  588. }
  589. }
  590. return (collection);
  591. }
  592. void
  593. Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
  594. const size_t max_leases) const {
  595. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED4)
  596. .arg(max_leases);
  597. // Obtain the index which segragates leases by state and time.
  598. const Lease6StorageExpirationIndex& index = storage6_.get<ExpirationIndexTag>();
  599. // Retrieve leases which are not reclaimed and which haven't expired. The
  600. // 'less-than' operator will be used for both components of the index. So,
  601. // for the 'state' 'false' is less than 'true'. Also the leases with
  602. // expiration time lower than current time will be returned.
  603. Lease6StorageExpirationIndex::const_iterator ub =
  604. index.upper_bound(boost::make_tuple(false, time(NULL)));
  605. // Copy only the number of leases indicated by the max_leases parameter.
  606. for (Lease6StorageExpirationIndex::const_iterator lease = index.begin();
  607. (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
  608. max_leases));
  609. ++lease) {
  610. expired_leases.push_back(Lease6Ptr(new Lease6(**lease)));
  611. }
  612. }
  613. void
  614. Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
  615. const size_t max_leases) const {
  616. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED6)
  617. .arg(max_leases);
  618. // Obtain the index which segragates leases by state and time.
  619. const Lease4StorageExpirationIndex& index = storage4_.get<ExpirationIndexTag>();
  620. // Retrieve leases which are not reclaimed and which haven't expired. The
  621. // 'less-than' operator will be used for both components of the index. So,
  622. // for the 'state' 'false' is less than 'true'. Also the leases with
  623. // expiration time lower than current time will be returned.
  624. Lease4StorageExpirationIndex::const_iterator ub =
  625. index.upper_bound(boost::make_tuple(false, time(NULL)));
  626. // Copy only the number of leases indicated by the max_leases parameter.
  627. for (Lease4StorageExpirationIndex::const_iterator lease = index.begin();
  628. (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
  629. max_leases));
  630. ++lease) {
  631. expired_leases.push_back(Lease4Ptr(new Lease4(**lease)));
  632. }
  633. }
  634. void
  635. Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
  636. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  637. DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
  638. // Obtain 'by address' index.
  639. Lease4StorageAddressIndex& index = storage4_.get<AddressIndexTag>();
  640. // Lease must exist if it is to be updated.
  641. Lease4StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
  642. if (lease_it == index.end()) {
  643. isc_throw(NoSuchLease, "failed to update the lease with address "
  644. << lease->addr_ << " - no such lease");
  645. }
  646. // Try to write a lease to disk first. If this fails, the lease will
  647. // not be inserted to the memory and the disk and in-memory data will
  648. // remain consistent.
  649. if (persistLeases(V4)) {
  650. lease_file4_->append(*lease);
  651. }
  652. // Use replace() to re-index leases.
  653. index.replace(lease_it, Lease4Ptr(new Lease4(*lease)));
  654. }
  655. void
  656. Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
  657. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  658. DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
  659. // Obtain 'by address' index.
  660. Lease6StorageAddressIndex& index = storage6_.get<AddressIndexTag>();
  661. // Lease must exist if it is to be updated.
  662. Lease6StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
  663. if (lease_it == index.end()) {
  664. isc_throw(NoSuchLease, "failed to update the lease with address "
  665. << lease->addr_ << " - no such lease");
  666. }
  667. // Try to write a lease to disk first. If this fails, the lease will
  668. // not be inserted to the memory and the disk and in-memory data will
  669. // remain consistent.
  670. if (persistLeases(V6)) {
  671. lease_file6_->append(*lease);
  672. }
  673. // Use replace() to re-index leases.
  674. index.replace(lease_it, Lease6Ptr(new Lease6(*lease)));
  675. }
  676. bool
  677. Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
  678. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  679. DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
  680. if (addr.isV4()) {
  681. // v4 lease
  682. Lease4Storage::iterator l = storage4_.find(addr);
  683. if (l == storage4_.end()) {
  684. // No such lease
  685. return (false);
  686. } else {
  687. if (persistLeases(V4)) {
  688. // Copy the lease. The valid lifetime needs to be modified and
  689. // we don't modify the original lease.
  690. Lease4 lease_copy = **l;
  691. // Setting valid lifetime to 0 means that lease is being
  692. // removed.
  693. lease_copy.valid_lft_ = 0;
  694. lease_file4_->append(lease_copy);
  695. }
  696. storage4_.erase(l);
  697. return (true);
  698. }
  699. } else {
  700. // v6 lease
  701. Lease6Storage::iterator l = storage6_.find(addr);
  702. if (l == storage6_.end()) {
  703. // No such lease
  704. return (false);
  705. } else {
  706. if (persistLeases(V6)) {
  707. // Copy the lease. The lifetimes need to be modified and we
  708. // don't modify the original lease.
  709. Lease6 lease_copy = **l;
  710. // Setting lifetimes to 0 means that lease is being removed.
  711. lease_copy.valid_lft_ = 0;
  712. lease_copy.preferred_lft_ = 0;
  713. lease_file6_->append(lease_copy);
  714. }
  715. storage6_.erase(l);
  716. return (true);
  717. }
  718. }
  719. }
  720. uint64_t
  721. Memfile_LeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
  722. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  723. DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED4)
  724. .arg(secs);
  725. return (deleteExpiredReclaimedLeases<
  726. Lease4StorageExpirationIndex, Lease4
  727. >(secs, V4, storage4_, lease_file4_));
  728. }
  729. uint64_t
  730. Memfile_LeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
  731. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  732. DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6)
  733. .arg(secs);
  734. return (deleteExpiredReclaimedLeases<
  735. Lease6StorageExpirationIndex, Lease6
  736. >(secs, V6, storage6_, lease_file6_));
  737. }
  738. template<typename IndexType, typename LeaseType, typename StorageType,
  739. typename LeaseFileType>
  740. uint64_t
  741. Memfile_LeaseMgr::deleteExpiredReclaimedLeases(const uint32_t secs,
  742. const Universe& universe,
  743. StorageType& storage,
  744. LeaseFileType& lease_file) const {
  745. // Obtain the index which segragates leases by state and time.
  746. IndexType& index = storage.template get<ExpirationIndexTag>();
  747. // This returns the first element which is greater than the specified
  748. // tuple (true, time(NULL) - secs). However, the range between the
  749. // beginnng of the index and returned element also includes all the
  750. // elements for which the first value is false (lease state is NOT
  751. // reclaimed), because false < true. All elements between the
  752. // beginning of the index and the element returned, for which the
  753. // first value is true, represent the reclaimed leases which should
  754. // be deleted, because their expiration time + secs has occured earlier
  755. // than current time.
  756. typename IndexType::const_iterator upper_limit =
  757. index.upper_bound(boost::make_tuple(true, time(NULL) - secs));
  758. // Now, we have to exclude all elements of the index which represent
  759. // leases in the state other than reclaimed - with the first value
  760. // in the index equal to false. Note that elements in the index are
  761. // ordered from the lower to the higher ones. So, all elements with
  762. // the first value of false are placed before the elements with the
  763. // value of true. Hence, we have to find the first element which
  764. // contains value of true. The time value is the lowest possible.
  765. typename IndexType::const_iterator lower_limit =
  766. index.upper_bound(boost::make_tuple(true, std::numeric_limits<int64_t>::min()));
  767. // If there are some elements in this range, delete them.
  768. uint64_t num_leases = static_cast<uint64_t>(std::distance(lower_limit, upper_limit));
  769. if (num_leases > 0) {
  770. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  771. DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START)
  772. .arg(num_leases);
  773. // If lease persistence is enabled, we also have to mark leases
  774. // as deleted in the lease file. We do this by setting the
  775. // lifetime to 0.
  776. if (persistLeases(universe)) {
  777. for (typename IndexType::const_iterator lease = lower_limit;
  778. lease != upper_limit; ++lease) {
  779. // Copy lease to not affect the lease in the container.
  780. LeaseType lease_copy(**lease);
  781. // Set the valid lifetime to 0 to indicate the removal
  782. // of the lease.
  783. lease_copy.valid_lft_ = 0;
  784. lease_file->append(lease_copy);
  785. }
  786. }
  787. // Erase leases from memory.
  788. index.erase(lower_limit, upper_limit);
  789. }
  790. // Return number of leases deleted.
  791. return (num_leases);
  792. }
  793. std::string
  794. Memfile_LeaseMgr::getDescription() const {
  795. return (std::string("In memory database with leases stored in a CSV file."));
  796. }
  797. void
  798. Memfile_LeaseMgr::commit() {
  799. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
  800. }
  801. void
  802. Memfile_LeaseMgr::rollback() {
  803. LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
  804. DHCPSRV_MEMFILE_ROLLBACK);
  805. }
  806. std::string
  807. Memfile_LeaseMgr::appendSuffix(const std::string& file_name,
  808. const LFCFileType& file_type) {
  809. std::string name(file_name);
  810. switch (file_type) {
  811. case FILE_INPUT:
  812. name += ".1";
  813. break;
  814. case FILE_PREVIOUS:
  815. name += ".2";
  816. break;
  817. case FILE_OUTPUT:
  818. name += ".output";
  819. break;
  820. case FILE_FINISH:
  821. name += ".completed";
  822. break;
  823. case FILE_PID:
  824. name += ".pid";
  825. break;
  826. default:
  827. // Do not append any suffix for the FILE_CURRENT.
  828. ;
  829. }
  830. return (name);
  831. }
  832. std::string
  833. Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
  834. std::ostringstream s;
  835. s << CfgMgr::instance().getDataDir() << "/kea-leases";
  836. s << (u == V4 ? "4" : "6");
  837. s << ".csv";
  838. return (s.str());
  839. }
  840. std::string
  841. Memfile_LeaseMgr::getLeaseFilePath(Universe u) const {
  842. if (u == V4) {
  843. return (lease_file4_ ? lease_file4_->getFilename() : "");
  844. }
  845. return (lease_file6_ ? lease_file6_->getFilename() : "");
  846. }
  847. bool
  848. Memfile_LeaseMgr::persistLeases(Universe u) const {
  849. // Currently, if the lease file IO is not created, it means that writes to
  850. // disk have been explicitly disabled by the administrator. At some point,
  851. // there may be a dedicated ON/OFF flag implemented to control this.
  852. if (u == V4 && lease_file4_) {
  853. return (true);
  854. }
  855. return (u == V6 && lease_file6_);
  856. }
  857. std::string
  858. Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
  859. std::string persist_val;
  860. try {
  861. persist_val = conn_.getParameter("persist");
  862. } catch (const Exception&) {
  863. // If parameter persist hasn't been specified, we use a default value
  864. // 'yes'.
  865. persist_val = "true";
  866. }
  867. // If persist_val is 'false' we will not store leases to disk, so let's
  868. // return empty file name.
  869. if (persist_val == "false") {
  870. return ("");
  871. } else if (persist_val != "true") {
  872. isc_throw(isc::BadValue, "invalid value 'persist="
  873. << persist_val << "'");
  874. }
  875. std::string lease_file;
  876. try {
  877. lease_file = conn_.getParameter("name");
  878. } catch (const Exception&) {
  879. lease_file = getDefaultLeaseFilePath(u);
  880. }
  881. return (lease_file);
  882. }
  883. template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
  884. bool Memfile_LeaseMgr::loadLeasesFromFiles(const std::string& filename,
  885. boost::shared_ptr<LeaseFileType>& lease_file,
  886. StorageType& storage) {
  887. // Check if the instance of the LFC is running right now. If it is
  888. // running, we refuse to load leases as the LFC may be writing to the
  889. // lease files right now. When the user retries server configuration
  890. // it should go through.
  891. /// @todo Consider applying a timeout for an LFC and retry when this
  892. /// timeout elapses.
  893. PIDFile pid_file(appendSuffix(filename, FILE_PID));
  894. if (pid_file.check()) {
  895. isc_throw(DbOpenError, "unable to load leases from files while the "
  896. "lease file cleanup is in progress");
  897. }
  898. storage.clear();
  899. // Load the leasefile.completed, if exists.
  900. bool conversion_needed = false;
  901. lease_file.reset(new LeaseFileType(std::string(filename + ".completed")));
  902. if (lease_file->exists()) {
  903. LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
  904. MAX_LEASE_ERRORS);
  905. conversion_needed = conversion_needed || lease_file->needsConversion();
  906. } else {
  907. // If the leasefile.completed doesn't exist, let's load the leases
  908. // from leasefile.2 and leasefile.1, if they exist.
  909. lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_PREVIOUS)));
  910. if (lease_file->exists()) {
  911. LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
  912. MAX_LEASE_ERRORS);
  913. conversion_needed = conversion_needed || lease_file->needsConversion();
  914. }
  915. lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_INPUT)));
  916. if (lease_file->exists()) {
  917. LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
  918. MAX_LEASE_ERRORS);
  919. conversion_needed = conversion_needed || lease_file->needsConversion();
  920. }
  921. }
  922. // Always load leases from the primary lease file. If the lease file
  923. // doesn't exist it will be created by the LeaseFileLoader. Note
  924. // that the false value passed as the last parameter to load
  925. // function causes the function to leave the file open after
  926. // it is parsed. This file will be used by the backend to record
  927. // future lease updates.
  928. lease_file.reset(new LeaseFileType(filename));
  929. LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
  930. MAX_LEASE_ERRORS, false);
  931. conversion_needed = conversion_needed || lease_file->needsConversion();
  932. return (conversion_needed);
  933. }
  934. bool
  935. Memfile_LeaseMgr::isLFCRunning() const {
  936. return (lfc_setup_->isRunning());
  937. }
  938. int
  939. Memfile_LeaseMgr::getLFCExitStatus() const {
  940. return (lfc_setup_->getExitStatus());
  941. }
  942. void
  943. Memfile_LeaseMgr::lfcCallback() {
  944. LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_START);
  945. // Check if we're in the v4 or v6 space and use the appropriate file.
  946. if (lease_file4_) {
  947. lfcExecute(lease_file4_);
  948. } else if (lease_file6_) {
  949. lfcExecute(lease_file6_);
  950. }
  951. }
  952. void
  953. Memfile_LeaseMgr::lfcSetup(bool conversion_needed) {
  954. std::string lfc_interval_str = "0";
  955. try {
  956. lfc_interval_str = conn_.getParameter("lfc-interval");
  957. } catch (const std::exception&) {
  958. // Ignore and default to 0.
  959. }
  960. uint32_t lfc_interval = 0;
  961. try {
  962. lfc_interval = boost::lexical_cast<uint32_t>(lfc_interval_str);
  963. } catch (boost::bad_lexical_cast&) {
  964. isc_throw(isc::BadValue, "invalid value of the lfc-interval "
  965. << lfc_interval_str << " specified");
  966. }
  967. if (lfc_interval > 0 || conversion_needed) {
  968. lfc_setup_.reset(new LFCSetup(boost::bind(&Memfile_LeaseMgr::lfcCallback, this)));
  969. lfc_setup_->setup(lfc_interval, lease_file4_, lease_file6_, conversion_needed);
  970. }
  971. }
  972. template<typename LeaseFileType>
  973. void Memfile_LeaseMgr::lfcExecute(boost::shared_ptr<LeaseFileType>& lease_file) {
  974. bool do_lfc = true;
  975. // Check the status of the LFC instance.
  976. // If the finish file exists or the copy of the lease file exists it
  977. // is an indication that another LFC instance may be in progress or
  978. // may be stalled. In that case we don't want to rotate the current
  979. // lease file to avoid overriding the contents of the existing file.
  980. CSVFile lease_file_finish(appendSuffix(lease_file->getFilename(), FILE_FINISH));
  981. CSVFile lease_file_copy(appendSuffix(lease_file->getFilename(), FILE_INPUT));
  982. if (!lease_file_finish.exists() && !lease_file_copy.exists()) {
  983. // Close the current file so as we can move it to the copy file.
  984. lease_file->close();
  985. // Move the current file to the copy file. Remember the result
  986. // because we don't want to run LFC if the rename failed.
  987. do_lfc = (rename(lease_file->getFilename().c_str(),
  988. lease_file_copy.getFilename().c_str()) == 0);
  989. if (!do_lfc) {
  990. LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_LEASE_FILE_RENAME_FAIL)
  991. .arg(lease_file->getFilename())
  992. .arg(lease_file_copy.getFilename())
  993. .arg(strerror(errno));
  994. }
  995. // Regardless if we successfully moved the current file or not,
  996. // we need to re-open the current file for the server to write
  997. // new lease updates. If the file has been successfully moved,
  998. // this will result in creation of the new file. Otherwise,
  999. // an existing file will be opened.
  1000. try {
  1001. lease_file->open(true);
  1002. } catch (const CSVFileError& ex) {
  1003. // If we're unable to open the lease file this is a serious
  1004. // error because the server will not be able to persist
  1005. // leases.
  1006. /// @todo We need to better address this error. It should
  1007. /// trigger an alarm (once we have a monitoring system in
  1008. /// place) so as an administrator can correct it. In
  1009. /// practice it should be very rare that this happens and
  1010. /// is most likely related to a human error, e.g. changing
  1011. /// file permissions.
  1012. LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_LEASE_FILE_REOPEN_FAIL)
  1013. .arg(lease_file->getFilename())
  1014. .arg(ex.what());
  1015. // Reset the pointer to the file so as the backend doesn't
  1016. // try to write leases to disk.
  1017. lease_file.reset();
  1018. do_lfc = false;
  1019. }
  1020. }
  1021. // Once the files have been rotated, or untouched if another LFC had
  1022. // not finished, a new process is started.
  1023. if (do_lfc) {
  1024. lfc_setup_->execute();
  1025. }
  1026. }
  1027. AddressStatsQuery4Ptr
  1028. Memfile_LeaseMgr::startAddressStatsQuery4() {
  1029. AddressStatsQuery4Ptr query(new MemfileAddressStatsQuery4(storage4_));
  1030. query->start();
  1031. return(query);
  1032. }
  1033. } // end of namespace isc::dhcp
  1034. } // end of namespace isc