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>
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
26namespace {
27
29const uint32_t MAX_LEASE_ERRORS = 100;
30
38const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";
39
40} // end of anonymous namespace
41
42using namespace isc::asiolink;
43using namespace isc::db;
44using namespace isc::util;
45
46namespace isc {
47namespace dhcp {
48
63class LFCSetup {
64public:
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
107private:
108
111 boost::scoped_ptr<util::ProcessSpawn> process_;
112
115
117 pid_t pid_;
118
123 TimerMgrPtr timer_mgr_;
124};
125
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
154void
155LFCSetup::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.
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
230void
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
242bool
244 return (process_ && process_->isRunning(pid_));
245}
246
247int
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
263public:
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
313protected:
315 std::vector<LeaseStatsRow> rows_;
316
318 std::vector<LeaseStatsRow>::iterator next_pos_;
319};
320
331public:
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() {
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
457private:
459 Lease4Storage& storage4_;
460};
461
462
473public:
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
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
624private:
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
686std::string
688 std::stringstream tmp;
689 tmp << "Memfile backend " << MAJOR_VERSION;
690 tmp << "." << MINOR_VERSION;
691 return (tmp.str());
692}
693
694bool
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
715bool
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
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
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
772Memfile_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
793Memfile_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
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
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
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
1071void
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
1096void
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
1121void
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
1147void
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
1173bool
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
1220uint64_t
1223 DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED4)
1224 .arg(secs);
1225 return (deleteExpiredReclaimedLeases<
1227 >(secs, V4, storage4_, lease_file4_));
1228}
1229
1230uint64_t
1233 DHCPSRV_MEMFILE_DELETE_EXPIRED_RECLAIMED6)
1234 .arg(secs);
1235 return (deleteExpiredReclaimedLeases<
1237 >(secs, V6, storage6_, lease_file6_));
1238}
1239
1240template<typename IndexType, typename LeaseType, typename StorageType,
1241 typename LeaseFileType>
1242uint64_t
1243Memfile_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
1303std::string
1305 return (std::string("In memory database with leases stored in a CSV file."));
1306}
1307
1308void
1310 LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
1311}
1312
1313void
1316 DHCPSRV_MEMFILE_ROLLBACK);
1317}
1318
1319std::string
1320Memfile_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
1347std::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
1356std::string
1358 if (u == V4) {
1359 return (lease_file4_ ? lease_file4_->getFilename() : "");
1360 }
1361
1362 return (lease_file6_ ? lease_file6_->getFilename() : "");
1363}
1364
1365bool
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
1377std::string
1378Memfile_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
1406template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
1407bool 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
1464bool
1466 return (lfc_setup_->isRunning());
1467}
1468
1469int
1471 return (lfc_setup_->getExitStatus());
1472}
1473
1474void
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
1487void
1488Memfile_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
1510template<typename LeaseFileType>
1511void 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
1616size_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
1644size_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
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown on failure to open database.
Invalid address family used as input to Lease Manager.
Definition: db_exceptions.h:64
Provides methods to access CSV file with DHCPv4 leases.
Provides methods to access CSV file with DHCPv6 leases.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
std::string getDataDir() const
returns path do the data directory
Definition: cfgmgr.cc:30
Holds Client identifier or client IPv4 address.
Definition: duid.h:111
const std::vector< uint8_t > & getClientId() const
Returns reference to the client-id data.
Definition: duid.cc:116
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:121
Holds DUID (DHCPv6 Unique Identifier)
Definition: duid.h:27
std::string toText() const
Returns textual representation of a DUID (e.g. 00:01:02:03:ff)
Definition: duid.cc:74
const std::vector< uint8_t > & getDuid() const
Returns a const reference to the actual DUID value.
Definition: duid.cc:44
Represents a configuration for Lease File Cleanup.
void execute()
Spawns a new process.
int getExitStatus() const
Returns exit code of the last completed cleanup.
bool isRunning() const
Checks if the lease file cleanup is in progress.
LFCSetup(asiolink::IntervalTimer::Callback callback)
Constructor.
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.
Abstract Lease Manager.
Definition: lease_mgr.h:222
Wraps value holding size of the page with leases.
Definition: lease_mgr.h:43
const size_t page_size_
Holds page size.
Definition: lease_mgr.h:53
Base class for fulfilling a statistical lease data query.
Definition: lease_mgr.h:128
SubnetID getLastSubnetID() const
Returns the value of last subnet ID specified (or zero)
Definition: lease_mgr.h:183
SubnetID getFirstSubnetID() const
Returns the value of first subnet ID specified (or zero)
Definition: lease_mgr.h:178
SelectMode getSelectMode() const
Returns the selection criteria mode The value returned is based upon the constructor variant used and...
Definition: lease_mgr.h:190
Memfile derivation of the IPv4 statistical lease data query.
MemfileLeaseStatsQuery4(Lease4Storage &storage4, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for a subnet range query.
virtual ~MemfileLeaseStatsQuery4()
Destructor.
void start()
Creates the IPv4 lease statistical data result set.
MemfileLeaseStatsQuery4(Lease4Storage &storage4)
Constructor for an all subnets query.
MemfileLeaseStatsQuery4(Lease4Storage &storage4, const SubnetID &subnet_id)
Constructor for a single subnet query.
Memfile derivation of the IPv6 statistical lease data query.
MemfileLeaseStatsQuery6(Lease6Storage &storage6)
Constructor.
virtual void start()
Creates the IPv6 lease statistical data result set.
virtual ~MemfileLeaseStatsQuery6()
Destructor.
MemfileLeaseStatsQuery6(Lease6Storage &storage6, const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for a subnet range query.
MemfileLeaseStatsQuery6(Lease6Storage &storage6, const SubnetID &subnet_id)
Constructor for a single subnet query.
Base Memfile derivation of the statistical lease data query.
std::vector< LeaseStatsRow >::iterator next_pos_
An iterator for accessing the next row within the result set.
MemfileLeaseStatsQuery()
Constructor for all subnets query.
MemfileLeaseStatsQuery(const SubnetID &first_subnet_id, const SubnetID &last_subnet_id)
Constructor for subnet range query.
virtual bool getNextRow(LeaseStatsRow &row)
Fetches the next row in the result set.
std::vector< LeaseStatsRow > rows_
A vector containing the "result set".
virtual ~MemfileLeaseStatsQuery()
Destructor.
int getRowCount() const
Returns the number of rows in the result set.
MemfileLeaseStatsQuery(const SubnetID &subnet_id)
Constructor for single subnet query.
virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress &addr) const
Returns existing IPv4 lease for specified IPv4 address.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery6(const SubnetID &subnet_id)
Creates and runs the IPv6 lease stats query for a single subnet.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs)
Deletes all expired-reclaimed DHCPv6 leases.
Memfile_LeaseMgr(const db::DatabaseConnection::ParameterMap &parameters)
The sole lease manager constructor.
bool isLFCRunning() const
Checks if the process performing lease file cleanup is running.
virtual size_t wipeLeases4(const SubnetID &subnet_id)
Removes specified IPv4 leases.
virtual size_t wipeLeases6(const SubnetID &subnet_id)
Removed specified IPv6 leases.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs)
Deletes all expired-reclaimed DHCPv4 leases.
virtual void getExpiredLeases6(Lease6Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv6 leases.
Universe
Specifies universe (V4, V6)
virtual std::string getDescription() const
Returns description of the backend.
virtual LeaseStatsQueryPtr startSubnetLeaseStatsQuery4(const SubnetID &subnet_id)
Creates and runs the IPv4 lease stats query for a single subnet.
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.
virtual bool deleteLease(const isc::asiolink::IOAddress &addr)
Deletes a lease.
LFCFileType
Types of the lease files used by the Lease File Cleanup.
@ FILE_PREVIOUS
Previous Lease File.
virtual void commit()
Commit Transactions.
virtual bool addLease(const Lease4Ptr &lease)
Adds an IPv4 lease.
int getLFCExitStatus() const
Returns the status code returned by the last executed LFC process.
bool persistLeases(Universe u) const
Specifies whether or not leases are written to disk.
static std::string getDBVersion()
Local version of getDBVersion() class method.
virtual LeaseStatsQueryPtr startLeaseStatsQuery6()
Creates and runs the IPv6 lease stats query.
virtual void rollback()
Rollback Transactions.
virtual LeaseStatsQueryPtr startLeaseStatsQuery4()
Creates and runs the IPv4 lease stats query.
virtual void getExpiredLeases4(Lease4Collection &expired_leases, const size_t max_leases) const
Returns a collection of expired DHCPv4 leases.
virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress &addr) const
Returns existing IPv6 lease for a given IPv6 address.
virtual Lease6Collection getLeases6() const
Returns all IPv6 leases.
std::string getLeaseFilePath(Universe u) const
Returns an absolute path to the lease file.
virtual void lfcCallback()
A callback function triggering Lease File Cleanup (LFC).
virtual void updateLease4(const Lease4Ptr &lease4)
Updates IPv4 lease.
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.
virtual Lease4Collection getLeases4() const
Returns all IPv4 leases.
static std::string appendSuffix(const std::string &file_name, const LFCFileType &file_type)
Appends appropriate suffix to the file name.
virtual void updateLease6(const Lease6Ptr &lease6)
Updates IPv6 lease.
virtual ~Memfile_LeaseMgr()
Destructor (closes file)
std::string getDefaultLeaseFilePath(Universe u) const
Returns default path to the lease file.
Attempt to update lease that was not there.
Manages a pool of asynchronous interval timers.
Definition: timer_mgr.h:54
Exception thrown when an error occurs during CSV file processing.
Definition: csv_file.h:22
Provides input/output access to CSV files.
Definition: csv_file.h:290
Class to help with processing PID files.
Definition: pid_file.h:40
Exception thrown when error occurs during spawning a process.
Definition: process_spawn.h:20
Utility class for spawning new processes.
Definition: process_spawn.h:60
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
static const int MINOR_VERSION
Defines minor version of the memfile backend.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
Lease6Storage::index< ExpirationIndexTag >::type Lease6StorageExpirationIndex
DHCPv6 lease storage index by expiration time.
Lease4Storage::index< ClientIdHWAddressSubnetIdIndexTag >::type Lease4StorageClientIdHWAddressSubnetIdIndex
DHCPv4 lease storage index by client id, HW address and subnet id.
Lease6Storage::index< DuidIndexTag >::type Lease6StorageDuidIndex
DHCPv6 lease storage index by Subnet-id.
boost::shared_ptr< Lease6 > Lease6Ptr
Pointer to a Lease6 structure.
Definition: lease.h:463
std::vector< Lease6Ptr > Lease6Collection
A collection of IPv6 leases.
Definition: lease.h:604
boost::shared_ptr< LeaseStatsQuery > LeaseStatsQueryPtr
Defines a pointer to a LeaseStatsQuery.
Definition: lease_mgr.h:207
Lease6Storage::index< DuidIaidTypeIndexTag >::type Lease6StorageDuidIaidTypeIndex
DHCPv6 lease storage index by DUID, IAID, lease type.
boost::shared_ptr< TimerMgr > TimerMgrPtr
Type definition of the shared pointer to TimerMgr.
Definition: timer_mgr.h:25
Lease4Storage::index< ExpirationIndexTag >::type Lease4StorageExpirationIndex
DHCPv4 lease storage index by expiration time.
Lease6Storage::index< AddressIndexTag >::type Lease6StorageAddressIndex
DHCPv6 lease storage index by address.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
Lease4Storage::index< ClientIdSubnetIdIndexTag >::type Lease4StorageClientIdSubnetIdIndex
DHCPv4 lease storage index by client and subnet identifier.
Lease4Storage::index< HWAddressSubnetIdIndexTag >::type Lease4StorageHWAddressSubnetIdIndex
DHCPv4 lease storage index by HW address and subnet identifier.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
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.
Lease4Storage::index< SubnetIdIndexTag >::type Lease4StorageSubnetIdIndex
DHCPv4 lease storage index by client id, HW address and subnet id.
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< Lease4Ptr > Lease4Collection
A collection of IPv4 leases.
Definition: lease.h:455
Lease4Storage::index< AddressIndexTag >::type Lease4StorageAddressIndex
DHCPv4 lease storage index by address.
boost::shared_ptr< Lease4 > Lease4Ptr
Pointer to a Lease4 structure.
Definition: lease.h:248
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
Lease6Storage::index< SubnetIdIndexTag >::type Lease6StorageSubnetIdIndex
DHCPv6 lease storage index by Subnet-id.
Definition: edns.h:19
std::vector< std::string > ProcessArgs
Type of the container holding arguments of the executable being run as a background process.
Definition: process_spawn.h:32
Defines the logger used by the top-level component of kea-dhcp-ddns.
Tag for indexes by address.
Tag for indexes by client id, HW address and subnet id.
Tag for indexes by client and subnet identifiers.
Tag for indexes by DUID, IAID, lease type tuple.
Tag for index using DUID.
Tag for indexes by expiration time.
Hardware type that represents information from DHCPv4 packet.
Definition: hwaddr.h:20
std::vector< uint8_t > hwaddr_
Definition: hwaddr.h:98
std::string toText(bool include_htype=true) const
Returns textual representation of a hardware address (e.g.
Definition: hwaddr.cc:51
Tag for indexes by HW address, subnet identifier tuple.
Structure that holds a lease for IPv4 address.
Definition: lease.h:256
Structure that holds a lease for IPv6 address and/or prefix.
Definition: lease.h:471
uint32_t preferred_lft_
preferred lifetime
Definition: lease.h:497
Contains a single row of lease statistical data.
Definition: lease_mgr.h:61
static const uint32_t STATE_DEFAULT
A lease in the default state.
Definition: lease.h:61
uint32_t valid_lft_
Valid lifetime.
Definition: lease.h:125
static const uint32_t STATE_DECLINED
Declined lease.
Definition: lease.h:64
Type
Type of lease or pool.
Definition: lease.h:38
@ TYPE_PD
the lease contains IPv6 prefix (for prefix delegation)
Definition: lease.h:41
@ TYPE_NA
the lease contains non-temporary IPv6 address
Definition: lease.h:39
static std::string typeToText(Type type)
returns text representation of a lease type
Definition: lease.cc:39
Tag for indexs by subnet-id.