123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- // Copyright (C) 2012-2014 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.
- #include <dhcpsrv/cfgmgr.h>
- #include <dhcpsrv/dhcpsrv_log.h>
- #include <dhcpsrv/memfile_lease_mgr.h>
- #include <exceptions/exceptions.h>
- #include <iostream>
- using namespace isc::dhcp;
- Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
- : LeaseMgr(parameters) {
- // Check the universe and use v4 file or v6 file.
- std::string universe = getParameter("universe");
- if (universe == "4") {
- std::string file4 = initLeaseFilePath(V4);
- if (!file4.empty()) {
- lease_file4_.reset(new CSVLeaseFile4(file4));
- lease_file4_->open();
- load4();
- }
- } else {
- std::string file6 = initLeaseFilePath(V6);
- if (!file6.empty()) {
- lease_file6_.reset(new CSVLeaseFile6(file6));
- lease_file6_->open();
- load6();
- }
- }
- // If lease persistence have been disabled for both v4 and v6,
- // issue a warning. It is ok not to write leases to disk when
- // doing testing, but it should not be done in normal server
- // operation.
- if (!persistLeases(V4) && !persistLeases(V6)) {
- LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
- }
- }
- Memfile_LeaseMgr::~Memfile_LeaseMgr() {
- if (lease_file4_) {
- lease_file4_->close();
- lease_file4_.reset();
- }
- if (lease_file6_) {
- lease_file6_->close();
- lease_file6_.reset();
- }
- }
- bool
- Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
- if (getLease4(lease->addr_)) {
- // there is a lease with specified address already
- return (false);
- }
- // Try to write a lease to disk first. If this fails, the lease will
- // not be inserted to the memory and the disk and in-memory data will
- // remain consistent.
- if (persistLeases(V4)) {
- lease_file4_->append(*lease);
- }
- storage4_.insert(lease);
- return (true);
- }
- bool
- Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
- if (getLease6(lease->type_, lease->addr_)) {
- // there is a lease with specified address already
- return (false);
- }
- // Try to write a lease to disk first. If this fails, the lease will
- // not be inserted to the memory and the disk and in-memory data will
- // remain consistent.
- if (persistLeases(V6)) {
- lease_file6_->append(*lease);
- }
- storage6_.insert(lease);
- return (true);
- }
- Lease4Ptr
- Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
- typedef Lease4Storage::nth_index<0>::type SearchIndex;
- const SearchIndex& idx = storage4_.get<0>();
- Lease4Storage::iterator l = idx.find(addr);
- if (l == storage4_.end()) {
- return (Lease4Ptr());
- } else {
- return (Lease4Ptr(new Lease4(**l)));
- }
- }
- Lease4Collection
- Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
- typedef Lease4Storage::nth_index<0>::type SearchIndex;
- Lease4Collection collection;
- const SearchIndex& idx = storage4_.get<0>();
- for(SearchIndex::const_iterator lease = idx.begin();
- lease != idx.end(); ++lease) {
- // Every Lease4 has a hardware address, so we can compare it
- if ((*lease)->hwaddr_ == hwaddr.hwaddr_) {
- collection.push_back((*lease));
- }
- }
- return (collection);
- }
- Lease4Ptr
- Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
- .arg(hwaddr.toText());
- // We are going to use index #1 of the multi index container.
- // We define SearchIndex locally in this function because
- // currently only this function uses this index.
- typedef Lease4Storage::nth_index<1>::type SearchIndex;
- // Get the index.
- const SearchIndex& idx = storage4_.get<1>();
- // Try to find the lease using HWAddr and subnet id.
- SearchIndex::const_iterator lease =
- idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
- // Lease was not found. Return empty pointer to the caller.
- if (lease == idx.end()) {
- return (Lease4Ptr());
- }
- // Lease was found. Return it to the caller.
- return (Lease4Ptr(new Lease4(**lease)));
- }
- Lease4Collection
- Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
- typedef Memfile_LeaseMgr::Lease4Storage::nth_index<0>::type SearchIndex;
- Lease4Collection collection;
- const SearchIndex& idx = storage4_.get<0>();
- for(SearchIndex::const_iterator lease = idx.begin();
- lease != idx.end(); ++ lease) {
- // client-id is not mandatory in DHCPv4. There can be a lease that does
- // not have a client-id. Dereferencing null pointer would be a bad thing
- if((*lease)->client_id_ && *(*lease)->client_id_ == client_id) {
- collection.push_back((*lease));
- }
- }
- return (collection);
- }
- Lease4Ptr
- Memfile_LeaseMgr::getLease4(const ClientId& client_id,
- const HWAddr& hwaddr,
- SubnetID subnet_id) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
- .arg(hwaddr.toText())
- .arg(subnet_id);
- // We are going to use index #3 of the multi index container.
- // We define SearchIndex locally in this function because
- // currently only this function uses this index.
- typedef Lease4Storage::nth_index<3>::type SearchIndex;
- // Get the index.
- const SearchIndex& idx = storage4_.get<3>();
- // Try to get the lease using client id, hardware address and subnet id.
- SearchIndex::const_iterator lease =
- idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
- subnet_id));
- if (lease == idx.end()) {
- // Lease was not found. Return empty pointer to the caller.
- return (Lease4Ptr());
- }
- // Lease was found. Return it to the caller.
- return (*lease);
- }
- Lease4Ptr
- Memfile_LeaseMgr::getLease4(const ClientId& client_id,
- SubnetID subnet_id) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
- .arg(client_id.toText());
- // We are going to use index #2 of the multi index container.
- // We define SearchIndex locally in this function because
- // currently only this function uses this index.
- typedef Lease4Storage::nth_index<2>::type SearchIndex;
- // Get the index.
- const SearchIndex& idx = storage4_.get<2>();
- // Try to get the lease using client id and subnet id.
- SearchIndex::const_iterator lease =
- idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
- // Lease was not found. Return empty pointer to the caller.
- if (lease == idx.end()) {
- return (Lease4Ptr());
- }
- // Lease was found. Return it to the caller.
- return (Lease4Ptr(new Lease4(**lease)));
- }
- Lease6Ptr
- Memfile_LeaseMgr::getLease6(Lease::Type type,
- const isc::asiolink::IOAddress& addr) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_ADDR6)
- .arg(addr.toText())
- .arg(Lease::typeToText(type));
- Lease6Storage::iterator l = storage6_.find(addr);
- if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
- return (Lease6Ptr());
- } else {
- return (Lease6Ptr(new Lease6(**l)));
- }
- }
- Lease6Collection
- Memfile_LeaseMgr::getLeases6(Lease::Type type,
- const DUID& duid, uint32_t iaid) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_IAID_DUID)
- .arg(iaid)
- .arg(duid.toText())
- .arg(Lease::typeToText(type));
- // We are going to use index #1 of the multi index container.
- typedef Lease6Storage::nth_index<1>::type SearchIndex;
- // Get the index.
- const SearchIndex& idx = storage6_.get<1>();
- // Try to get the lease using the DUID, IAID and lease type.
- std::pair<SearchIndex::iterator, SearchIndex::iterator> l =
- idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
- Lease6Collection collection;
- for(SearchIndex::iterator lease = l.first; lease != l.second; ++lease) {
- collection.push_back(Lease6Ptr(new Lease6(**lease)));
- }
- return (collection);
- }
- Lease6Collection
- Memfile_LeaseMgr::getLeases6(Lease::Type type,
- const DUID& duid, uint32_t iaid,
- SubnetID subnet_id) const {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
- .arg(iaid)
- .arg(subnet_id)
- .arg(duid.toText())
- .arg(Lease::typeToText(type));
- // We are going to use index #1 of the multi index container.
- typedef Lease6Storage::nth_index<1>::type SearchIndex;
- // Get the index.
- const SearchIndex& idx = storage6_.get<1>();
- // Try to get the lease using the DUID, IAID and lease type.
- std::pair<SearchIndex::iterator, SearchIndex::iterator> l =
- idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
- Lease6Collection collection;
- for(SearchIndex::iterator lease = l.first; lease != l.second; ++lease) {
- // Filter out the leases which subnet id doesn't match.
- if((*lease)->subnet_id_ == subnet_id) {
- collection.push_back(Lease6Ptr(new Lease6(**lease)));
- }
- }
- return (collection);
- }
- void
- Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
- Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
- if (lease_it == storage4_.end()) {
- isc_throw(NoSuchLease, "failed to update the lease with address "
- << lease->addr_ << " - no such lease");
- }
- // Try to write a lease to disk first. If this fails, the lease will
- // not be inserted to the memory and the disk and in-memory data will
- // remain consistent.
- if (persistLeases(V4)) {
- lease_file4_->append(*lease);
- }
- **lease_it = *lease;
- }
- void
- Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
- Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
- if (lease_it == storage6_.end()) {
- isc_throw(NoSuchLease, "failed to update the lease with address "
- << lease->addr_ << " - no such lease");
- }
- // Try to write a lease to disk first. If this fails, the lease will
- // not be inserted to the memory and the disk and in-memory data will
- // remain consistent.
- if (persistLeases(V6)) {
- lease_file6_->append(*lease);
- }
- **lease_it = *lease;
- }
- bool
- Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
- if (addr.isV4()) {
- // v4 lease
- Lease4Storage::iterator l = storage4_.find(addr);
- if (l == storage4_.end()) {
- // No such lease
- return (false);
- } else {
- if (persistLeases(V4)) {
- // Copy the lease. The valid lifetime needs to be modified and
- // we don't modify the original lease.
- Lease4 lease_copy = **l;
- // Setting valid lifetime to 0 means that lease is being
- // removed.
- lease_copy.valid_lft_ = 0;
- lease_file4_->append(lease_copy);
- }
- storage4_.erase(l);
- return (true);
- }
- } else {
- // v6 lease
- Lease6Storage::iterator l = storage6_.find(addr);
- if (l == storage6_.end()) {
- // No such lease
- return (false);
- } else {
- if (persistLeases(V6)) {
- // Copy the lease. The lifetimes need to be modified and we
- // don't modify the original lease.
- Lease6 lease_copy = **l;
- // Setting lifetimes to 0 means that lease is being removed.
- lease_copy.valid_lft_ = 0;
- lease_copy.preferred_lft_ = 0;
- lease_file6_->append(lease_copy);
- }
- storage6_.erase(l);
- return (true);
- }
- }
- }
- std::string
- Memfile_LeaseMgr::getDescription() const {
- return (std::string("This is a dummy memfile backend implementation.\n"
- "It does not offer any useful lease management and its only\n"
- "purpose is to test abstract lease manager API."));
- }
- void
- Memfile_LeaseMgr::commit() {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
- }
- void
- Memfile_LeaseMgr::rollback() {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
- DHCPSRV_MEMFILE_ROLLBACK);
- }
- std::string
- Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
- std::ostringstream s;
- s << CfgMgr::instance().getDataDir() << "/kea-leases";
- s << (u == V4 ? "4" : "6");
- s << ".csv";
- return (s.str());
- }
- std::string
- Memfile_LeaseMgr::getLeaseFilePath(Universe u) const {
- if (u == V4) {
- return (lease_file4_ ? lease_file4_->getFilename() : "");
- }
- return (lease_file6_ ? lease_file6_->getFilename() : "");
- }
- bool
- Memfile_LeaseMgr::persistLeases(Universe u) const {
- // Currently, if the lease file IO is not created, it means that writes to
- // disk have been explicitly disabled by the administrator. At some point,
- // there may be a dedicated ON/OFF flag implemented to control this.
- if (u == V4 && lease_file4_) {
- return (true);
- }
- return (u == V6 && lease_file6_);
- }
- std::string
- Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
- std::string persist_val;
- try {
- persist_val = getParameter("persist");
- } catch (const Exception& ex) {
- // If parameter persist hasn't been specified, we use a default value
- // 'yes'.
- persist_val = "true";
- }
- // If persist_val is 'false' we will not store leases to disk, so let's
- // return empty file name.
- if (persist_val == "false") {
- return ("");
- } else if (persist_val != "true") {
- isc_throw(isc::BadValue, "invalid value 'persist="
- << persist_val << "'");
- }
- std::string lease_file;
- try {
- lease_file = getParameter("name");
- } catch (const Exception& ex) {
- lease_file = getDefaultLeaseFilePath(u);
- }
- return (lease_file);
- }
- void
- Memfile_LeaseMgr::load4() {
- // If lease file hasn't been opened, we are working in non-persistent mode.
- // That's fine, just leave.
- if (!persistLeases(V4)) {
- return;
- }
- LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LEASES_RELOAD4)
- .arg(lease_file4_->getFilename());
- // Remove existing leases (if any). We will recreate them based on the
- // data on disk.
- storage4_.clear();
- Lease4Ptr lease;
- do {
- /// @todo Currently we stop parsing on first failure. It is possible
- /// that only one (or a few) leases are bad, so in theory we could
- /// continue parsing but that would require some error counters to
- /// prevent endless loops. That is enhancement for later time.
- if (!lease_file4_->next(lease)) {
- isc_throw(DbOperationError, "Failed to parse the DHCPv6 lease in"
- " the lease file: " << lease_file4_->getReadMsg());
- }
- // If we got the lease, we update the internal container holding
- // leases. Otherwise, we reached the end of file and we leave.
- if (lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA,
- DHCPSRV_MEMFILE_LEASE_LOAD4)
- .arg(lease->toText());
- loadLease4(lease);
- }
- } while (lease);
- }
- void
- Memfile_LeaseMgr::loadLease4(Lease4Ptr& lease) {
- // Check if the lease already exists.
- Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
- // Lease doesn't exist.
- if (lease_it == storage4_.end()) {
- // Add the lease only if valid lifetime is greater than 0.
- // We use valid lifetime of 0 to indicate that lease should
- // be removed.
- if (lease->valid_lft_ > 0) {
- storage4_.insert(lease);
- }
- } else {
- // We use valid lifetime of 0 to indicate that the lease is
- // to be removed. In such case, erase the lease.
- if (lease->valid_lft_ == 0) {
- storage4_.erase(lease_it);
- } else {
- // Update existing lease.
- **lease_it = *lease;
- }
- }
- }
- void
- Memfile_LeaseMgr::load6() {
- // If lease file hasn't been opened, we are working in non-persistent mode.
- // That's fine, just leave.
- if (!persistLeases(V6)) {
- return;
- }
- LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LEASES_RELOAD6)
- .arg(lease_file6_->getFilename());
- // Remove existing leases (if any). We will recreate them based on the
- // data on disk.
- storage6_.clear();
- Lease6Ptr lease;
- do {
- /// @todo Currently we stop parsing on first failure. It is possible
- /// that only one (or a few) leases are bad, so in theory we could
- /// continue parsing but that would require some error counters to
- /// prevent endless loops. That is enhancement for later time.
- if (!lease_file6_->next(lease)) {
- isc_throw(DbOperationError, "Failed to parse the DHCPv6 lease in"
- " the lease file: " << lease_file6_->getReadMsg());
- }
- // If we got the lease, we update the internal container holding
- // leases. Otherwise, we reached the end of file and we leave.
- if (lease) {
- LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA,
- DHCPSRV_MEMFILE_LEASE_LOAD6)
- .arg(lease->toText());
- loadLease6(lease);
- }
- } while (lease);
- }
- void
- Memfile_LeaseMgr::loadLease6(Lease6Ptr& lease) {
- // Check if the lease already exists.
- Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
- // Lease doesn't exist.
- if (lease_it == storage6_.end()) {
- // Add the lease only if valid lifetime is greater than 0.
- // We use valid lifetime of 0 to indicate that lease should
- // be removed.
- if (lease->valid_lft_ > 0) {
- storage6_.insert(lease);
- }
- } else {
- // We use valid lifetime of 0 to indicate that the lease is
- // to be removed. In such case, erase the lease.
- if (lease->valid_lft_ == 0) {
- storage6_.erase(lease_it);
- } else {
- // Update existing lease.
- **lease_it = *lease;
- }
- }
- }
|