// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #ifndef LEASE_FILE_LOADER_H #define LEASE_FILE_LOADER_H #include #include #include #include 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. /// /// @todo Add a method which dumps all leases from the storage to a /// specified lease file. 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 /// lease file must be opened and the internal file pointer should /// be set to the beginning of 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. /// @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 static void load(LeaseFileType& lease_file, StorageType& storage, const uint32_t max_errors = 0xFFFFFFFF) { LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LEASE_FILE_LOAD) .arg(lease_file.getFilename()); boost::shared_ptr 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 ((max_errors < 0xFFFFFFFF) && (++errcnt > max_errors)) { 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 { **lease_it = *lease; } } } else { // Being here means that we hit the end of file. break; } } } }; } } #endif // LEASE_FILE_LOADER_H