123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #ifndef LEASE_FILE_LOADER_H
- #define LEASE_FILE_LOADER_H
- #include <dhcpsrv/dhcpsrv_log.h>
- #include <dhcpsrv/memfile_lease_storage.h>
- #include <util/versioned_csv_file.h>
- #include <boost/shared_ptr.hpp>
- namespace isc {
- namespace dhcp {
- /// @brief Utility class to manage bulk of leases in the lease files.
- ///
- /// This class exposes methods which allow for bulk loading leases from
- /// the lease file and dumping the leases held in memory into the
- /// lease file. There are two major use cases for this class:
- /// - load leases by the DHCP server when the server starts up or
- /// reloads configuration,
- /// - an application performing a lease file cleanup rewrites the whole
- /// lease file to remove the redundant lease entries.
- ///
- /// In the former case, this class is used by the @c MemFile_LeaseMgr.
- /// In the latter case, this class is used by the standalone application
- /// which reads the whole lease file into memory (storage) and then
- /// dumps the leases held in the storage to another file.
- ///
- /// The methods in this class are templated so as they can be used both
- /// with the @c Lease4Storage and @c Lease6Storage to process the DHCPv4
- /// and DHCPv6 leases respectively.
- ///
- class LeaseFileLoader {
- public:
- /// @brief Load leases from the lease file into the specified storage.
- ///
- /// This method iterates over the entries in the lease file in the
- /// CSV format, creates @c Lease4 or @c Lease6 objects and inserts
- /// them into the storage to which reference is specified as an
- /// argument. If there are multiple entries for the particular lease
- /// in the lease file the entries further in the lease file override
- /// the previous entries.
- ///
- /// If the method finds the entry with the valid lifetime of 0 it
- /// means that the particular lease was released and the method
- /// removes an existing lease from the container.
- ///
- /// @param lease_file A reference to the @c CSVLeaseFile4 or
- /// @c CSVLeaseFile6 object representing the lease file. The file
- /// doesn't need to be open because the method re-opens the file.
- /// @param storage A reference to the container to which leases
- /// should be inserted.
- /// @param max_errors Maximum number of corrupted leases in the
- /// lease file. The method will skip corrupted leases but after
- /// exceeding the specified number of errors it will throw an
- /// exception.
- /// @param close_file_on_exit A boolean flag which indicates if
- /// the file should be closed after it has been successfully parsed.
- /// One case when the file is not opened is when the server starts
- /// up, reads the leases in the file and then leaves the file open
- /// for writing future lease updates.
- /// @tparam LeaseObjectType A @c Lease4 or @c Lease6.
- /// @tparam LeaseFileType A @c CSVLeaseFile4 or @c CSVLeaseFile6.
- /// @tparam StorageType A @c Lease4Storage or @c Lease6Storage.
- ///
- /// @throw isc::util::CSVFileError when the maximum number of errors
- /// has been exceeded.
- template<typename LeaseObjectType, typename LeaseFileType,
- typename StorageType>
- static void load(LeaseFileType& lease_file, StorageType& storage,
- const uint32_t max_errors = 0xFFFFFFFF,
- const bool close_file_on_exit = true) {
- LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LEASE_FILE_LOAD)
- .arg(lease_file.getFilename());
- // Reopen the file, as we don't know whether the file is open
- // and we also don't know its current state.
- lease_file.close();
- lease_file.open();
- boost::shared_ptr<LeaseObjectType> lease;
- // Track the number of corrupted leases.
- uint32_t errcnt = 0;
- while (true) {
- // Unable to parse the lease.
- if (!lease_file.next(lease)) {
- // A value of 0xFFFFFFFF indicates that we don't return
- // until the whole file is parsed, even if errors occur.
- // Otherwise, check if we have exceeded the maximum number
- // of errors and throw an exception if we have.
- if (++errcnt > max_errors) {
- // If we break parsing the CSV file because of too many
- // errors, it doesn't make sense to keep the file open.
- // This is because the caller wouldn't know where we
- // stopped parsing and where the internal file pointer
- // is. So, there are probably no cases when the caller
- // would continue to use the open file.
- lease_file.close();
- isc_throw(util::CSVFileError, "exceeded maximum number of"
- " failures " << max_errors << " to read a lease"
- " from the lease file "
- << lease_file.getFilename());
- }
- // Skip the corrupted lease.
- continue;
- }
- // Lease was found and we successfully parsed it.
- if (lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA,
- DHCPSRV_MEMFILE_LEASE_LOAD)
- .arg(lease->toText());
- // Check if this lease exists.
- typename StorageType::iterator lease_it =
- storage.find(lease->addr_);
- // The lease doesn't exist yet. Insert the lease if
- // it has a positive valid lifetime.
- if (lease_it == storage.end()) {
- if (lease->valid_lft_ > 0) {
- storage.insert(lease);
- }
- } else {
- // The lease exists. If the new entry has a valid
- // lifetime of 0 it is an indication to remove the
- // existing entry. Otherwise, we update the lease.
- if (lease->valid_lft_ == 0) {
- storage.erase(lease_it);
- } else {
- // Use replace to re-index leases on update.
- storage.replace(lease_it, lease);
- }
- }
- } else {
- // Being here means that we hit the end of file.
- break;
- }
- }
- if (lease_file.needsConversion()) {
- LOG_WARN(dhcpsrv_logger,
- (lease_file.getInputSchemaState()
- == util::VersionedCSVFile::NEEDS_UPGRADE
- ? DHCPSRV_MEMFILE_NEEDS_UPGRADING
- : DHCPSRV_MEMFILE_NEEDS_DOWNGRADING))
- .arg(lease_file.getFilename())
- .arg(lease_file.getSchemaVersion());
- }
- if (close_file_on_exit) {
- lease_file.close();
- }
- }
- /// @brief Write leases from the storage into a lease file
- ///
- /// This method iterates over the @c Lease4 or @c Lease6 object in the
- /// storage specified in the arguments and writes them to the file
- /// specified in the arguments.
- ///
- /// This method writes all entries in the storage to the file, it does
- /// not perform any checks for expiration or duplication.
- ///
- /// The order in which the entries will be written to the file depends
- /// on the first index in the multi-index container. Currently that
- /// is the v4 or v6 IP address and they are written from lowest to highest.
- ///
- /// Before writing the method will close the file if it is open
- /// and reopen it for writing. After completion it will close
- /// the file.
- ///
- /// @param lease_file A reference to the @c CSVLeaseFile4 or
- /// @c CSVLeaseFile6 object representing the lease file. The file
- /// doesn't need to be open because the method re-opens the file.
- /// @param storage A reference to the container from which leases
- /// should be written.
- ///
- /// @tparam LeaseObjectType A @c Lease4 or @c Lease6.
- /// @tparam LeaseFileType A @c CSVLeaseFile4 or @c CSVLeaseFile6.
- /// @tparam StorageType A @c Lease4Storage or @c Lease6Storage.
- template<typename LeaseObjectType, typename LeaseFileType,
- typename StorageType>
- static void write(LeaseFileType& lease_file, const StorageType& storage) {
- // Reopen the file, as we don't know whether the file is open
- // and we also don't know its current state.
- lease_file.close();
- lease_file.open();
- // Iterate over the storage area writing out the leases
- for (typename StorageType::const_iterator lease = storage.begin();
- lease != storage.end();
- ++lease) {
- try {
- lease_file.append(**lease);
- } catch (const isc::Exception&) {
- // Close the file
- lease_file.close();
- throw;
- }
- }
- // Close the file
- lease_file.close();
- }
- };
- } // namesapce dhcp
- } // namespace isc
- #endif // LEASE_FILE_LOADER_H
|