Commit 1b616670 authored by Yoshitaka Aharen's avatar Yoshitaka Aharen
Browse files

[2157] modified an interface to get statistics data

Counters::get returns auth statistics data in the format defined in the
spec file.
parent 2f912a5d
......@@ -319,7 +319,7 @@
"item_optional": false,
"item_default": 0,
"item_title": "request.sig0",
"item_description": "Number of requests with SIG(0) received; not implemented in BIND 10"
"item_description": "Number of requests with SIG(0) received; currently not implemented in BIND 10"
},
{
"item_name": "request.badsig",
......@@ -991,7 +991,7 @@
"item_optional": false,
"item_default": 0,
"item_title": "response.edns0",
"item_description": "Number of responses with EDNS0; not implemented in BIND 10"
"item_description": "Number of responses with EDNS0"
},
{
"item_name": "response.tsig",
......@@ -1007,7 +1007,7 @@
"item_optional": false,
"item_default": 0,
"item_title": "response.sig0",
"item_description": "Number of responses with SIG(0); not implemented in BIND 10"
"item_description": "Number of responses with SIG(0); currently not implemented in BIND 10"
},
{
"item_name": "qrysuccess",
......
......@@ -282,10 +282,6 @@ public:
}
}
/// Bind the ModuleSpec object in config_session_ with
/// isc:config::ModuleSpec::validateStatistics.
void registerStatisticsValidator();
/// Socket session forwarder for dynamic update requests
BaseSocketSessionForwarder& ddns_base_forwarder_;
......@@ -319,9 +315,6 @@ private:
bool xfrout_connected_;
AbstractXfroutClient& xfrout_client_;
// validateStatistics
bool validateStatistics(isc::data::ConstElementPtr data) const;
auth::Query query_;
};
......@@ -489,7 +482,6 @@ AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
void
AuthSrv::setConfigSession(ModuleCCSession* config_session) {
impl_->config_session_ = config_session;
impl_->registerStatisticsValidator();
}
ModuleCCSession*
......@@ -566,7 +558,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
// statistics: check TSIG attributes
// SIG(0) is currently not implemented in Auth
stats_attrs.setQuerySig(true, false,
tsig_error == TSIGError::NOERROR());
tsig_error != TSIGError::NOERROR());
}
if (tsig_error != TSIGError::NOERROR()) {
......@@ -584,7 +576,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
{
ConstEDNSPtr edns = message.getEDNS();
if (edns != NULL) {
stats_attrs.setQueryEDNS(true, edns->getVersion() == 0);
stats_attrs.setQueryEDNS(true, edns->getVersion() != 0);
stats_attrs.setQueryDO(edns->getDNSSECAwareness());
}
}
......@@ -825,22 +817,6 @@ AuthSrvImpl::processUpdate(const IOMessage& io_message) {
return (false);
}
void
AuthSrvImpl::registerStatisticsValidator() {
counters_.registerStatisticsValidator(
boost::bind(&AuthSrvImpl::validateStatistics, this, _1));
}
bool
AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
if (config_session_ == NULL) {
return (false);
}
return (
config_session_->getModuleSpec().validateStatistics(
data, true));
}
void
AuthSrvImpl::resumeServer(DNSServer* server, Message& message,
statistics::QRAttributes& stats_attrs,
......@@ -870,7 +846,7 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
}
ConstElementPtr AuthSrv::getStatistics() const {
return (impl_->counters_.getStatistics());
return (impl_->counters_.get());
}
const AddressList&
......
......@@ -44,20 +44,34 @@ using namespace isc::dns;
using namespace isc::auth;
using namespace isc::statistics;
namespace {
void
fillNodes(const Counter& counter, const char* const nodename[],
const size_t size,
isc::auth::statistics::Counters::ItemTreeType& trees)
{
using namespace isc::data;
for (size_t i = 0; i < size; ++i) {
trees->set (nodename[i],
Element::create(static_cast<long int>(counter.get(i)))
);
}
}
} // anonymous namespace
namespace isc {
namespace auth {
namespace statistics {
// TODO: Make use of wrappers like isc::dns::Opcode
// for counter item type.
class CountersImpl : boost::noncopyable {
public:
CountersImpl();
~CountersImpl();
void inc(const QRAttributes& qrattrs, const Message& response);
isc::data::ConstElementPtr getStatistics() const;
void registerStatisticsValidator(Counters::validator_type validator);
Counters::ItemTreeType get() const;
private:
// counter for query/response
Counter server_qr_counter_;
......@@ -65,8 +79,8 @@ private:
Counter socket_counter_;
// set of counters for zones
CounterDictionary zone_qr_counters_;
// validator
Counters::validator_type validator_;
void incRequest(const QRAttributes& qrattrs, const Message& response);
void incResponse(const QRAttributes& qrattrs, const Message& response);
};
CountersImpl::CountersImpl() :
......@@ -74,15 +88,16 @@ CountersImpl::CountersImpl() :
// size of server_socket_counter_: SOCKET_COUNTER_TYPES
server_qr_counter_(QR_COUNTER_TYPES),
socket_counter_(SOCKET_COUNTER_TYPES),
zone_qr_counters_(QR_COUNTER_TYPES),
validator_()
zone_qr_counters_(QR_COUNTER_TYPES)
{}
CountersImpl::~CountersImpl()
{}
void
CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) {
CountersImpl::incRequest(const QRAttributes& qrattrs,
const Message& response)
{
// protocols carrying request
if (qrattrs.req_ip_version_ == AF_INET) {
server_qr_counter_.inc(QR_REQUEST_IPV4);
......@@ -104,7 +119,8 @@ CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) {
}
if (qrattrs.req_is_badsig_) {
server_qr_counter_.inc(QR_REQUEST_BADSIG);
// If signature validation is failed, no other attributes are reliable
// If signature validation is failed, no other query attributes are
// reliable. Skip processing of the rest of query counters.
return;
}
......@@ -148,118 +164,104 @@ CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) {
server_qr_counter_.inc(qtype_type);
// OPCODE
server_qr_counter_.inc(QROpCodeToQRCounterType[qrattrs.req_opcode_]);
}
// response
if (qrattrs.answer_sent_) {
// responded
server_qr_counter_.inc(QR_RESPONSE);
// response truncated
if (qrattrs.res_is_truncated_) {
server_qr_counter_.inc(QR_RESPONSE_TRUNCATED);
}
// response EDNS
ConstEDNSPtr response_edns = response.getEDNS();
if (response_edns != NULL && response_edns->getVersion() == 0) {
server_qr_counter_.inc(QR_RESPONSE_EDNS0);
}
void
CountersImpl::incResponse(const QRAttributes& qrattrs,
const Message& response)
{
// responded
server_qr_counter_.inc(QR_RESPONSE);
// response TSIG
if (qrattrs.req_is_tsig_) {
// assume response is TSIG signed if request is TSIG signed
server_qr_counter_.inc(QR_RESPONSE_TSIG);
}
// response truncated
if (qrattrs.res_is_truncated_) {
server_qr_counter_.inc(QR_RESPONSE_TRUNCATED);
}
// response SIG(0) is currently not implemented
// response EDNS
ConstEDNSPtr response_edns = response.getEDNS();
if (response_edns != NULL && response_edns->getVersion() == 0) {
server_qr_counter_.inc(QR_RESPONSE_EDNS0);
}
// RCODE
const unsigned int rcode = response.getRcode().getCode();
unsigned int rcode_type = QR_RCODE_OTHER;
if (rcode < 23) {
// rcode 0..22
rcode_type = QRRCodeToQRCounterType[rcode];
} else {
// opcode larger than 22 is reserved or unassigned
rcode_type = QR_RCODE_OTHER;
}
server_qr_counter_.inc(rcode_type);
// response TSIG
if (qrattrs.req_is_tsig_) {
// assume response is TSIG signed if request is TSIG signed
server_qr_counter_.inc(QR_RESPONSE_TSIG);
}
// compound attributes
const unsigned int answer_rrs =
response.getRRCount(Message::SECTION_ANSWER);
const bool is_aa_set = response.getHeaderFlag(Message::HEADERFLAG_AA);
// response SIG(0) is currently not implemented
// RCODE
const unsigned int rcode = response.getRcode().getCode();
unsigned int rcode_type = QR_RCODE_OTHER;
if (rcode < 23) {
// rcode 0..22
rcode_type = QRRCodeToQRCounterType[rcode];
} else {
// opcode larger than 22 is reserved or unassigned
rcode_type = QR_RCODE_OTHER;
}
server_qr_counter_.inc(rcode_type);
// compound attributes
const unsigned int answer_rrs =
response.getRRCount(Message::SECTION_ANSWER);
const bool is_aa_set = response.getHeaderFlag(Message::HEADERFLAG_AA);
if (is_aa_set) {
// QryAuthAns
server_qr_counter_.inc(QR_QRYAUTHANS);
} else {
// QryNoAuthAns
server_qr_counter_.inc(QR_QRYNOAUTHANS);
}
if (is_aa_set) {
// QryAuthAns
server_qr_counter_.inc(QR_QRYAUTHANS);
if (rcode == Rcode::NOERROR_CODE) {
if (answer_rrs > 0) {
// QrySuccess
server_qr_counter_.inc(QR_QRYSUCCESS);
} else {
// QryNoAuthAns
server_qr_counter_.inc(QR_QRYNOAUTHANS);
}
if (rcode == Rcode::NOERROR_CODE) {
if (answer_rrs > 0) {
// QrySuccess
server_qr_counter_.inc(QR_QRYSUCCESS);
if (is_aa_set) {
// QryNxrrset
server_qr_counter_.inc(QR_QRYNXRRSET);
} else {
if (is_aa_set) {
// QryNxrrset
server_qr_counter_.inc(QR_QRYNXRRSET);
} else {
// QryReferral
server_qr_counter_.inc(QR_QRYREFERRAL);
}
// QryReferral
server_qr_counter_.inc(QR_QRYREFERRAL);
}
} else if (rcode == Rcode::REFUSED_CODE) {
// AuthRej
server_qr_counter_.inc(QR_QRYREJECT);
}
} else if (rcode == Rcode::REFUSED_CODE) {
// AuthRej
server_qr_counter_.inc(QR_QRYREJECT);
}
}
isc::data::ConstElementPtr
CountersImpl::getStatistics() const {
std::stringstream statistics_string;
statistics_string << "{ \"queries.udp\": "
<< server_qr_counter_.get(QR_REQUEST_UDP)
<< ", \"queries.tcp\": "
<< server_qr_counter_.get(QR_REQUEST_TCP);
// Insert non 0 Opcode counters.
for (int i = QR_OPCODE_QUERY; i <= QR_OPCODE_OTHER; ++i) {
const Counter::Type counter = server_qr_counter_.get(i);
if (counter != 0) {
statistics_string << ", \"" << QRCounterItemName[i] << "\": "
<< counter;
}
}
// Insert non 0 Rcode counters.
for (int i = QR_RCODE_NOERROR; i <= QR_RCODE_OTHER; ++i) {
const Counter::Type counter = server_qr_counter_.get(i);
if (counter != 0) {
statistics_string << ", \"" << QRCounterItemName[i] << "\": "
<< counter;
}
}
statistics_string << "}";
isc::data::ConstElementPtr statistics_element =
isc::data::Element::fromJSON(statistics_string);
// validate the statistics data before send
if (validator_) {
if (!validator_(statistics_element)) {
LOG_ERROR(auth_logger, AUTH_INVALID_STATISTICS_DATA);
return (isc::data::ElementPtr());
}
void
CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) {
// increment request counters
incRequest(qrattrs, response);
if (qrattrs.answer_sent_) {
// increment response counters if answer was sent
incResponse(qrattrs, response);
}
return (statistics_element);
}
void
CountersImpl::registerStatisticsValidator
(Counters::validator_type validator)
{
validator_ = validator;
Counters::ItemTreeType
CountersImpl::get() const {
using namespace isc::data;
Counters::ItemTreeType item_tree = Element::createMap();
Counters::ItemTreeType zones = Element::createMap();
item_tree->set("zones", zones);
Counters::ItemTreeType server = Element::createMap();
fillNodes(server_qr_counter_, QRCounterItemName, QR_COUNTER_TYPES,
server);
zones->set("_SERVER_", server);
return (item_tree);
}
Counters::Counters() : impl_(new CountersImpl())
......@@ -272,16 +274,9 @@ Counters::inc(const QRAttributes& qrattrs, const Message& response) {
impl_->inc(qrattrs, response);
}
isc::data::ConstElementPtr
Counters::getStatistics() const {
return (impl_->getStatistics());
}
void
Counters::registerStatisticsValidator
(Counters::validator_type validator) const
{
return (impl_->registerStatisticsValidator(validator));
Counters::ItemTreeType
Counters::get() const {
return (impl_->get());
}
} // namespace statistics
......
......@@ -204,6 +204,19 @@ class Counters {
private:
boost::scoped_ptr<CountersImpl> impl_;
public:
/// \brief A type of statistics item tree in isc::data::MapElement.
/// {
/// zone_name => {
/// item_name => item_value,
/// item_name => item_value, ...
/// },
/// ...
/// }
/// item_name is a string seperated by '.'.
/// item_value is an integer.
///
typedef isc::data::ElementPtr ItemTreeType;
/// The constructor.
///
/// This constructor is mostly exception free. But it may still throw
......@@ -218,42 +231,26 @@ public:
/// \brief Increment counters according to the parameters.
///
/// This constructor is mostly exception free. But it may still throw
/// a standard exception if memory allocation fails inside the method.
///
/// \param qrattrs Query/Response attributes.
/// \param response DNS response message.
///
/// \throw None
/// \throw std::bad_alloc Internal resource allocation fails
///
void inc(const QRAttributes& qrattrs, const isc::dns::Message& response);
/// \brief Answers statistics counters to statistics module.
/// \brief Get statistics counters.
///
/// This method is mostly exception free (error conditions are
/// represented via the return value). But it may still throw
/// This method is mostly exception free. But it may still throw
/// a standard exception if memory allocation fails inside the method.
///
/// \return statistics data
///
isc::data::ConstElementPtr getStatistics() const;
/// \brief A type of validation function for the specification in
/// isc::config::ModuleSpec.
///
/// This type might be useful for not only statistics
/// specificatoin but also for config_data specification and for
/// commnad.
///
typedef boost::function<bool(const isc::data::ConstElementPtr&)>
validator_type;
/// \brief Register a function type of the statistics validation
/// function for Counters.
///
/// This method never throws an exception.
///
/// \param validator A function type of the validation of
/// statistics specification.
/// \throw std::bad_alloc Internal resource allocation fails
///
void registerStatisticsValidator(Counters::validator_type validator) const;
ItemTreeType get() const;
};
} // namespace statistics
......
......@@ -252,14 +252,9 @@ void
expectCounterItem(ConstElementPtr stats,
const std::string& item, const int expected) {
ConstElementPtr value(Element::create(0));
if (item == "queries.udp" || item == "queries.tcp" || expected != 0) {
ASSERT_TRUE(stats->find(item, value)) << " Item: " << item;
value = stats->find(item);
EXPECT_EQ(expected, value->intValue()) << " Item: " << item;
} else {
ASSERT_FALSE(stats->find(item, value)) << " Item: " << item <<
std::endl << " Value: " << value->intValue();
}
ASSERT_TRUE(stats->find(item, value)) << " Item: " << item;
value = stats->find(item);
EXPECT_EQ(expected, value->intValue()) << " Item: " << item;
}
// We did not configure any client lists. Therefore it should be REFUSED
......@@ -446,8 +441,7 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) {
// TSIG should have failed, and so the per opcode counter shouldn't be
// incremented.
ConstElementPtr stats = server.getStatistics();
expectCounterItem(stats, "opcode.normal", 0);
expectCounterItem(stats, "opcode.other", 0);
expectCounterItem(stats->get("zones")->get("_SERVER_"), "opcode.other", 0);
checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1);
}
......@@ -1076,9 +1070,10 @@ TEST_F(AuthSrvTest,
// Submit UDP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterUDPNormal) {
// The counters should be initialized to 0.
ConstElementPtr stats_init = server.getStatistics();
expectCounterItem(stats_init, "queries.udp", 0);
expectCounterItem(stats_init, "queries.tcp", 0);
ConstElementPtr stats_init = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_init, "request.udp", 0);
expectCounterItem(stats_init, "request.tcp", 0);
expectCounterItem(stats_init, "opcode.query", 0);
expectCounterItem(stats_init, "rcode.refused", 0);
// Create UDP message and process.
......@@ -1092,9 +1087,10 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
// request.tcp, opcode.query, qtype.ns, rcode.refused, response
// and these counters should not be incremented:
// request.tcp
ConstElementPtr stats_after = server.getStatistics();
expectCounterItem(stats_after, "queries.udp", 1);
expectCounterItem(stats_after, "queries.tcp", 0);
ConstElementPtr stats_after = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_after, "request.udp", 1);
expectCounterItem(stats_after, "request.tcp", 0);
expectCounterItem(stats_after, "opcode.query", 1);
expectCounterItem(stats_after, "rcode.refused", 1);
}
......@@ -1102,9 +1098,10 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) {
// Submit TCP normal query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPNormal) {
// The counters should be initialized to 0.
ConstElementPtr stats_init = server.getStatistics();
expectCounterItem(stats_init, "queries.udp", 0);
expectCounterItem(stats_init, "queries.tcp", 0);
ConstElementPtr stats_init = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_init, "request.udp", 0);
expectCounterItem(stats_init, "request.tcp", 0);
expectCounterItem(stats_init, "opcode.query", 0);
expectCounterItem(stats_init, "rcode.refused", 0);
// Create TCP message and process.
......@@ -1118,9 +1115,10 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
// request.tcp, opcode.query, qtype.ns, rcode.refused, response
// and these counters should not be incremented:
// request.udp
ConstElementPtr stats_after = server.getStatistics();
expectCounterItem(stats_after, "queries.udp", 0);
expectCounterItem(stats_after, "queries.tcp", 1);
ConstElementPtr stats_after = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_after, "request.udp", 0);
expectCounterItem(stats_after, "request.tcp", 1);
expectCounterItem(stats_after, "opcode.query", 1);
expectCounterItem(stats_after, "rcode.refused", 1);
}
......@@ -1128,9 +1126,10 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) {
// Submit TCP AXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
// The counters should be initialized to 0.
ConstElementPtr stats_init = server.getStatistics();
expectCounterItem(stats_init, "queries.udp", 0);
expectCounterItem(stats_init, "queries.tcp", 0);
ConstElementPtr stats_init = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_init, "request.udp", 0);
expectCounterItem(stats_init, "request.tcp", 0);
expectCounterItem(stats_init, "opcode.query", 0);
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("example.com"), RRClass::IN(), RRType::AXFR());
......@@ -1145,18 +1144,20 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) {
// request.tcp, opcode.query, qtype.axfr
// and these counters should not be incremented:
// request.udp, response
ConstElementPtr stats_after = server.getStatistics();
expectCounterItem(stats_after, "queries.udp", 0);
expectCounterItem(stats_after, "queries.tcp", 1);
ConstElementPtr stats_after = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_after, "request.udp", 0);
expectCounterItem(stats_after, "request.tcp", 1);
expectCounterItem(stats_after, "opcode.query", 1);
}
// Submit TCP IXFR query and check query counter
TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
// The counters should be initialized to 0.
ConstElementPtr stats_init = server.getStatistics();
expectCounterItem(stats_init, "queries.udp", 0);
expectCounterItem(stats_init, "queries.tcp", 0);
ConstElementPtr stats_init = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_init, "request.udp", 0);
expectCounterItem(stats_init, "request.tcp", 0);
expectCounterItem(stats_init, "opcode.query", 0);
UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
Name("example.com"), RRClass::IN(), RRType::IXFR());
......@@ -1171,9 +1172,10 @@ TEST_F(AuthSrvTest, queryCounterTCPIXFR) {
// request.tcp, opcode.query, qtype.ixfr
// and these counters should not be incremented:
// request.udp, response
ConstElementPtr stats_after = server.getStatistics();
expectCounterItem(stats_after, "queries.udp", 0);
expectCounterItem(stats_after, "queries.tcp", 1);
ConstElementPtr stats_after = server.getStatistics()->
get("zones")->get("_SERVER_");
expectCounterItem(stats_after, "request.udp", 0);
expectCounterItem(stats_after, "request.tcp", 1);
expectCounterItem(stats_after, "opcode.query", 1);
}
......@@ -1182,7 +1184,8 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) {
// The counter should be initialized to 0.
for (int i = 0; i < 6; ++i) {
// The counter should be initialized to 0.
expectCounterItem(server.getStatistics(),
expectCounterItem(server.getStatistics()->
get("zones")->get("_SERVER_"),
QRCounterItemName[QROpCodeToQRCounterType[i]], 0);
// For each possible opcode, create a request message and send it
......@@ -1201,7 +1204,8 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) {