Kea  1.5.0
memfile_lease_mgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2018 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 
7 #include <config.h>
9 #include <dhcpsrv/cfgmgr.h>
11 #include <dhcpsrv/dhcpsrv_log.h>
14 #include <dhcpsrv/timer_mgr.h>
15 #include <exceptions/exceptions.h>
16 #include <util/pid_file.h>
17 #include <util/process_spawn.h>
18 #include <util/signal_set.h>
19 #include <cstdio>
20 #include <cstring>
21 #include <errno.h>
22 #include <iostream>
23 #include <limits>
24 #include <sstream>
25 
26 namespace {
27 
29 const uint32_t MAX_LEASE_ERRORS = 100;
30 
38 const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";
39 
40 } // end of anonymous namespace
41 
42 using namespace isc::asiolink;
43 using namespace isc::db;
44 using namespace isc::util;
45 
46 namespace isc {
47 namespace dhcp {
48 
63 class LFCSetup {
64 public:
65 
74 
78  ~LFCSetup();
79 
91  void setup(const uint32_t lfc_interval,
92  const boost::shared_ptr<CSVLeaseFile4>& lease_file4,
93  const boost::shared_ptr<CSVLeaseFile6>& lease_file6,
94  bool run_once_now = false);
95 
97  void execute();
98 
102  bool isRunning() const;
103 
105  int getExitStatus() const;
106 
107 private:
108 
111  boost::scoped_ptr<util::ProcessSpawn> process_;
112 
115 
117  pid_t pid_;
118 
123  TimerMgrPtr timer_mgr_;
124 };
125 
126 LFCSetup::LFCSetup(asiolink::IntervalTimer::Callback callback)
127  : process_(), callback_(callback), pid_(0),
128  timer_mgr_(TimerMgr::instance()) {
129 }
130 
132  try {
133  // Remove the timer. This will throw an exception if the timer does not
134  // exist. There are several possible reasons for this:
135  // a) It hasn't been registered (although if the LFC Setup instance
136  // exists it means that the timer must have been registered or that
137  // such registration has been attempted).
138  // b) The registration may fail if the duplicate timer exists or if the
139  // TimerMgr's worker thread is running but if this happens it is a
140  // programming error.
141  // c) The program is shutting down and the timer has been removed by
142  // another component.
143  timer_mgr_->unregisterTimer("memfile-lfc");
144 
145  } catch (const std::exception& ex) {
146  // We don't want exceptions being thrown from the destructor so we just
147  // log a message here. The message is logged at debug severity as
148  // we don't want an error message output during shutdown.
150  DHCPSRV_MEMFILE_LFC_UNREGISTER_TIMER_FAILED).arg(ex.what());
151  }
152 }
153 
154 void
155 LFCSetup::setup(const uint32_t lfc_interval,
156  const boost::shared_ptr<CSVLeaseFile4>& lease_file4,
157  const boost::shared_ptr<CSVLeaseFile6>& lease_file6,
158  bool run_once_now) {
159 
160  // If to nothing to do, punt
161  if (lfc_interval == 0 && !run_once_now) {
162  return;
163  }
164 
165  // Start preparing the command line for kea-lfc.
166  std::string executable;
167  char* c_executable = getenv(KEA_LFC_EXECUTABLE_ENV_NAME);
168  if (c_executable == NULL) {
169  executable = KEA_LFC_EXECUTABLE;
170  } else {
171  executable = c_executable;
172  }
173 
174  // Gather the base file name.
175  std::string lease_file = lease_file4 ? lease_file4->getFilename() :
176  lease_file6->getFilename();
177 
178  // Create the other names by appending suffixes to the base name.
179  util::ProcessArgs args;
180  // Universe: v4 or v6.
181  args.push_back(lease_file4 ? "-4" : "-6");
182 
183  // Previous file.
184  args.push_back("-x");
185  args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
187  // Input file.
188  args.push_back("-i");
189  args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
191  // Output file.
192  args.push_back("-o");
193  args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
195  // Finish file.
196  args.push_back("-f");
197  args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
199  // PID file.
200  args.push_back("-p");
201  args.push_back(Memfile_LeaseMgr::appendSuffix(lease_file,
203 
204  // The configuration file is currently unused.
205  args.push_back("-c");
206  args.push_back("ignored-path");
207 
208  // Create the process (do not start it yet).
209  process_.reset(new util::ProcessSpawn(executable, args));
210 
211  // If we've been told to run it once now, invoke the callback directly.
212  if (run_once_now) {
213  callback_();
214  }
215 
216  // If it's supposed to run periodically, setup that now.
217  if (lfc_interval > 0) {
218  // Set the timer to call callback function periodically.
219  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SETUP).arg(lfc_interval);
220 
221  // Multiple the lfc_interval value by 1000 as this value specifies
222  // a timeout in seconds, whereas the setup() method expects the
223  // timeout in milliseconds.
224  timer_mgr_->registerTimer("memfile-lfc", callback_, lfc_interval * 1000,
226  timer_mgr_->setup("memfile-lfc");
227  }
228 }
229 
230 void
232  try {
233  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_EXECUTE)
234  .arg(process_->getCommandLine());
235  pid_ = process_->spawn();
236 
237  } catch (const ProcessSpawnError&) {
238  LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SPAWN_FAIL);
239  }
240 }
241 
242 bool
244  return (process_ && process_->isRunning(pid_));
245 }
246 
247 int
249  if (!process_) {
250  isc_throw(InvalidOperation, "unable to obtain LFC process exit code: "
251  " the process is NULL");
252  }
253  return (process_->getExitStatus(pid_));
254 }
255 
256 
263 public:
267  : rows_(0), next_pos_(rows_.end()) {
268  };
269 
274  : LeaseStatsQuery(subnet_id), rows_(0), next_pos_(rows_.end()) {
275  };
276 
281  MemfileLeaseStatsQuery(const SubnetID& first_subnet_id, const SubnetID& last_subnet_id)
282  : LeaseStatsQuery(first_subnet_id, last_subnet_id), rows_(0), next_pos_(rows_.end()) {
283  };
284 
287 
298  virtual bool getNextRow(LeaseStatsRow& row) {
299  if (next_pos_ == rows_.end()) {
300  return (false);
301  }
302 
303  row = *next_pos_;
304  ++next_pos_;
305  return (true);
306  }
307 
309  int getRowCount() const {
310  return (rows_.size());
311  }
312 
313 protected:
315  std::vector<LeaseStatsRow> rows_;
316 
318  std::vector<LeaseStatsRow>::iterator next_pos_;
319 };
320 
331 public:
336  : MemfileLeaseStatsQuery(), storage4_(storage4) {
337  };
338 
343  MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& subnet_id)
344  : MemfileLeaseStatsQuery(subnet_id), storage4_(storage4) {
345  };
346 
352  MemfileLeaseStatsQuery4(Lease4Storage& storage4, const SubnetID& first_subnet_id,
353  const SubnetID& last_subnet_id)
354  : MemfileLeaseStatsQuery(first_subnet_id, last_subnet_id), storage4_(storage4) {
355  };
356 
359 
374  void start() {
375  const Lease4StorageSubnetIdIndex& idx
376  = storage4_.get<SubnetIdIndexTag>();
377 
378  // Set lower and upper bounds based on select mode
379  Lease4StorageSubnetIdIndex::const_iterator lower;
380  Lease4StorageSubnetIdIndex::const_iterator upper;
381  switch (getSelectMode()) {
382  case ALL_SUBNETS:
383  lower = idx.begin();
384  upper = idx.end();
385  break;
386 
387  case SINGLE_SUBNET:
388  lower = idx.lower_bound(getFirstSubnetID());
389  upper = idx.upper_bound(getFirstSubnetID());
390  break;
391 
392  case SUBNET_RANGE:
393  lower = idx.lower_bound(getFirstSubnetID());
394  upper = idx.upper_bound(getLastSubnetID());
395  break;
396  }
397 
398  // Return an empty set if there are no rows.
399  if (lower == upper) {
400  return;
401  }
402 
403  // Iterate over the leases in order by subnet, accumulating per
404  // subnet counts for each state of interest. As we finish each
405  // subnet, add the appropriate rows to our result set.
406  SubnetID cur_id = 0;
407  int64_t assigned = 0;
408  int64_t declined = 0;
409  for(Lease4StorageSubnetIdIndex::const_iterator lease = lower;
410  lease != upper; ++lease) {
411  // If we've hit the next subnet, add rows for the current subnet
412  // and wipe the accumulators
413  if ((*lease)->subnet_id_ != cur_id) {
414  if (cur_id > 0) {
415  if (assigned > 0) {
416  rows_.push_back(LeaseStatsRow(cur_id,
418  assigned));
419  assigned = 0;
420  }
421 
422  if (declined > 0) {
423  rows_.push_back(LeaseStatsRow(cur_id,
425  declined));
426  declined = 0;
427  }
428  }
429 
430  // Update current subnet id
431  cur_id = (*lease)->subnet_id_;
432  }
433 
434  // Bump the appropriate accumulator
435  if ((*lease)->state_ == Lease::STATE_DEFAULT) {
436  ++assigned;
437  } else if ((*lease)->state_ == Lease::STATE_DECLINED) {
438  ++declined;
439  }
440  }
441 
442  // Make the rows for last subnet
443  if (assigned > 0) {
444  rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DEFAULT,
445  assigned));
446  }
447 
448  if (declined > 0) {
449  rows_.push_back(LeaseStatsRow(cur_id, Lease::STATE_DECLINED,
450  declined));
451  }
452 
453  // Reset the next row position back to the beginning of the rows.
454  next_pos_ = rows_.begin();
455  }
456 
457 private:
459  Lease4Storage& storage4_;
460 };
461 
462 
473 public:
478  : MemfileLeaseStatsQuery(), storage6_(storage6) {
479  };
480 
485  MemfileLeaseStatsQuery6(Lease6Storage& storage6, const SubnetID& subnet_id)
486  : MemfileLeaseStatsQuery(subnet_id), storage6_(storage6) {
487  };
488 
494  MemfileLeaseStatsQuery6(Lease6Storage& storage6, const SubnetID& first_subnet_id,
495  const SubnetID& last_subnet_id)
496  : MemfileLeaseStatsQuery(first_subnet_id, last_subnet_id), storage6_(storage6) {
497  };
498 
501 
515  virtual void start() {
516  // Get the subnet_id index
517  const Lease6StorageSubnetIdIndex& idx
518  = storage6_.get<SubnetIdIndexTag>();
519 
520  // Set lower and upper bounds based on select mode
521  Lease6StorageSubnetIdIndex::const_iterator lower;
522  Lease6StorageSubnetIdIndex::const_iterator upper;
523  switch (getSelectMode()) {
524  case ALL_SUBNETS:
525  lower = idx.begin();
526  upper = idx.end();
527  break;
528 
529  case SINGLE_SUBNET:
530  lower = idx.lower_bound(getFirstSubnetID());
531  upper = idx.upper_bound(getFirstSubnetID());
532  break;
533 
534  case SUBNET_RANGE:
535  lower = idx.lower_bound(getFirstSubnetID());
536  upper = idx.upper_bound(getLastSubnetID());
537  break;
538  }
539 
540  // Return an empty set if there are no rows.
541  if (lower == upper) {
542  return;
543  }
544 
545  // Iterate over the leases in order by subnet, accumulating per
546  // subnet counts for each state of interest. As we finish each
547  // subnet, add the appropriate rows to our result set.
548  SubnetID cur_id = 0;
549  int64_t assigned = 0;
550  int64_t declined = 0;
551  int64_t assigned_pds = 0;
552  for(Lease6StorageSubnetIdIndex::const_iterator lease = lower;
553  lease != upper; ++lease) {
554  // If we've hit the next subnet, add rows for the current subnet
555  // and wipe the accumulators
556  if ((*lease)->subnet_id_ != cur_id) {
557  if (cur_id > 0) {
558  if (assigned > 0) {
559  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
561  assigned));
562  assigned = 0;
563  }
564 
565  if (declined > 0) {
566  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
568  declined));
569  declined = 0;
570  }
571 
572  if (assigned_pds > 0) {
573  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD,
575  assigned_pds));
576  assigned_pds = 0;
577  }
578  }
579 
580  // Update current subnet id
581  cur_id = (*lease)->subnet_id_;
582  }
583 
584  // Bump the appropriate accumulator
585  if ((*lease)->state_ == Lease::STATE_DEFAULT) {
586  switch((*lease)->type_) {
587  case Lease::TYPE_NA:
588  ++assigned;
589  break;
590  case Lease::TYPE_PD:
591  ++assigned_pds;
592  break;
593  default:
594  break;
595  }
596  } else if ((*lease)->state_ == Lease::STATE_DECLINED) {
597  // In theory only NAs can be declined
598  if (((*lease)->type_) == Lease::TYPE_NA) {
599  ++declined;
600  }
601  }
602  }
603 
604  // Make the rows for last subnet, unless there were no rows
605  if (assigned > 0) {
606  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
607  Lease::STATE_DEFAULT, assigned));
608  }
609 
610  if (declined > 0) {
611  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_NA,
612  Lease::STATE_DECLINED, declined));
613  }
614 
615  if (assigned_pds > 0) {
616  rows_.push_back(LeaseStatsRow(cur_id, Lease::TYPE_PD,
617  Lease::STATE_DEFAULT, assigned_pds));
618  }
619 
620  // Set the next row position to the beginning of the rows.
621  next_pos_ = rows_.begin();
622  }
623 
624 private:
626  Lease6Storage& storage6_;
627 };
628 
629 // Explicit definition of class static constants. Values are given in the
630 // declaration so they're not needed here.
633 
635  : LeaseMgr(), lfc_setup_(), conn_(parameters)
636  {
637  bool conversion_needed = false;
638 
639  // Check the universe and use v4 file or v6 file.
640  std::string universe = conn_.getParameter("universe");
641  if (universe == "4") {
642  std::string file4 = initLeaseFilePath(V4);
643  if (!file4.empty()) {
644  conversion_needed = loadLeasesFromFiles<Lease4,
645  CSVLeaseFile4>(file4,
646  lease_file4_,
647  storage4_);
648  }
649  } else {
650  std::string file6 = initLeaseFilePath(V6);
651  if (!file6.empty()) {
652  conversion_needed = loadLeasesFromFiles<Lease6,
653  CSVLeaseFile6>(file6,
654  lease_file6_,
655  storage6_);
656  }
657  }
658 
659  // If lease persistence have been disabled for both v4 and v6,
660  // issue a warning. It is ok not to write leases to disk when
661  // doing testing, but it should not be done in normal server
662  // operation.
663  if (!persistLeases(V4) && !persistLeases(V6)) {
664  LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
665  } else {
666  if (conversion_needed) {
667  LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_CONVERTING_LEASE_FILES)
668  .arg(MAJOR_VERSION).arg(MINOR_VERSION);
669  }
670  lfcSetup(conversion_needed);
671  }
672 
673 }
674 
676  if (lease_file4_) {
677  lease_file4_->close();
678  lease_file4_.reset();
679  }
680  if (lease_file6_) {
681  lease_file6_->close();
682  lease_file6_.reset();
683  }
684 }
685 
686 std::string
688  std::stringstream tmp;
689  tmp << "Memfile backend " << MAJOR_VERSION;
690  tmp << "." << MINOR_VERSION;
691  return (tmp.str());
692 }
693 
694 bool
697  DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
698 
699  if (getLease4(lease->addr_)) {
700  // there is a lease with specified address already
701  return (false);
702  }
703 
704  // Try to write a lease to disk first. If this fails, the lease will
705  // not be inserted to the memory and the disk and in-memory data will
706  // remain consistent.
707  if (persistLeases(V4)) {
708  lease_file4_->append(*lease);
709  }
710 
711  storage4_.insert(lease);
712  return (true);
713 }
714 
715 bool
718  DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
719 
720  if (getLease6(lease->type_, lease->addr_)) {
721  // there is a lease with specified address already
722  return (false);
723  }
724 
725  // Try to write a lease to disk first. If this fails, the lease will
726  // not be inserted to the memory and the disk and in-memory data will
727  // remain consistent.
728  if (persistLeases(V6)) {
729  lease_file6_->append(*lease);
730  }
731 
732  storage6_.insert(lease);
733  return (true);
734 }
735 
736 Lease4Ptr
739  DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
740 
741  const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
742  Lease4StorageAddressIndex::iterator l = idx.find(addr);
743  if (l == idx.end()) {
744  return (Lease4Ptr());
745  } else {
746  return (Lease4Ptr(new Lease4(**l)));
747  }
748 }
749 
751 Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
753  DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
754  Lease4Collection collection;
755 
756  // Using composite index by 'hw address' and 'subnet id'. It is
757  // ok to use it for searching by the 'hw address' only.
759  storage4_.get<HWAddressSubnetIdIndexTag>();
760  std::pair<Lease4StorageHWAddressSubnetIdIndex::const_iterator,
761  Lease4StorageHWAddressSubnetIdIndex::const_iterator> l
762  = idx.equal_range(boost::make_tuple(hwaddr.hwaddr_));
763 
764  for(auto lease = l.first; lease != l.second; ++lease) {
765  collection.push_back(Lease4Ptr(new Lease4(**lease)));
766  }
767 
768  return (collection);
769 }
770 
771 Lease4Ptr
772 Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
774  DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
775  .arg(hwaddr.toText());
776 
777  // Get the index by HW Address and Subnet Identifier.
779  storage4_.get<HWAddressSubnetIdIndexTag>();
780  // Try to find the lease using HWAddr and subnet id.
781  Lease4StorageHWAddressSubnetIdIndex::const_iterator lease =
782  idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
783  // Lease was not found. Return empty pointer to the caller.
784  if (lease == idx.end()) {
785  return (Lease4Ptr());
786  }
787 
788  // Lease was found. Return it to the caller.
789  return (Lease4Ptr(new Lease4(**lease)));
790 }
791 
793 Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
795  DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
796  Lease4Collection collection;
797  // Using composite index by 'client id' and 'subnet id'. It is ok
798  // to use it to search by 'client id' only.
800  storage4_.get<ClientIdSubnetIdIndexTag>();
801  std::pair<Lease4StorageClientIdSubnetIdIndex::const_iterator,
802  Lease4StorageClientIdSubnetIdIndex::const_iterator> l
803  = idx.equal_range(boost::make_tuple(client_id.getClientId()));
804 
805  for(auto lease = l.first; lease != l.second; ++lease) {
806  collection.push_back(Lease4Ptr(new Lease4(**lease)));
807  }
808 
809  return (collection);
810 }
811 
812 Lease4Ptr
814  const HWAddr& hwaddr,
815  SubnetID subnet_id) const {
817  DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
818  .arg(hwaddr.toText())
819  .arg(subnet_id);
820 
821  // Get the index by client id, HW address and subnet id.
823  storage4_.get<ClientIdHWAddressSubnetIdIndexTag>();
824  // Try to get the lease using client id, hardware address and subnet id.
825  Lease4StorageClientIdHWAddressSubnetIdIndex::const_iterator lease =
826  idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
827  subnet_id));
828 
829  if (lease == idx.end()) {
830  // Lease was not found. Return empty pointer to the caller.
831  return (Lease4Ptr());
832  }
833 
834  // Lease was found. Return it to the caller.
835  return (*lease);
836 }
837 
838 Lease4Ptr
840  SubnetID subnet_id) const {
842  DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
843  .arg(client_id.toText());
844 
845  // Get the index by client and subnet id.
847  storage4_.get<ClientIdSubnetIdIndexTag>();
848  // Try to get the lease using client id and subnet id.
849  Lease4StorageClientIdSubnetIdIndex::const_iterator lease =
850  idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
851  // Lease was not found. Return empty pointer to the caller.
852  if (lease == idx.end()) {
853  return (Lease4Ptr());
854  }
855  // Lease was found. Return it to the caller.
856  return (Lease4Ptr(new Lease4(**lease)));
857 }
858 
861  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID4)
862  .arg(subnet_id);
863 
864  Lease4Collection collection;
865  const Lease4StorageSubnetIdIndex& idx = storage4_.get<SubnetIdIndexTag>();
866  std::pair<Lease4StorageSubnetIdIndex::const_iterator,
867  Lease4StorageSubnetIdIndex::const_iterator> l =
868  idx.equal_range(subnet_id);
869 
870  for (auto lease = l.first; lease != l.second; ++lease) {
871  collection.push_back(Lease4Ptr(new Lease4(**lease)));
872  }
873 
874  return (collection);
875 }
876 
879  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET4);
880 
881  Lease4Collection collection;
882  for (auto lease = storage4_.begin(); lease != storage4_.end(); ++lease ) {
883  collection.push_back(Lease4Ptr(new Lease4(**lease)));
884  }
885 
886  return (collection);
887 }
888 
891  const LeasePageSize& page_size) const {
892  // Expecting IPv4 address.
893  if (!lower_bound_address.isV4()) {
894  isc_throw(InvalidAddressFamily, "expected IPv4 address while "
895  "retrieving leases from the lease database, got "
896  << lower_bound_address);
897  }
898 
899  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE4)
900  .arg(page_size.page_size_)
901  .arg(lower_bound_address.toText());
902 
903  Lease4Collection collection;
904  const Lease4StorageAddressIndex& idx = storage4_.get<AddressIndexTag>();
905  Lease4StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
906 
907  // Exclude the lower bound address specified by the caller.
908  if ((lb != idx.end()) && ((*lb)->addr_ == lower_bound_address)) {
909  ++lb;
910  }
911 
912  // Return all other leases being within the page size.
913  for (auto lease = lb;
914  (lease != idx.end()) && (std::distance(lb, lease) < page_size.page_size_);
915  ++lease) {
916  collection.push_back(Lease4Ptr(new Lease4(**lease)));
917  }
918 
919  return (collection);
920 }
921 
922 Lease6Ptr
924  const isc::asiolink::IOAddress& addr) const {
926  DHCPSRV_MEMFILE_GET_ADDR6)
927  .arg(addr.toText())
928  .arg(Lease::typeToText(type));
929  Lease6Storage::iterator l = storage6_.find(addr);
930  if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
931  return (Lease6Ptr());
932  } else {
933  return (Lease6Ptr(new Lease6(**l)));
934  }
935 }
936 
939  const DUID& duid, uint32_t iaid) const {
941  DHCPSRV_MEMFILE_GET_IAID_DUID)
942  .arg(iaid)
943  .arg(duid.toText())
944  .arg(Lease::typeToText(type));
945 
946  // Get the index by DUID, IAID, lease type.
947  const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
948  // Try to get the lease using the DUID, IAID and lease type.
949  std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
950  Lease6StorageDuidIaidTypeIndex::const_iterator> l =
951  idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
952  Lease6Collection collection;
953  for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
954  l.first; lease != l.second; ++lease) {
955  collection.push_back(Lease6Ptr(new Lease6(**lease)));
956  }
957 
958  return (collection);
959 }
960 
963  const DUID& duid, uint32_t iaid,
964  SubnetID subnet_id) const {
966  DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
967  .arg(iaid)
968  .arg(subnet_id)
969  .arg(duid.toText())
970  .arg(Lease::typeToText(type));
971 
972  // Get the index by DUID, IAID, lease type.
973  const Lease6StorageDuidIaidTypeIndex& idx = storage6_.get<DuidIaidTypeIndexTag>();
974  // Try to get the lease using the DUID, IAID and lease type.
975  std::pair<Lease6StorageDuidIaidTypeIndex::const_iterator,
976  Lease6StorageDuidIaidTypeIndex::const_iterator> l =
977  idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
978  Lease6Collection collection;
979  for(Lease6StorageDuidIaidTypeIndex::const_iterator lease =
980  l.first; lease != l.second; ++lease) {
981  // Filter out the leases which subnet id doesn't match.
982  if((*lease)->subnet_id_ == subnet_id) {
983  collection.push_back(Lease6Ptr(new Lease6(**lease)));
984  }
985  }
986 
987  return (collection);
988 }
989 
992  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_SUBID6)
993  .arg(subnet_id);
994 
995  Lease6Collection collection;
996  const Lease6StorageSubnetIdIndex& idx = storage6_.get<SubnetIdIndexTag>();
997  std::pair<Lease6StorageSubnetIdIndex::const_iterator,
998  Lease6StorageSubnetIdIndex::const_iterator> l =
999  idx.equal_range(subnet_id);
1000 
1001  for (auto lease = l.first; lease != l.second; ++lease) {
1002  collection.push_back(Lease6Ptr(new Lease6(**lease)));
1003  }
1004 
1005  return (collection);
1006 }
1007 
1010  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6);
1011 
1012  Lease6Collection collection;
1013  for (auto lease = storage6_.begin(); lease != storage6_.end(); ++lease ) {
1014  collection.push_back(Lease6Ptr(new Lease6(**lease)));
1015  }
1016 
1017  return (collection);
1018 }
1019 
1022  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6_DUID)
1023  .arg(duid.toText());
1024 
1025  Lease6Collection collection;
1026  const Lease6StorageDuidIndex& idx = storage6_.get<DuidIndexTag>();
1027  std::pair<Lease6StorageDuidIndex::const_iterator,
1028  Lease6StorageDuidIndex::const_iterator> l =
1029  idx.equal_range(duid.getDuid());
1030 
1031  for (auto lease = l.first; lease != l.second; ++lease) {
1032  collection.push_back(Lease6Ptr(new Lease6(**lease)));
1033  }
1034 
1035  return (collection);
1036 }
1037 
1040  const LeasePageSize& page_size) const {
1041  // Expecting IPv6 address.
1042  if (!lower_bound_address.isV6()) {
1043  isc_throw(InvalidAddressFamily, "expected IPv6 address while "
1044  "retrieving leases from the lease database, got "
1045  << lower_bound_address);
1046  }
1047 
1048  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_PAGE6)
1049  .arg(page_size.page_size_)
1050  .arg(lower_bound_address.toText());
1051 
1052  Lease6Collection collection;
1053  const Lease6StorageAddressIndex& idx = storage6_.get<AddressIndexTag>();
1054  Lease6StorageAddressIndex::const_iterator lb = idx.lower_bound(lower_bound_address);
1055 
1056  // Exclude the lower bound address specified by the caller.
1057  if ((lb != idx.end()) && ((*lb)->addr_ == lower_bound_address)) {
1058  ++lb;
1059  }
1060 
1061  // Return all other leases being within the page size.
1062  for (auto lease = lb;
1063  (lease != idx.end()) && (std::distance(lb, lease) < page_size.page_size_);
1064  ++lease) {
1065  collection.push_back(Lease6Ptr(new Lease6(**lease)));
1066  }
1067 
1068  return (collection);
1069 }
1070 
1071 void
1073  const size_t max_leases) const {
1074  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED4)
1075  .arg(max_leases);
1076 
1077  // Obtain the index which segragates leases by state and time.
1078  const Lease4StorageExpirationIndex& index = storage4_.get<ExpirationIndexTag>();
1079 
1080  // Retrieve leases which are not reclaimed and which haven't expired. The
1081  // 'less-than' operator will be used for both components of the index. So,
1082  // for the 'state' 'false' is less than 'true'. Also the leases with
1083  // expiration time lower than current time will be returned.
1084  Lease4StorageExpirationIndex::const_iterator ub =
1085  index.upper_bound(boost::make_tuple(false, time(NULL)));
1086 
1087  // Copy only the number of leases indicated by the max_leases parameter.
1088  for (Lease4StorageExpirationIndex::const_iterator lease = index.begin();
1089  (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
1090  max_leases));
1091  ++lease) {
1092  expired_leases.push_back(Lease4Ptr(new Lease4(**lease)));
1093  }
1094 }
1095 
1096 void
1098  const size_t max_leases) const {
1099  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET_EXPIRED6)
1100  .arg(max_leases);
1101 
1102  // Obtain the index which segragates leases by state and time.
1103  const Lease6StorageExpirationIndex& index = storage6_.get<ExpirationIndexTag>();
1104 
1105  // Retrieve leases which are not reclaimed and which haven't expired. The
1106  // 'less-than' operator will be used for both components of the index. So,
1107  // for the 'state' 'false' is less than 'true'. Also the leases with
1108  // expiration time lower than current time will be returned.
1109  Lease6StorageExpirationIndex::const_iterator ub =
1110  index.upper_bound(boost::make_tuple(false, time(NULL)));
1111 
1112  // Copy only the number of leases indicated by the max_leases parameter.
1113  for (Lease6StorageExpirationIndex::const_iterator lease = index.begin();
1114  (lease != ub) && ((max_leases == 0) || (std::distance(index.begin(), lease) <
1115  max_leases));
1116  ++lease) {
1117  expired_leases.push_back(Lease6Ptr(new Lease6(**lease)));
1118  }
1119 }
1120 
1121 void
1124  DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
1125 
1126  // Obtain 'by address' index.
1127  Lease4StorageAddressIndex& index = storage4_.get<AddressIndexTag>();
1128 
1129  // Lease must exist if it is to be updated.
1130  Lease4StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
1131  if (lease_it == index.end()) {
1132  isc_throw(NoSuchLease, "failed to update the lease with address "
1133  << lease->addr_ << " - no such lease");
1134  }
1135 
1136  // Try to write a lease to disk first. If this fails, the lease will
1137  // not be inserted to the memory and the disk and in-memory data will
1138  // remain consistent.
1139  if (persistLeases(V4)) {
1140  lease_file4_->append(*lease);
1141  }
1142 
1143  // Use replace() to re-index leases.
1144  index.replace(lease_it, Lease4Ptr(new Lease4(*lease)));
1145 }
1146 
1147 void
1150  DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
1151 
1152  // Obtain 'by address' index.
1153  Lease6StorageAddressIndex& index = storage6_.get<AddressIndexTag>();
1154 
1155  // Lease must exist if it is to be updated.
1156  Lease6StorageAddressIndex::const_iterator lease_it = index.find(lease->addr_);
1157  if (lease_it == index.end()) {
1158  isc_throw(NoSuchLease, "failed to update the lease with address "
1159  << lease->addr_ << " - no such lease");
1160  }
1161 
1162  // Try to write a lease to disk first. If this fails, the lease will
1163  // not be inserted to the memory and the disk and in-memory data will
1164  // remain consistent.
1165  if (persistLeases(V6)) {
1166  lease_file6_->append(*lease);
1167  }
1168 
1169  // Use replace() to re-index leases.
1170  index.replace(lease_it, Lease6Ptr(new Lease6(*lease)));
1171 }
1172 
1173 bool
1176  DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
1177  if (addr.isV4()) {
1178  // v4 lease
1179  Lease4Storage::iterator l = storage4_.find(addr);
1180  if (l == storage4_.end()) {
1181  // No such lease
1182  return (false);
1183  } else {
1184  if (persistLeases(V4)) {
1185  // Copy the lease. The valid lifetime needs to be modified and
1186  // we don't modify the original lease.
1187  Lease4 lease_copy = **l;
1188  // Setting valid lifetime to 0 means that lease is being
1189  // removed.
1190  lease_copy.valid_lft_ = 0;
1191  lease_file4_->append(lease_copy);
1192  }
1193  storage4_.erase(l);
1194  return (true);
1195  }
1196 
1197  } else {
1198  // v6 lease
1199  Lease6Storage::iterator l = storage6_.find(addr);
1200  if (l == storage6_.end()) {
1201  // No such lease
1202  return (false);
1203  } else {
1204  if (persistLeases(V6)) {
1205  // Copy the lease. The lifetimes need to be modified and we
1206  // don't modify the original lease.
1207  Lease6 lease_copy = **l;
1208  // Setting lifetimes to 0 means that lease is being removed.
1209  lease_copy.valid_lft_ = 0;
1210  lease_copy.preferred_lft_ = 0;
1211  lease_file6_->append(lease_copy);
1212  }
1213 
1214  storage6_.erase(l);
1215  return (true);
1216  }
1217  }
1218 }
1219 
1220 uint64_t
1223  DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED4)
1224  .arg(secs);
1225  return (deleteExpiredReclaimedLeases<
1227  >(secs, V4, storage4_, lease_file4_));
1228 }
1229 
1230 uint64_t
1233  DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6)
1234  .arg(secs);
1235  return (deleteExpiredReclaimedLeases<
1237  >(secs, V6, storage6_, lease_file6_));
1238 }
1239 
1240 template<typename IndexType, typename LeaseType, typename StorageType,
1241  typename LeaseFileType>
1242 uint64_t
1243 Memfile_LeaseMgr::deleteExpiredReclaimedLeases(const uint32_t secs,
1244  const Universe& universe,
1245  StorageType& storage,
1246  LeaseFileType& lease_file) const {
1247  // Obtain the index which segragates leases by state and time.
1248  IndexType& index = storage.template get<ExpirationIndexTag>();
1249 
1250  // This returns the first element which is greater than the specified
1251  // tuple (true, time(NULL) - secs). However, the range between the
1252  // beginning of the index and returned element also includes all the
1253  // elements for which the first value is false (lease state is NOT
1254  // reclaimed), because false < true. All elements between the
1255  // beginning of the index and the element returned, for which the
1256  // first value is true, represent the reclaimed leases which should
1257  // be deleted, because their expiration time + secs has occurred earlier
1258  // than current time.
1259  typename IndexType::const_iterator upper_limit =
1260  index.upper_bound(boost::make_tuple(true, time(NULL) - secs));
1261 
1262  // Now, we have to exclude all elements of the index which represent
1263  // leases in the state other than reclaimed - with the first value
1264  // in the index equal to false. Note that elements in the index are
1265  // ordered from the lower to the higher ones. So, all elements with
1266  // the first value of false are placed before the elements with the
1267  // value of true. Hence, we have to find the first element which
1268  // contains value of true. The time value is the lowest possible.
1269  typename IndexType::const_iterator lower_limit =
1270  index.upper_bound(boost::make_tuple(true, std::numeric_limits<int64_t>::min()));
1271 
1272  // If there are some elements in this range, delete them.
1273  uint64_t num_leases = static_cast<uint64_t>(std::distance(lower_limit, upper_limit));
1274  if (num_leases > 0) {
1275 
1277  DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED_START)
1278  .arg(num_leases);
1279 
1280  // If lease persistence is enabled, we also have to mark leases
1281  // as deleted in the lease file. We do this by setting the
1282  // lifetime to 0.
1283  if (persistLeases(universe)) {
1284  for (typename IndexType::const_iterator lease = lower_limit;
1285  lease != upper_limit; ++lease) {
1286  // Copy lease to not affect the lease in the container.
1287  LeaseType lease_copy(**lease);
1288  // Set the valid lifetime to 0 to indicate the removal
1289  // of the lease.
1290  lease_copy.valid_lft_ = 0;
1291  lease_file->append(lease_copy);
1292  }
1293  }
1294 
1295  // Erase leases from memory.
1296  index.erase(lower_limit, upper_limit);
1297  }
1298  // Return number of leases deleted.
1299  return (num_leases);
1300 }
1301 
1302 
1303 std::string
1305  return (std::string("In memory database with leases stored in a CSV file."));
1306 }
1307 
1308 void
1310  LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
1311 }
1312 
1313 void
1316  DHCPSRV_MEMFILE_ROLLBACK);
1317 }
1318 
1319 std::string
1320 Memfile_LeaseMgr::appendSuffix(const std::string& file_name,
1321  const LFCFileType& file_type) {
1322  std::string name(file_name);
1323  switch (file_type) {
1324  case FILE_INPUT:
1325  name += ".1";
1326  break;
1327  case FILE_PREVIOUS:
1328  name += ".2";
1329  break;
1330  case FILE_OUTPUT:
1331  name += ".output";
1332  break;
1333  case FILE_FINISH:
1334  name += ".completed";
1335  break;
1336  case FILE_PID:
1337  name += ".pid";
1338  break;
1339  default:
1340  // Do not append any suffix for the FILE_CURRENT.
1341  ;
1342  }
1343 
1344  return (name);
1345 }
1346 
1347 std::string
1349  std::ostringstream s;
1350  s << CfgMgr::instance().getDataDir() << "/kea-leases";
1351  s << (u == V4 ? "4" : "6");
1352  s << ".csv";
1353  return (s.str());
1354 }
1355 
1356 std::string
1358  if (u == V4) {
1359  return (lease_file4_ ? lease_file4_->getFilename() : "");
1360  }
1361 
1362  return (lease_file6_ ? lease_file6_->getFilename() : "");
1363 }
1364 
1365 bool
1367  // Currently, if the lease file IO is not created, it means that writes to
1368  // disk have been explicitly disabled by the administrator. At some point,
1369  // there may be a dedicated ON/OFF flag implemented to control this.
1370  if (u == V4 && lease_file4_) {
1371  return (true);
1372  }
1373 
1374  return (u == V6 && lease_file6_);
1375 }
1376 
1377 std::string
1378 Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
1379  std::string persist_val;
1380  try {
1381  persist_val = conn_.getParameter("persist");
1382  } catch (const Exception&) {
1383  // If parameter persist hasn't been specified, we use a default value
1384  // 'yes'.
1385  persist_val = "true";
1386  }
1387  // If persist_val is 'false' we will not store leases to disk, so let's
1388  // return empty file name.
1389  if (persist_val == "false") {
1390  return ("");
1391 
1392  } else if (persist_val != "true") {
1393  isc_throw(isc::BadValue, "invalid value 'persist="
1394  << persist_val << "'");
1395  }
1396 
1397  std::string lease_file;
1398  try {
1399  lease_file = conn_.getParameter("name");
1400  } catch (const Exception&) {
1401  lease_file = getDefaultLeaseFilePath(u);
1402  }
1403  return (lease_file);
1404 }
1405 
1406 template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
1407 bool Memfile_LeaseMgr::loadLeasesFromFiles(const std::string& filename,
1408  boost::shared_ptr<LeaseFileType>& lease_file,
1409  StorageType& storage) {
1410  // Check if the instance of the LFC is running right now. If it is
1411  // running, we refuse to load leases as the LFC may be writing to the
1412  // lease files right now. When the user retries server configuration
1413  // it should go through.
1416  PIDFile pid_file(appendSuffix(filename, FILE_PID));
1417  if (pid_file.check()) {
1418  isc_throw(DbOpenError, "unable to load leases from files while the "
1419  "lease file cleanup is in progress");
1420  }
1421 
1422  storage.clear();
1423 
1424  // Load the leasefile.completed, if exists.
1425  bool conversion_needed = false;
1426  lease_file.reset(new LeaseFileType(std::string(filename + ".completed")));
1427  if (lease_file->exists()) {
1428  LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
1429  MAX_LEASE_ERRORS);
1430  conversion_needed = conversion_needed || lease_file->needsConversion();
1431  } else {
1432  // If the leasefile.completed doesn't exist, let's load the leases
1433  // from leasefile.2 and leasefile.1, if they exist.
1434  lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_PREVIOUS)));
1435  if (lease_file->exists()) {
1436  LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
1437  MAX_LEASE_ERRORS);
1438  conversion_needed = conversion_needed || lease_file->needsConversion();
1439  }
1440 
1441  lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_INPUT)));
1442  if (lease_file->exists()) {
1443  LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
1444  MAX_LEASE_ERRORS);
1445  conversion_needed = conversion_needed || lease_file->needsConversion();
1446  }
1447  }
1448 
1449  // Always load leases from the primary lease file. If the lease file
1450  // doesn't exist it will be created by the LeaseFileLoader. Note
1451  // that the false value passed as the last parameter to load
1452  // function causes the function to leave the file open after
1453  // it is parsed. This file will be used by the backend to record
1454  // future lease updates.
1455  lease_file.reset(new LeaseFileType(filename));
1456  LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
1457  MAX_LEASE_ERRORS, false);
1458  conversion_needed = conversion_needed || lease_file->needsConversion();
1459 
1460  return (conversion_needed);
1461 }
1462 
1463 
1464 bool
1466  return (lfc_setup_->isRunning());
1467 }
1468 
1469 int
1471  return (lfc_setup_->getExitStatus());
1472 }
1473 
1474 void
1476  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_START);
1477 
1478  // Check if we're in the v4 or v6 space and use the appropriate file.
1479  if (lease_file4_) {
1480  lfcExecute(lease_file4_);
1481 
1482  } else if (lease_file6_) {
1483  lfcExecute(lease_file6_);
1484  }
1485 }
1486 
1487 void
1488 Memfile_LeaseMgr::lfcSetup(bool conversion_needed) {
1489  std::string lfc_interval_str = "3600";
1490  try {
1491  lfc_interval_str = conn_.getParameter("lfc-interval");
1492  } catch (const std::exception&) {
1493  // Ignore and default to 3600.
1494  }
1495 
1496  uint32_t lfc_interval = 0;
1497  try {
1498  lfc_interval = boost::lexical_cast<uint32_t>(lfc_interval_str);
1499  } catch (boost::bad_lexical_cast&) {
1500  isc_throw(isc::BadValue, "invalid value of the lfc-interval "
1501  << lfc_interval_str << " specified");
1502  }
1503 
1504  if (lfc_interval > 0 || conversion_needed) {
1505  lfc_setup_.reset(new LFCSetup(boost::bind(&Memfile_LeaseMgr::lfcCallback, this)));
1506  lfc_setup_->setup(lfc_interval, lease_file4_, lease_file6_, conversion_needed);
1507  }
1508 }
1509 
1510 template<typename LeaseFileType>
1511 void Memfile_LeaseMgr::lfcExecute(boost::shared_ptr<LeaseFileType>& lease_file) {
1512  bool do_lfc = true;
1513 
1514  // Check the status of the LFC instance.
1515  // If the finish file exists or the copy of the lease file exists it
1516  // is an indication that another LFC instance may be in progress or
1517  // may be stalled. In that case we don't want to rotate the current
1518  // lease file to avoid overriding the contents of the existing file.
1519  CSVFile lease_file_finish(appendSuffix(lease_file->getFilename(), FILE_FINISH));
1520  CSVFile lease_file_copy(appendSuffix(lease_file->getFilename(), FILE_INPUT));
1521  if (!lease_file_finish.exists() && !lease_file_copy.exists()) {
1522  // Close the current file so as we can move it to the copy file.
1523  lease_file->close();
1524  // Move the current file to the copy file. Remember the result
1525  // because we don't want to run LFC if the rename failed.
1526  do_lfc = (rename(lease_file->getFilename().c_str(),
1527  lease_file_copy.getFilename().c_str()) == 0);
1528 
1529  if (!do_lfc) {
1530  LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_LEASE_FILE_RENAME_FAIL)
1531  .arg(lease_file->getFilename())
1532  .arg(lease_file_copy.getFilename())
1533  .arg(strerror(errno));
1534  }
1535 
1536  // Regardless if we successfully moved the current file or not,
1537  // we need to re-open the current file for the server to write
1538  // new lease updates. If the file has been successfully moved,
1539  // this will result in creation of the new file. Otherwise,
1540  // an existing file will be opened.
1541  try {
1542  lease_file->open(true);
1543 
1544  } catch (const CSVFileError& ex) {
1545  // If we're unable to open the lease file this is a serious
1546  // error because the server will not be able to persist
1547  // leases.
1554  LOG_ERROR(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_LEASE_FILE_REOPEN_FAIL)
1555  .arg(lease_file->getFilename())
1556  .arg(ex.what());
1557  // Reset the pointer to the file so as the backend doesn't
1558  // try to write leases to disk.
1559  lease_file.reset();
1560  do_lfc = false;
1561  }
1562  }
1563  // Once the files have been rotated, or untouched if another LFC had
1564  // not finished, a new process is started.
1565  if (do_lfc) {
1566  lfc_setup_->execute();
1567  }
1568 }
1569 
1572  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_));
1573  query->start();
1574  return(query);
1575 }
1576 
1579  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, subnet_id));
1580  query->start();
1581  return(query);
1582 }
1583 
1586  const SubnetID& last_subnet_id) {
1587  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery4(storage4_, first_subnet_id,
1588  last_subnet_id));
1589  query->start();
1590  return(query);
1591 }
1592 
1595  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_));
1596  query->start();
1597  return(query);
1598 }
1599 
1602  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_, subnet_id));
1603  query->start();
1604  return(query);
1605 }
1606 
1609  const SubnetID& last_subnet_id) {
1610  LeaseStatsQueryPtr query(new MemfileLeaseStatsQuery6(storage6_, first_subnet_id,
1611  last_subnet_id));
1612  query->start();
1613  return(query);
1614 }
1615 
1616 size_t Memfile_LeaseMgr::wipeLeases4(const SubnetID& subnet_id) {
1617  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_WIPE_LEASES4)
1618  .arg(subnet_id);
1619 
1620  // Get the index by DUID, IAID, lease type.
1621  const Lease4StorageSubnetIdIndex& idx = storage4_.get<SubnetIdIndexTag>();
1622 
1623  // Try to get the lease using the DUID, IAID and lease type.
1624  std::pair<Lease4StorageSubnetIdIndex::const_iterator,
1625  Lease4StorageSubnetIdIndex::const_iterator> l =
1626  idx.equal_range(subnet_id);
1627 
1628  // Let's collect all leases.
1629  Lease4Collection leases;
1630  for(auto lease = l.first; lease != l.second; ++lease) {
1631  leases.push_back(*lease);
1632  }
1633 
1634  size_t num = leases.size();
1635  for (auto l = leases.begin(); l != leases.end(); ++l) {
1636  deleteLease((*l)->addr_);
1637  }
1638  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_WIPE_LEASES4_FINISHED)
1639  .arg(subnet_id).arg(num);
1640 
1641  return (num);
1642 }
1643 
1644 size_t Memfile_LeaseMgr::wipeLeases6(const SubnetID& subnet_id) {
1645  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_WIPE_LEASES6)
1646  .arg(subnet_id);
1647 
1648  // Get the index by DUID, IAID, lease type.
1649  const Lease6StorageSubnetIdIndex& idx = storage6_.get<SubnetIdIndexTag>();
1650 
1651  // Try to get the lease using the DUID, IAID and lease type.
1652  std::pair<Lease6StorageSubnetIdIndex::const_iterator,
1653  Lease6StorageSubnetIdIndex::const_iterator> l =
1654  idx.equal_range(subnet_id);
1655 
1656  // Let's collect all leases.
1657  Lease6Collection leases;
1658  for(auto lease = l.first; lease != l.second; ++lease) {
1659  leases.push_back(*lease);
1660  }
1661 
1662  size_t num = leases.size();
1663  for (auto l = leases.begin(); l != leases.end(); ++l) {
1664  deleteLease((*l)->addr_);
1665  }
1666  LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_WIPE_LEASES6_FINISHED)
1667  .arg(subnet_id).arg(num);
1668 
1669  return (num);
1670 }
1671 
1672 
1673 } // end of namespace isc::dhcp
1674 } // end of namespace isc
virtual bool deleteLease(const isc::asiolink::IOAddress &addr)
Deletes a lease.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
Represents a configuration for Lease File Cleanup.
virtual void rollback()
Rollback Transactions.
Tag for indexes by DUID, IAID, lease type tuple.
virtual ~MemfileLeaseStatsQuery4()
Destructor.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
boost::shared_ptr< TimerMgr > TimerMgrPtr
Type definition of the shared pointer to TimerMgr.
Definition: timer_mgr.h:22
virtual ~Memfile_LeaseMgr()
Destructor (closes file)
MemfileLeaseStatsQuery(const SubnetID &subnet_id)
Constructor for single subnet query.
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:116
Structure that holds a lease for IPv4 address.
Definition: lease.h:256
virtual std::string getDescription() const
Returns description of the backend.
Abstract Lease Manager.
Definition: lease_mgr.h:222
void setup(const uint32_t lfc_interval, const boost::shared_ptr< CSVLeaseFile4 > &lease_file4, const boost::shared_ptr< CSVLeaseFile6 > &lease_file6, bool run_once_now=false)
Sets the new configuration for the Lease File Cleanup.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
int getExitStatus() const
Returns exit code of the last completed cleanup.
std::vector< LeaseStatsRow >::iterator next_pos_
An iterator for accessing the next row within the result set.
static std::string typeToText(Type type)
returns text representation of a lease type
Definition: lease.cc:39
Lease4Storage::index< ClientIdHWAddressSubnetIdIndexTag >::type Lease4StorageClientIdHWAddressSubnetIdIndex
DHCPv4 lease storage index by client id, HW address and subnet id.
Memfile derivation of the IPv6 statistical lease data query.
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
MemfileLeaseStatsQuery(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for subnet range query.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
uint32_t preferred_lft_
preferred lifetime
Definition: lease.h:497
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:54
Attempt to update lease that was not there.
std::vector< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:455
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery6(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
Lease6Storage::index< DuidIaidTypeIndexTag >::type Lease6StorageDuidIaidTypeIndex
DHCPv6 lease storage index by DUID, IAID, lease type.
Universe
Specifies universe (V4, V6)
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
Tag for indexes by expiration time.
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
bool isRunning() const
Checks if the lease file cleanup is in progress.
Lease4Storage::index< HWAddressSubnetIdIndexTag >::type Lease4StorageHWAddressSubnetIdIndex
DHCPv4 lease storage index by HW address and subnet identifier.
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:128
std::string getDataDir() const
returns path do the data directory
Definition: cfgmgr.cc:30
void start()
Creates the IPv4 lease statistical data result set.
Class to help with processing PID files.
Definition: pid_file.h:40
Memfile_LeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
The sole lease manager constructor.
Exception thrown when error occurs during spawning a process.
Definition: process_spawn.h:20
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
static std::string getDBVersion()
Local version of getDBVersion() class method.
LFCFileType
Types of the lease files used by the Lease File Cleanup.
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
Exception thrown on failure to open database.
Provides methods to access CSV file with DHCPv4 leases.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
MemfileLeaseStatsQuery6(Lease6Storage &storage6, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for a subnet range query.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
Lease6Storage::index< AddressIndexTag >::type Lease6StorageAddressIndex
DHCPv6 lease storage index by address.
MemfileLeaseStatsQuery6(Lease6Storage &storage6, const SubnetID &subnet_id)
Constructor for a single subnet query.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual void lfcCallback()
A callback function triggering Lease File Cleanup (LFC).
Lease6Storage::index< DuidIndexTag >::type Lease6StorageDuidIndex
DHCPv6 lease storage index by Subnet-id.
Lease4Storage::index< AddressIndexTag >::type Lease4StorageAddressIndex
DHCPv4 lease storage index by address.
Definition: edns.h:19
virtual bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
Lease4Storage::index< SubnetIdIndexTag >::type Lease4StorageSubnetIdIndex
DHCPv4 lease storage index by client id, HW address and subnet id.
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:53
bool isLFCRunning() const
Checks if the process performing lease file cleanup is running.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:245
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
Lease4Storage::index< ExpirationIndexTag >::type Lease4StorageExpirationIndex
DHCPv4 lease storage index by expiration time.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
Tag for indexes by client id, HW address and subnet id.
virtual void commit()
Commit Transactions.
SelectMode getSelectMode() const
Returns the selection criteria mode The value returned is based upon the constructor variant used and...
Definition: lease_mgr.h:190
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:471
boost::multi_index_container< Lease4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< AddressIndexTag >, boost::multi_index::member< Lease, isc::asiolink::IOAddress, &Lease::addr_ > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< HWAddressSubnetIdIndexTag >, boost::multi_index::composite_key< Lease4, boost::multi_index::const_mem_fun< Lease, const std::vector< uint8_t > &, &Lease::getHWAddrVector >, boost::multi_index::member< Lease, SubnetID, &Lease::subnet_id_ > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ClientIdSubnetIdIndexTag >, boost::multi_index::composite_key< Lease4, boost::multi_index::const_mem_fun< Lease4, const std::vector< uint8_t > &, &Lease4::getClientIdVector >, boost::multi_index::member< Lease, uint32_t, &Lease::subnet_id_ > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ClientIdHWAddressSubnetIdIndexTag >, boost::multi_index::composite_key< Lease4, boost::multi_index::const_mem_fun< Lease4, const std::vector< uint8_t > &, &Lease4::getClientIdVector >, boost::multi_index::const_mem_fun< Lease, const std::vector< uint8_t > &, &Lease::getHWAddrVector >, boost::multi_index::member< Lease, SubnetID, &Lease::subnet_id_ > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ExpirationIndexTag >, boost::multi_index::composite_key< Lease4, boost::multi_index::const_mem_fun< Lease, bool, &Lease::stateExpiredReclaimed >, boost::multi_index::const_mem_fun< Lease, int64_t, &Lease::getExpirationTime > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetIdIndexTag >, boost::multi_index::member< Lease, isc::dhcp::SubnetID, &Lease::subnet_id_ > > >> Lease4Storage
A multi index container holding DHCPv4 leases.
std::vector< std::string > ProcessArgs
Type of the container holding arguments of the executable being run as a background process.
Definition: process_spawn.h:28
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
static const int MINOR_VERSION
Defines minor version of the memfile backend.
boost::multi_index_container< Lease6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< AddressIndexTag >, boost::multi_index::member< Lease, isc::asiolink::IOAddress, &Lease::addr_ > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< DuidIaidTypeIndexTag >, boost::multi_index::composite_key< Lease6, boost::multi_index::const_mem_fun< Lease6, const std::vector< uint8_t > &, &Lease6::getDuidVector >, boost::multi_index::member< Lease6, uint32_t, &Lease6::iaid_ >, boost::multi_index::member< Lease6, Lease::Type, &Lease6::type_ > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< ExpirationIndexTag >, boost::multi_index::composite_key< Lease6, boost::multi_index::const_mem_fun< Lease, bool, &Lease::stateExpiredReclaimed >, boost::multi_index::const_mem_fun< Lease, int64_t, &Lease::getExpirationTime > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetIdIndexTag >, boost::multi_index::member< Lease, isc::dhcp::SubnetID, &Lease::subnet_id_ > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< DuidIndexTag >, boost::multi_index::const_mem_fun< Lease6, const std::vector< uint8_t > &, &Lease6::getDuidVector > > >> Lease6Storage
A multi index container holding DHCPv6 leases.
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:604
Tag for index using DUID.
MemfileLeaseStatsQuery()
Constructor for all subnets query.
MemfileLeaseStatsQuery4(Lease4Storage &storage4, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for a subnet range query.
Tag for indexes by HW address, subnet identifier tuple.
SubnetID getLastSubnetID() const
Returns the value of last subnet ID specified (or zero)
Definition: lease_mgr.h:183
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:44
virtual LeaseStatsQueryPtr startSubnetRangeLeaseStatsQuery4(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
the lease contains non-temporary IPv6 address
Definition: lease.h:39
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
Memfile derivation of the IPv4 statistical lease data query.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:64
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
std::string getLeaseFilePath(Universe u) const
Returns an absolute path to the lease file.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
bool persistLeases(Universe u) const
Specifies whether or not leases are written to disk.
virtual void updateLease4(const Lease4Ptr &lease4)
Updates IPv4 lease.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
Tag for indexes by address.
SubnetID getFirstSubnetID() const
Returns the value of first subnet ID specified (or zero)
Definition: lease_mgr.h:178
std::string getDefaultLeaseFilePath(Universe u) const
Returns default path to the lease file.
virtual ~MemfileLeaseStatsQuery6()
Destructor.
Type
Type of lease or pool.
Definition: lease.h:38
Lease6Storage::index< ExpirationIndexTag >::type Lease6StorageExpirationIndex
DHCPv6 lease storage index by expiration time.
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
A generic exception that is thrown if a function is called in a prohibited way.
Provides input/output access to CSV files.
Definition: csv_file.h:290
MemfileLeaseStatsQuery6(Lease6Storage &storage6)
Constructor.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
Base Memfile derivation of the statistical lease data query.
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition: lease.h:61
Utility class for spawning new processes.
Definition: process_spawn.h:60
Tag for indexes by client and subnet identifiers.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
static const uint32_t STATE_DECLINED
Declined lease.
Definition: lease.h:64
Contains a single row of lease statistical data.
Definition: lease_mgr.h:61
std::vector< LeaseStatsRow > rows_
A vector containing the "result set".
void execute()
Spawns a new process.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:74
MemfileLeaseStatsQuery4(Lease4Storage &storage4, const SubnetID &subnet_id)
Constructor for a single subnet query.
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
uint32_t valid_lft_
Valid lifetime.
Definition: lease.h:125
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Tag for indexs by subnet-id.
virtual ~MemfileLeaseStatsQuery()
Destructor.
Lease4Storage::index< ClientIdSubnetIdIndexTag >::type Lease4StorageClientIdSubnetIdIndex
DHCPv4 lease storage index by client and subnet identifier.
virtual void start()
Creates the IPv6 lease statistical data result set.
int getLFCExitStatus() const
Returns the status code returned by the last executed LFC process.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:460
Provides methods to access CSV file with DHCPv6 leases.
static std::string appendSuffix(const std::string &file_name, const LFCFileType &file_type)
Appends appropriate suffix to the file name.
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
MemfileLeaseStatsQuery4(Lease4Storage &storage4)
Constructor for an all subnets query.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns existing IPv4 lease for specified IPv4 address.
int getRowCount() const
Returns the number of rows in the result set.
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:121
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
Lease6Storage::index< SubnetIdIndexTag >::type Lease6StorageSubnetIdIndex
DHCPv6 lease storage index by Subnet-id.
virtual bool addLease(const Lease4Ptr &lease)
Adds an IPv4 lease.
Exception thrown when an error occurs during CSV file processing.
Definition: csv_file.h:22