Commit 8aa3b224 authored by Jelte Jansen's avatar Jelte Jansen
Browse files

[master] Merge branch 'trac449'

Conflicts:
	doc/Doxyfile
	src/lib/Makefile.am
parents 756e56a8 adba8b7c
167. [func] zhang likun, jelte
Added a basic implementation for a resolver cache (though not
used yet).
(Trac #449, git 756e56a8c683906b1b50bba5675c996fb1295820)
166. [func] jelte
The resolver now sends back a SERVFAIL when there is a client
timeout (timeout_client config setting), but it will not stop
......
......@@ -712,6 +712,8 @@ AC_CONFIG_FILES([Makefile
src/lib/testutils/testdata/Makefile
src/lib/nsas/Makefile
src/lib/nsas/tests/Makefile
src/lib/cache/Makefile
src/lib/cache/tests/Makefile
])
AC_OUTPUT([doc/version.ent
src/bin/cfgmgr/b10-cfgmgr.py
......
......@@ -568,7 +568,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
SUBDIRS = exceptions dns cc config datasrc python xfr bench log \
resolve asiolink testutils nsas
resolve asiolink testutils nsas cache
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache
AM_CPPFLAGS += $(SQLITE_CFLAGS)
AM_CXXFLAGS = $(B10_CXXFLAGS)
# Some versions of GCC warn about some versions of Boost regarding
# missing initializer for members in its posix_time.
# https://svn.boost.org/trac/boost/ticket/3477
# But older GCC compilers don't have the flag.
AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
if USE_CLANGPP
# clang++ complains about unused function parameters in some boost header
# files.
AM_CXXFLAGS += -Wno-unused-parameter
endif
lib_LTLIBRARIES = libcache.la
libcache_la_SOURCES = resolver_cache.h resolver_cache.cc
libcache_la_SOURCES += message_cache.h message_cache.cc
libcache_la_SOURCES += message_entry.h message_entry.cc
libcache_la_SOURCES += rrset_cache.h rrset_cache.cc
libcache_la_SOURCES += rrset_entry.h rrset_entry.cc
libcache_la_SOURCES += cache_entry_key.h cache_entry_key.cc
libcache_la_SOURCES += rrset_copy.h rrset_copy.cc
libcache_la_SOURCES += local_zone_data.h local_zone_data.cc
CLEANFILES = *.gcno *.gcda
* Revisit the algorithm used by getRRsetTrustLevel() in message_entry.cc.
* Implement dump/load/resize interfaces of rrset/message/recursor cache.
* Once LRU hash table is implemented, it should be used by message/rrset cache.
* Once the hash/lrulist related files in /lib/nsas is moved to seperated
folder, the code of recursor cache has to be updated.
* Set proper AD flags once DNSSEC is supported by the cache.
* When the message or rrset entry has expired, it should be removed
from the cache, or just moved to the head of LRU list, so that it
can removed first.
* Make resolver cache be smart to refetch the messages that are about
to expire.
// Copyright (C) 2010 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.
// $Id$
#include <sstream>
#include "cache_entry_key.h"
using namespace std;
namespace isc {
namespace cache {
const std::string
genCacheEntryName(const isc::dns::Name& name, const isc::dns::RRType& type) {
std::string keystr = name.toText();
ostringstream stream;
stream << type.getCode();
keystr += stream.str();
return (keystr);
}
const std::string
genCacheEntryName(const std::string& namestr, const uint16_t type) {
std::string keystr = namestr;
ostringstream stream;
stream << type;
keystr += stream.str();
return (keystr);
}
} // namespace cache
} // namespace isc
// Copyright (C) 2010 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.
// $Id$
#ifndef __CACHE_ENTRY_KEY_H
#define __CACHE_ENTRY_KEY_H
#include <string>
#include <dns/name.h>
#include <dns/rrtype.h>
namespace isc {
namespace cache {
/// \brief Entry Name Generation Functions
///
/// Generate the name for message/rrset entries.
///
/// Concatenates the string representation of the Name and the
/// string representation of the type number.
///
/// Note: the returned name is a text string, not wire format.
/// eg. if name is 'example.com.', type is 'A', the return
/// value is 'example.com.1'
///
/// \param name The Name to create a text entry for
/// \param type The RRType to create a text entry for
/// \return return the entry name.
const std::string
genCacheEntryName(const isc::dns::Name& name, const isc::dns::RRType& type);
///
/// \overload
///
/// \param namestr A string representation of a DNS Name
/// \param type The value of a DNS RRType
const std::string
genCacheEntryName(const std::string& namestr, const uint16_t type);
} // namespace cache
} // namespace isc
#endif // __CACHE_ENTRY_KEY_H
// Copyright (C) 2010 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.
// $Id$
#include <dns/rrset.h>
#include "local_zone_data.h"
#include "cache_entry_key.h"
#include "rrset_copy.h"
using namespace std;
using namespace isc::dns;
namespace isc {
namespace cache {
typedef pair<std::string, RRsetPtr> RRsetMapPair;
typedef map<std::string, RRsetPtr>::iterator RRsetMapIterator;
isc::dns::RRsetPtr
LocalZoneData::lookup(const isc::dns::Name& name,
const isc::dns::RRType& type)
{
string key = genCacheEntryName(name, type);
RRsetMapIterator iter = rrsets_map_.find(key);
if (iter == rrsets_map_.end()) {
return (RRsetPtr());
} else {
return (iter->second);
}
}
void
LocalZoneData::update(const isc::dns::RRset& rrset) {
//TODO Do we really need to recreate the rrset again?
string key = genCacheEntryName(rrset.getName(), rrset.getType());
RRset* rrset_copy = new RRset(rrset.getName(), rrset.getClass(),
rrset.getType(), rrset.getTTL());
rrsetCopy(rrset, *rrset_copy);
RRsetPtr rrset_ptr(rrset_copy);
rrsets_map_[key] = rrset_ptr;
}
} // namespace cache
} // namespace isc
// Copyright (C) 2010 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.
// $Id$
#ifndef _LOCAL_ZONE_DATA
#define _LOCAL_ZONE_DATA
#include <map>
#include <string>
#include <boost/shared_ptr.hpp>
#include <dns/rrset.h>
namespace isc {
namespace cache {
/// \brief Local Zone Data
/// The object of LocalZoneData represents the data of one
/// local zone. It provides the interface for lookup the rrsets
/// in the zone.
class LocalZoneData {
public:
LocalZoneData(uint16_t rrset_class) : class_(rrset_class)
{}
/// \brief Look up one rrset.
///
/// \param qname The query name to look up
/// \param qtype The query type to look up
/// \return return the shared_ptr of rrset if it is
/// found in the local zone, or else, return NULL.
isc::dns::RRsetPtr lookup(const isc::dns::Name& qname,
const isc::dns::RRType& qtype);
/// \brief Update the rrset in the local zone.
///
/// If the rrset doesn't exist, it will be added.
/// Otherwise, the existed one will be overwritten.
///
/// \param rrset The rrset to update
void update(const isc::dns::RRset& rrset);
private:
std::map<std::string, isc::dns::RRsetPtr> rrsets_map_; // RRsets of the zone
uint16_t class_; // The class of the zone
};
typedef boost::shared_ptr<LocalZoneData> LocalZoneDataPtr;
typedef boost::shared_ptr<const LocalZoneData> ConstLocalZoneDataPtr;
} // namespace cache
} // namespace isc
#endif // _LOCAL_ZONE_DATA
// Copyright (C) 2010 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.
// $Id$
#include <nsas/nsas_entry_compare.h>
#include <nsas/hash_table.h>
#include <nsas/hash_deleter.h>
#include "message_cache.h"
#include "cache_entry_key.h"
using namespace isc::nsas;
using namespace isc::dns;
using namespace std;
namespace isc {
namespace cache {
MessageCache::MessageCache(boost::shared_ptr<RRsetCache> rrset_cache,
uint32_t cache_size, uint16_t message_class):
message_class_(message_class),
rrset_cache_(rrset_cache),
message_table_(new NsasEntryCompare<MessageEntry>, cache_size),
message_lru_((3 * cache_size),
new HashDeleter<MessageEntry>(message_table_))
{
}
bool
MessageCache::lookup(const isc::dns::Name& qname,
const isc::dns::RRType& qtype,
isc::dns::Message& response)
{
std::string entry_name = genCacheEntryName(qname, qtype);
HashKey entry_key = HashKey(entry_name, RRClass(message_class_));
MessageEntryPtr msg_entry = message_table_.get(entry_key);
if(msg_entry) {
message_lru_.touch(msg_entry);
return (msg_entry->genMessage(time(NULL), response));
}
return (false);
}
bool
MessageCache::update(const Message& msg) {
QuestionIterator iter = msg.beginQuestion();
std::string entry_name = genCacheEntryName((*iter)->getName(), (*iter)->getType());
HashKey entry_key = HashKey(entry_name, RRClass(message_class_));
// The simplest way to update is removing the old message entry directly.
// We have find the existed message entry, since we need to delete it
// from lru list too.
// TODO, but there should be a better way, since we here have to remove and
// add the message entry, maybe there is one way to touch it once.
MessageEntryPtr old_msg_entry = message_table_.get(entry_key);
if (old_msg_entry) {
message_lru_.remove(old_msg_entry);
}
MessageEntryPtr msg_entry(new MessageEntry(msg, rrset_cache_));
message_lru_.add(msg_entry);
return (message_table_.add(msg_entry, entry_key, true));
}
void
MessageCache::dump(const std::string&) {
//TODO
}
void
MessageCache::load(const std::string&) {
//TODO
}
bool
MessageCache::resize(uint32_t) {
//TODO
return (true);
}
} // namespace cache
} // namespace isc
// Copyright (C) 2010 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.
// $Id$
#ifndef __MESSAGE_CACHE_H
#define __MESSAGE_CACHE_H
#include <string>
#include <boost/shared_ptr.hpp>
#include <dns/message.h>
#include "message_entry.h"
#include <nsas/hash_table.h>
#include <nsas/lru_list.h>
namespace isc {
namespace cache {
class RRsetCache;
/// \brief Message Cache
/// The object of MessageCache represents the cache for class-specific
/// messages.
///
class MessageCache {
// Noncopyable
private:
MessageCache(const MessageCache& source);
MessageCache& operator=(const MessageCache& source);
public:
/// \param cache_size The size of message cache.
MessageCache(boost::shared_ptr<RRsetCache> rrset_cache_,
uint32_t cache_size, uint16_t message_class);
/// \brief Look up message in cache.
/// \param message generated response message if the message entry
/// can be found.
///
/// \return return true if the message can be found in cache, or else,
/// return false.
//TODO Maybe some user just want to get the message_entry.
bool lookup(const isc::dns::Name& qname,
const isc::dns::RRType& qtype,
isc::dns::Message& message);
/// \brief Update the message in the cache with the new one.
/// If the message doesn't exist in the cache, it will be added
/// directly.
bool update(const isc::dns::Message& msg);
/// \brief Dump the message cache to specified file.
/// \todo It should can be dumped to one configured database.
void dump(const std::string& file_name);
/// \brief Load the cache from one file.
/// \todo It should can be loaded from one configured database.
void load(const std::string& file_name);
/// \brief Resize the size of message cache in runtime.
bool resize(uint32_t size);
protected:
/// \brief Get the hash key for the message entry in the cache.
/// \param name query name of the message.
/// \param type query type of the message.
/// \return return the hash key.
HashKey getEntryHashKey(const isc::dns::Name& name,
const isc::dns::RRType& type) const;
// Make these variants be protected for easy unittest.
protected:
uint16_t message_class_; // The class of the message cache.
boost::shared_ptr<RRsetCache> rrset_cache_;
isc::nsas::HashTable<MessageEntry> message_table_;
isc::nsas::LruList<MessageEntry> message_lru_;
};
typedef boost::shared_ptr<MessageCache> MessageCachePtr;
} // namespace cache
} // namespace isc
#endif // __MESSAGE_CACHE_H
// Copyright (C) 2010 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.
// $Id$
#include <limits>
#include <dns/message.h>
#include <nsas/nsas_entry.h>
#include "message_entry.h"
#include "rrset_cache.h"
using namespace isc::dns;
using namespace std;
namespace isc {
namespace cache {
static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();
MessageEntry::MessageEntry(const isc::dns::Message& msg,
boost::shared_ptr<RRsetCache> rrset_cache):
rrset_cache_(rrset_cache),
headerflag_aa_(false),
headerflag_tc_(false)
{
initMessageEntry(msg);
entry_name_ = genCacheEntryName(query_name_, query_type_);
hash_key_ptr_ = new HashKey(entry_name_, RRClass(query_class_));
}
bool
MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
const time_t time_now)
{
uint16_t entry_count = answer_count_ + authority_count_ + additional_count_;
rrset_entry_vec.reserve(rrset_entry_vec.size() + entry_count);
for (int index = 0; index < entry_count; ++index) {
RRsetEntryPtr rrset_entry = rrset_cache_->lookup(rrsets_[index].name_,
rrsets_[index].type_);
if (time_now < rrset_entry->getExpireTime()) {
rrset_entry_vec.push_back(rrset_entry);
} else {
return (false);
}
}
return (true);
}
void
MessageEntry::addRRset(isc::dns::Message& message,
const vector<RRsetEntryPtr>& rrset_entry_vec,
const isc::dns::Message::Section& section,
bool dnssec_need)
{
uint16_t start_index = 0;
uint16_t end_index = answer_count_;
assert(section != Message::SECTION_QUESTION);
if (section == Message::SECTION_AUTHORITY) {
start_index = answer_count_;
end_index = answer_count_ + authority_count_;
} else if (section == Message::SECTION_ADDITIONAL) {
start_index = answer_count_ + authority_count_;
end_index = start_index + additional_count_;
}
for(uint16_t index = start_index; index < end_index; ++index) {
message.addRRset(section, rrset_entry_vec[index]->getRRset(), dnssec_need);
}
}
bool
MessageEntry::genMessage(const time_t& time_now,
isc::dns::Message& msg)
{
if (time_now >= expire_time_) {
// The message entry has expired.
return (false);
} else {
// Before do any generation, we should check if some rrset
// has expired, if it is, return false.
vector<RRsetEntryPtr> rrset_entry_vec;
if (false == getRRsetEntries(rrset_entry_vec, time_now)) {
return (false);
}
// Begin message generation. We don't need to add question
// section, since it has been included in the message.
// Set cached header flags.
msg.setHeaderFlag(Message::HEADERFLAG_AA, headerflag_aa_);
msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
bool dnssec_need = msg.getEDNS().get();
addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER, dnssec_need);
addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY, dnssec_need);
addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL, dnssec_need);
return (true);
}
}
RRsetTrustLevel
MessageEntry::getRRsetTrustLevel(const Message& message,