From: Yoshitaka Aharen Date: Mon, 1 Oct 2012 12:02:38 +0000 (+0900) Subject: [2155] modify Counters::inc() to update new counters X-Git-Tag: trac2487_base~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72941a64efbe4843657cbb05f8945f7c6dc0e3a0;p=thirdparty%2Fkea.git [2155] modify Counters::inc() to update new counters Counters::inc() now takes DNS message and query/response attributes. It increments the counters related to the message. Some tests have been mofdified or removedue to the change of the interface. --- diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in index a471b7a87f..30a455d8e0 100644 --- a/src/bin/auth/auth.spec.pre.in +++ b/src/bin/auth/auth.spec.pre.in @@ -145,7 +145,7 @@ "item_type": "integer", "item_optional": false, "item_default": 0, - "item_title": "Queries TCP ", + "item_title": "Queries TCP", "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially" }, { @@ -180,14 +180,6 @@ "item_title": "Received status requests", "item_description": "The number of total request counts whose opcode is status" }, - { - "item_name": "opcode.reserved3", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 3", - "item_description": "The number of total request counts whose opcode is 3 (reserved)" - }, { "item_name": "opcode.notify", "item_type": "integer", @@ -205,84 +197,12 @@ "item_description": "The number of total request counts whose opcode is update" }, { - "item_name": "opcode.reserved6", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 6", - "item_description": "The number of total request counts whose opcode is 6 (reserved)" - }, - { - "item_name": "opcode.reserved7", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 7", - "item_description": "The number of total request counts whose opcode is 7 (reserved)" - }, - { - "item_name": "opcode.reserved8", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 8", - "item_description": "The number of total request counts whose opcode is 8 (reserved)" - }, - { - "item_name": "opcode.reserved9", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 9", - "item_description": "The number of total request counts whose opcode is 9 (reserved)" - }, - { - "item_name": "opcode.reserved10", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 10", - "item_description": "The number of total request counts whose opcode is 10 (reserved)" - }, - { - "item_name": "opcode.reserved11", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 11", - "item_description": "The number of total request counts whose opcode is 11 (reserved)" - }, - { - "item_name": "opcode.reserved12", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 12", - "item_description": "The number of total request counts whose opcode is 12 (reserved)" - }, - { - "item_name": "opcode.reserved13", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 13", - "item_description": "The number of total request counts whose opcode is 13 (reserved)" - }, - { - "item_name": "opcode.reserved14", - "item_type": "integer", - "item_optional": true, - "item_default": 0, - "item_title": "Received requests opcode 14", - "item_description": "The number of total request counts whose opcode is 14 (reserved)" - }, - { - "item_name": "opcode.reserved15", + "item_name": "opcode.other", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Received requests opcode 15", - "item_description": "The number of total request counts whose opcode is 15 (reserved)" + "item_title": "Received requests opcode other", + "item_description": "The number of total request counts whose opcode is other (not well-known)" }, { "item_name": "rcode.noerror", @@ -373,52 +293,68 @@ "item_description": "The number of total responses with rcode 10 (NOTZONE)" }, { - "item_name": "rcode.reserved11", + "item_name": "rcode.badsigvers", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent response with rcode 11", - "item_description": "The number of total responses with rcode 11 (reserved)" + "item_title": "Sent 'EDNS version not implemented' response", + "item_description": "The number of total responses with rcode 16 (BADVERS)" }, { - "item_name": "rcode.reserved12", + "item_name": "rcode.badkey", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent response with rcode 12", - "item_description": "The number of total responses with rcode 12 (reserved)" + "item_title": "Sent 'Key not recognized' response", + "item_description": "The number of total responses with rcode 17 (BADKEY)" }, { - "item_name": "rcode.reserved13", + "item_name": "rcode.badtime", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent response with rcode 13", - "item_description": "The number of total responses with rcode 13 (reserved)" + "item_title": "Sent 'Signature out of time window' response", + "item_description": "The number of total responses with rcode 18 (BADTIME)" }, { - "item_name": "rcode.reserved14", + "item_name": "rcode.badmode", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent response with rcode 14", - "item_description": "The number of total responses with rcode 14 (reserved)" + "item_title": "Sent 'Bad TKEY Mode' response", + "item_description": "The number of total responses with rcode 19 (BADMODE)" }, { - "item_name": "rcode.reserved15", + "item_name": "rcode.badname", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent response with rcode 15", - "item_description": "The number of total responses with rcode 15 (reserved)" + "item_title": "Sent 'Duplicate key name' response", + "item_description": "The number of total responses with rcode 20 (BADNAME)" }, { - "item_name": "rcode.badvers", + "item_name": "rcode.badalg", "item_type": "integer", "item_optional": true, "item_default": 0, - "item_title": "Sent 'EDNS version not implemented' response", - "item_description": "The number of total responses with rcode 16 (BADVERS)" + "item_title": "Sent 'Algorithm not supported' response", + "item_description": "The number of total responses with rcode 21 (BADALG)" + }, + { + "item_name": "rcode.badtrunc", + "item_type": "integer", + "item_optional": true, + "item_default": 0, + "item_title": "Sent 'Bad Truncation' response", + "item_description": "The number of total responses with rcode 22 (BADTRUNC)" + }, + { + "item_name": "rcode.other", + "item_type": "integer", + "item_optional": true, + "item_default": 0, + "item_title": "Sent responses with rcode other", + "item_description": "The number of total responses with rcode other (not well-known)" } ] } diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc index 8005efe6e2..a297301806 100644 --- a/src/bin/auth/auth_srv.cc +++ b/src/bin/auth/auth_srv.cc @@ -296,27 +296,29 @@ public: /// \brief Resume the server /// - /// This is a wrapper call for DNSServer::resume(done), if 'done' is true, - /// the Rcode set in the given Message is counted in the statistics - /// counter. + /// This is a wrapper call for DNSServer::resume(done). Query/Response + /// statistics counters are incremented in this method. /// /// This method is expected to be called by processMessage() /// /// \param server The DNSServer as passed to processMessage() /// \param message The response as constructed by processMessage() - /// \param done If true, the Rcode from the given message is counted, - /// this value is then passed to server->resume(bool) + /// \param stats_attrs Query/response attributes for statistics which is + /// not in \p messsage. + /// Note: This parameter is modified inside this method + /// to store whether the answer has been sent and + /// the response is truncated. + /// \param done If true, it indicates there is a response. + /// this value will be passed to server->resume(bool) void resumeServer(isc::asiodns::DNSServer* server, isc::dns::Message& message, - bool done); + statistics::QRAttributes& stats_attrs, + const bool done); private: bool xfrout_connected_; AbstractXfroutClient& xfrout_client_; - /// Increment query counter - void incCounter(const int protocol); - // validateStatistics bool validateStatistics(isc::data::ConstElementPtr data) const; @@ -500,6 +502,12 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message, OutputBuffer& buffer, DNSServer* server) { InputBuffer request_buffer(io_message.getData(), io_message.getDataSize()); + statistics::QRAttributes stats_attrs; + + // statistics: check transport carrying the message (IP, transport) + stats_attrs.setQueryIPVersion(io_message.getRemoteEndpoint().getFamily()); + stats_attrs.setQueryTransportProtocol( + io_message.getRemoteEndpoint().getProtocol()); // First, check the header part. If we fail even for the base header, // just drop the message. @@ -509,13 +517,13 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message, // Ignore all responses. if (message.getHeaderFlag(Message::HEADERFLAG_QR)) { LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_RECEIVED); - impl_->resumeServer(server, message, false); + impl_->resumeServer(server, message, stats_attrs, false); return; } } catch (const Exception& ex) { LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_HEADER_PARSE_FAIL) .arg(ex.what()); - impl_->resumeServer(server, message, false); + impl_->resumeServer(server, message, stats_attrs, false); return; } @@ -526,13 +534,13 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message, LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PROTOCOL_ERROR) .arg(error.getRcode().toText()).arg(error.what()); makeErrorMessage(impl_->renderer_, message, buffer, error.getRcode()); - impl_->resumeServer(server, message, true); + impl_->resumeServer(server, message, stats_attrs, true); return; } catch (const Exception& ex) { LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_PACKET_PARSE_ERROR) .arg(ex.what()); makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL()); - impl_->resumeServer(server, message, true); + impl_->resumeServer(server, message, stats_attrs, true); return; } // other exceptions will be handled at a higher layer. @@ -555,21 +563,35 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message, **impl_->keyring_)); tsig_error = tsig_context->verify(tsig_record, io_message.getData(), io_message.getDataSize()); + // statistics: check TSIG attributes + // SIG(0) is currently not implemented in Auth + stats_attrs.setQuerySig(true, false, + tsig_error == TSIGError::NOERROR()); } if (tsig_error != TSIGError::NOERROR()) { makeErrorMessage(impl_->renderer_, message, buffer, tsig_error.toRcode(), tsig_context); - impl_->resumeServer(server, message, true); + impl_->resumeServer(server, message, stats_attrs, true); return; } const Opcode opcode = message.getOpcode(); bool send_answer = true; try { - // update per opcode statistics counter. This can only be reliable - // after TSIG check succeeds. - impl_->counters_.inc(message.getOpcode()); + // statistics: check EDNS + // note: This can only be reliable after TSIG check succeeds. + { + ConstEDNSPtr edns = message.getEDNS(); + if (edns != NULL) { + stats_attrs.setQueryEDNS(true, edns->getVersion() == 0); + stats_attrs.setQueryDO(edns->getDNSSECAwareness()); + } + } + + // statistics: check OpCode + // note: This can only be reliable after TSIG check succeeds. + stats_attrs.setQueryOpCode(opcode.getCode()); if (opcode == Opcode::NOTIFY()) { send_answer = impl_->processNotify(io_message, message, buffer, @@ -611,7 +633,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message, LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RESPONSE_FAILURE_UNKNOWN); makeErrorMessage(impl_->renderer_, message, buffer, Rcode::SERVFAIL()); } - impl_->resumeServer(server, message, send_answer); + impl_->resumeServer(server, message, stats_attrs, send_answer); } bool @@ -628,9 +650,6 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message, message.setHeaderFlag(Message::HEADERFLAG_AA); message.setRcode(Rcode::NOERROR()); - // Increment query counter. - incCounter(io_message.getSocket().getProtocol()); - if (remote_edns) { EDNSPtr local_edns = EDNSPtr(new EDNS()); local_edns->setDNSSECAwareness(dnssec_ok); @@ -675,9 +694,6 @@ AuthSrvImpl::processXfrQuery(const IOMessage& io_message, Message& message, OutputBuffer& buffer, auto_ptr tsig_context) { - // Increment query counter. - incCounter(io_message.getSocket().getProtocol()); - if (io_message.getSocket().getProtocol() == IPPROTO_UDP) { LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_AXFR_UDP); makeErrorMessage(renderer_, message, buffer, Rcode::FORMERR(), @@ -809,19 +825,6 @@ AuthSrvImpl::processUpdate(const IOMessage& io_message) { return (false); } -void -AuthSrvImpl::incCounter(const int protocol) { - // Increment query counter. - if (protocol == IPPROTO_UDP) { - counters_.inc(Counters::SERVER_UDP_QUERY); - } else if (protocol == IPPROTO_TCP) { - counters_.inc(Counters::SERVER_TCP_QUERY); - } else { - // unknown protocol - isc_throw(Unexpected, "Unknown protocol: " << protocol); - } -} - void AuthSrvImpl::registerStatisticsValidator() { counters_.registerStatisticsValidator( @@ -839,10 +842,15 @@ AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const { } void -AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) { +AuthSrvImpl::resumeServer(DNSServer* server, Message& message, + statistics::QRAttributes& stats_attrs, + const bool done) { if (done) { - counters_.inc(message.getRcode()); + stats_attrs.answerWasSent(); + // isTruncated from MessageRenderer + stats_attrs.setResponseTruncated(renderer_.isTruncated()); } + counters_.inc(stats_attrs, message); server->resume(done); } @@ -865,21 +873,6 @@ ConstElementPtr AuthSrv::getStatistics() const { return (impl_->counters_.getStatistics()); } -uint64_t -AuthSrv::getCounter(const Counters::ServerCounterType type) const { - return (impl_->counters_.getCounter(type)); -} - -uint64_t -AuthSrv::getCounter(const Opcode opcode) const { - return (impl_->counters_.getCounter(opcode)); -} - -uint64_t -AuthSrv::getCounter(const Rcode rcode) const { - return (impl_->counters_.getCounter(rcode)); -} - const AddressList& AuthSrv::getListenAddresses() const { return (impl_->listen_addresses_); diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h index 1f996a7f13..a3d84023b0 100644 --- a/src/bin/auth/auth_srv.h +++ b/src/bin/auth/auth_srv.h @@ -210,52 +210,6 @@ public: /// \return JSON format statistics data. isc::data::ConstElementPtr getStatistics() const; - /// \brief Get the value of counter in the Counters. - /// - /// This function calls Counters::getStatistics() and - /// returns its return value. - /// - /// This function never throws an exception as far as - /// Counters::getStatistics() doesn't throw. - /// - /// Note: Currently this function is for testing purpose only. - /// - /// \param type Type of a counter to get the value of - /// - /// \return the value of the counter. - - uint64_t getCounter( - const isc::auth::statistics::Counters::ServerCounterType type) - const; - - /// \brief Get the value of per Opcode counter in the Auth Counters. - /// - /// This function calls Counters::getCounter(isc::dns::Opcode) and - /// returns its return value. - /// - /// \note This is a tentative interface as an attempt of experimentally - /// supporting more statistics counters. This should eventually be more - /// generalized. In any case, this method is mainly for testing. - /// - /// \throw None - /// \param opcode The opcode of the counter to get the value of - /// \return the value of the counter. - uint64_t getCounter(const isc::dns::Opcode opcode) const; - - /// \brief Get the value of per Rcode counter in the Auth Counters. - /// - /// This function calls Counters::getCounter(isc::dns::Rcode) and - /// returns its return value. - /// - /// \note This is a tentative interface as an attempt of experimentally - /// supporting more statistics counters. This should eventually be more - /// generalized. In any case, this method is mainly for testing. - /// - /// \throw None - /// \param rcode The rcode of the counter to get the value of - /// \return the value of the counter. - uint64_t getCounter(const isc::dns::Rcode rcode) const; - /** * \brief Set and get the addresses we listen on. */ diff --git a/src/bin/auth/statistics.cc b/src/bin/auth/statistics.cc index 6b68ab093a..e1b12a411e 100644 --- a/src/bin/auth/statistics.cc +++ b/src/bin/auth/statistics.cc @@ -13,9 +13,11 @@ // PERFORMANCE OF THIS SOFTWARE. #include +#include #include #include +#include #include #include @@ -32,6 +34,12 @@ #include +#include +#include +#include +#include +#include + using namespace isc::dns; using namespace isc::auth; using namespace isc::statistics; @@ -47,90 +55,189 @@ class CountersImpl : boost::noncopyable { public: CountersImpl(); ~CountersImpl(); - void inc(const Counters::ServerCounterType type); - void inc(const Opcode opcode) { - opcode_counter_.inc(opcode.getCode()); - } - void inc(const Rcode rcode) { - rcode_counter_.inc(rcode.getCode()); - } - void inc(const std::string& zone, const Counters::PerZoneCounterType type); + void inc(const QRAttributes& qrattrs, const Message& response); isc::data::ConstElementPtr getStatistics() const; - void registerStatisticsValidator (Counters::validator_type validator); - // Currently for testing purpose only - uint64_t getCounter(const Counters::ServerCounterType type) const; - uint64_t getCounter(const Opcode opcode) const { - return (opcode_counter_.get(opcode.getCode())); - } - uint64_t getCounter(const Rcode rcode) const { - return (rcode_counter_.get(rcode.getCode())); - } + void registerStatisticsValidator(Counters::validator_type validator); private: - Counter server_counter_; - Counter opcode_counter_; - static const size_t NUM_OPCODES = 16; - Counter rcode_counter_; - static const size_t NUM_RCODES = 17; - CounterDictionary per_zone_counter_; + // counter for query/response + Counter server_qr_counter_; + // counter for socket + Counter socket_counter_; + // set of counters for zones + CounterDictionary zone_qr_counters_; + // validator Counters::validator_type validator_; }; CountersImpl::CountersImpl() : - // initialize counter - // size of server_counter_: Counters::SERVER_COUNTER_TYPES - // size of per_zone_counter_: Counters::PER_ZONE_COUNTER_TYPES - server_counter_(Counters::SERVER_COUNTER_TYPES), - opcode_counter_(NUM_OPCODES), rcode_counter_(NUM_RCODES), - per_zone_counter_(Counters::PER_ZONE_COUNTER_TYPES) -{ - per_zone_counter_.addElement("_SERVER_"); -} + // size of server_qr_counter_, zone_qr_counters_: QR_COUNTER_TYPES + // 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_() +{} CountersImpl::~CountersImpl() {} void -CountersImpl::inc(const Counters::ServerCounterType type) { - server_counter_.inc(type); -} +CountersImpl::inc(const QRAttributes& qrattrs, const Message& response) { + // protocols carrying request + if (qrattrs.req_ip_version_ == AF_INET) { + server_qr_counter_.inc(QR_REQUEST_IPV4); + } else if (qrattrs.req_ip_version_ == AF_INET6) { + server_qr_counter_.inc(QR_REQUEST_IPV6); + } + if (qrattrs.req_transport_protocol_ == IPPROTO_UDP) { + server_qr_counter_.inc(QR_REQUEST_UDP); + } else if (qrattrs.req_transport_protocol_ == IPPROTO_TCP) { + server_qr_counter_.inc(QR_REQUEST_TCP); + } -void -CountersImpl::inc(const std::string& zone, - const Counters::PerZoneCounterType type) -{ - per_zone_counter_[zone].inc(type); + // query TSIG + if (qrattrs.req_is_tsig_) { + server_qr_counter_.inc(QR_REQUEST_TSIG); + } + if (qrattrs.req_is_sig0_) { + server_qr_counter_.inc(QR_REQUEST_SIG0); + } + if (qrattrs.req_is_badsig_) { + server_qr_counter_.inc(QR_REQUEST_BADSIG); + // If signature validation is failed, no other attributes are reliable + return; + } + + // query EDNS + if (qrattrs.req_is_edns_0_) { + server_qr_counter_.inc(QR_REQUEST_EDNS0); + } + if (qrattrs.req_is_edns_badver_) { + server_qr_counter_.inc(QR_REQUEST_BADEDNSVER); + } + + // query DNSSEC + if (qrattrs.req_is_dnssec_ok_) { + server_qr_counter_.inc(QR_REQUEST_DNSSEC_OK); + } + + // QTYPE + unsigned int qtype_type = QR_QTYPE_OTHER; + const QuestionIterator qiter = response.beginQuestion(); + if (qiter != response.endQuestion()) { + // get the first and only question section + const QuestionPtr qptr = *qiter; + if (qptr != NULL) { + // get the qtype code + const unsigned int qtype = qptr->getType().getCode(); + if (qtype < 258) { + // qtype 0..257 + qtype_type = QRQTypeToQRCounterType[qtype]; + } else if (qtype < 32768) { + // qtype 258..32767 + qtype_type = QR_QTYPE_OTHER; + } else if (qtype < 32770) { + // qtype 32768..32769 + qtype_type = QR_QTYPE_TA + (qtype - 32768); + } else { + // qtype 32770..65535 + qtype_type = QR_QTYPE_OTHER; + } + } + } + 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); + } + + // 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 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 (rcode == Rcode::NOERROR_CODE) { + if (answer_rrs > 0) { + // QrySuccess + server_qr_counter_.inc(QR_QRYSUCCESS); + } else { + if (is_aa_set) { + // QryNxrrset + server_qr_counter_.inc(QR_QRYNXRRSET); + } else { + // QryReferral + server_qr_counter_.inc(QR_QRYREFERRAL); + } + } + } 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_counter_.get(Counters::SERVER_UDP_QUERY) + << server_qr_counter_.get(QR_REQUEST_UDP) << ", \"queries.tcp\": " - << server_counter_.get(Counters::SERVER_TCP_QUERY); + << server_qr_counter_.get(QR_REQUEST_TCP); // Insert non 0 Opcode counters. - for (int i = 0; i < NUM_OPCODES; ++i) { - const Counter::Type counter = opcode_counter_.get(i); + for (int i = QR_OPCODE_QUERY; i <= QR_OPCODE_OTHER; ++i) { + const Counter::Type counter = server_qr_counter_.get(i); if (counter != 0) { - // The counter item name should be derived lower-cased textual - // representation of the code. - std::string opcode_txt = Opcode(i).toText(); - std::transform(opcode_txt.begin(), opcode_txt.end(), - opcode_txt.begin(), ::tolower); - statistics_string << ", \"opcode." << opcode_txt << "\": " + statistics_string << ", \"" << QRCounterItemName[i] << "\": " << counter; } } // Insert non 0 Rcode counters. - for (int i = 0; i < NUM_RCODES; ++i) { - const Counter::Type counter = rcode_counter_.get(i); + for (int i = QR_RCODE_NOERROR; i <= QR_RCODE_OTHER; ++i) { + const Counter::Type counter = server_qr_counter_.get(i); if (counter != 0) { - // The counter item name should be derived lower-cased textual - // representation of the code. - std::string rcode_txt = Rcode(i).toText(); - std::transform(rcode_txt.begin(), rcode_txt.end(), - rcode_txt.begin(), ::tolower); - statistics_string << ", \"rcode." << rcode_txt << "\": " + statistics_string << ", \"" << QRCounterItemName[i] << "\": " << counter; } } @@ -155,30 +262,14 @@ CountersImpl::registerStatisticsValidator validator_ = validator; } -// Currently for testing purpose only -uint64_t -CountersImpl::getCounter(const Counters::ServerCounterType type) const { - return (server_counter_.get(type)); -} - Counters::Counters() : impl_(new CountersImpl()) {} Counters::~Counters() {} void -Counters::inc(const Counters::ServerCounterType type) { - impl_->inc(type); -} - -void -Counters::inc(const Opcode opcode) { - impl_->inc(opcode); -} - -void -Counters::inc(const Rcode rcode) { - impl_->inc(rcode); +Counters::inc(const QRAttributes& qrattrs, const Message& response) { + impl_->inc(qrattrs, response); } isc::data::ConstElementPtr @@ -186,21 +277,6 @@ Counters::getStatistics() const { return (impl_->getStatistics()); } -uint64_t -Counters::getCounter(const Counters::ServerCounterType type) const { - return (impl_->getCounter(type)); -} - -uint64_t -Counters::getCounter(const Opcode opcode) const { - return (impl_->getCounter(opcode)); -} - -uint64_t -Counters::getCounter(const Rcode rcode) const { - return (impl_->getCounter(rcode)); -} - void Counters::registerStatisticsValidator (Counters::validator_type validator) const diff --git a/src/bin/auth/statistics.h b/src/bin/auth/statistics.h index d0ddd5f4e2..f3efa7da2e 100644 --- a/src/bin/auth/statistics.h +++ b/src/bin/auth/statistics.h @@ -15,11 +15,13 @@ #ifndef __STATISTICS_H #define __STATISTICS_H 1 -#include -#include #include #include +#include + +#include + #include #include @@ -184,9 +186,7 @@ QRAttributes::reset() { /// statistics module. /// /// This class is designed to be a part of \c AuthSrv. -/// Call \c inc() to increment a counter for specific type of query in -/// the query processing function. use \c enum \c CounterType to specify -/// the type of query. +/// Call \c inc() to increment a counter for the query. /// Call \c getStatistics() to answer statistics information to statistics /// module with statistics_session, when the command \c getstats is received. /// @@ -204,17 +204,6 @@ class Counters { private: boost::scoped_ptr impl_; public: - // Enum for the type of counter - enum ServerCounterType { - SERVER_UDP_QUERY, ///< SERVER_UDP_QUERY: counter for UDP queries - SERVER_TCP_QUERY, ///< SERVER_TCP_QUERY: counter for TCP queries - SERVER_COUNTER_TYPES ///< The number of defined counters - }; - enum PerZoneCounterType { - ZONE_UDP_QUERY, ///< ZONE_UDP_QUERY: counter for UDP queries - ZONE_TCP_QUERY, ///< ZONE_TCP_QUERY: counter for TCP queries - PER_ZONE_COUNTER_TYPES ///< The number of defined counters - }; /// The constructor. /// /// This constructor is mostly exception free. But it may still throw @@ -227,33 +216,14 @@ public: /// ~Counters(); - /// \brief Increment the counter specified by the parameter. - /// - /// \param type Type of a counter to increment. - /// - /// \throw std::out_of_range \a type is unknown. - /// - /// usage: counter.inc(Counters::SERVER_UDP_QUERY); - /// - void inc(const ServerCounterType type); - - /// \brief Increment the counter of a per opcode counter. - /// - /// \note This is a tentative interface. See \c getCounter(). + /// \brief Increment counters according to the parameters. /// - /// \param opcode The opcode of the counter to increment. + /// \param qrattrs Query/Response attributes. + /// \param response DNS response message. /// /// \throw None - void inc(const isc::dns::Opcode opcode); - - /// \brief Increment the counter of a per rcode counter. - /// - /// \note This is a tentative interface. See \c getCounter(). /// - /// \param rcode The rcode of the counter to increment. - /// - /// \throw None - void inc(const isc::dns::Rcode rcode); + void inc(const QRAttributes& qrattrs, const isc::dns::Message& response); /// \brief Answers statistics counters to statistics module. /// @@ -265,47 +235,6 @@ public: /// isc::data::ConstElementPtr getStatistics() const; - /// \brief Get the value of a counter in the Counters. - /// - /// This function returns a value of the counter specified by \a type. - /// This method never throws an exception. - /// - /// Note: Currently this function is for testing purpose only. - /// - /// \param type Type of a counter to get the value of - /// - /// \return the value of the counter specified by \a type. - uint64_t getCounter(const Counters::ServerCounterType type) const; - - /// \brief Get the value of a per opcode counter. - /// - /// This method returns the value of the per opcode counter for the - /// specified \c opcode. - /// - /// \note This is a tentative interface as an attempt of experimentally - /// supporting more statistics counters. This should eventually be more - /// generalized. In any case, this method is mainly for testing. - /// - /// \throw None - /// \param opcode The opcode of the counter to get the value of - /// \return the value of the counter. - uint64_t getCounter(const isc::dns::Opcode opcode) const; - - /// \brief Get the value of a per rcode counter. - /// - /// This method returns the value of the per rcode counter for the - /// specified \c rcode. - /// - /// \note As mentioned in getCounter(const isc::dns::Opcode opcode), - /// This is a tentative interface as an attempt of experimentally - /// supporting more statistics counters. This should eventually be more - /// generalized. In any case, this method is mainly for testing. - /// - /// \throw None - /// \param rcode The rcode of the counter to get the value of - /// \return the value of the counter. - uint64_t getCounter(const isc::dns::Rcode rcode) const; - /// \brief A type of validation function for the specification in /// isc::config::ModuleSpec. /// diff --git a/src/bin/auth/statistics_items.h b/src/bin/auth/statistics_items.h index c1cdf9afd1..9404576bbe 100644 --- a/src/bin/auth/statistics_items.h +++ b/src/bin/auth/statistics_items.h @@ -369,6 +369,310 @@ const char* const QRCounterItemName[QR_COUNTER_TYPES] = { "rcode.other" }; +const int QROpCodeToQRCounterType[16] = { + QR_OPCODE_QUERY, + QR_OPCODE_IQUERY, + QR_OPCODE_STATUS, + QR_OPCODE_OTHER, + QR_OPCODE_NOTIFY, + QR_OPCODE_UPDATE, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER, + QR_OPCODE_OTHER +}; +const int QRQTypeToQRCounterType[258] = { + QR_QTYPE_OTHER, + QR_QTYPE_A, + QR_QTYPE_NS, + QR_QTYPE_MD, + QR_QTYPE_MF, + QR_QTYPE_CNAME, + QR_QTYPE_SOA, + QR_QTYPE_MB, + QR_QTYPE_MG, + QR_QTYPE_MR, + QR_QTYPE_NULL, + QR_QTYPE_WKS, + QR_QTYPE_PTR, + QR_QTYPE_HINFO, + QR_QTYPE_MINFO, + QR_QTYPE_MX, + QR_QTYPE_TXT, + QR_QTYPE_RP, + QR_QTYPE_AFSDB, + QR_QTYPE_X25, + QR_QTYPE_ISDN, + QR_QTYPE_RT, + QR_QTYPE_NSAP, + QR_QTYPE_NSAP_PTR, + QR_QTYPE_SIG, + QR_QTYPE_KEY, + QR_QTYPE_PX, + QR_QTYPE_GPOS, + QR_QTYPE_AAAA, + QR_QTYPE_LOC, + QR_QTYPE_NXT, + QR_QTYPE_EID, + QR_QTYPE_NIMLOC, + QR_QTYPE_SRV, + QR_QTYPE_ATMA, + QR_QTYPE_NAPTR, + QR_QTYPE_KX, + QR_QTYPE_CERT, + QR_QTYPE_A6, + QR_QTYPE_DNAME, + QR_QTYPE_SINK, + QR_QTYPE_OPT, + QR_QTYPE_APL, + QR_QTYPE_DS, + QR_QTYPE_SSHFP, + QR_QTYPE_IPSECKEY, + QR_QTYPE_RRSIG, + QR_QTYPE_NSEC, + QR_QTYPE_DNSKEY, + QR_QTYPE_DHCID, + QR_QTYPE_NSEC3, + QR_QTYPE_NSEC3PARAM, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_HIP, + QR_QTYPE_NINFO, + QR_QTYPE_RKEY, + QR_QTYPE_TALINK, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_SPF, + QR_QTYPE_UINFO, + QR_QTYPE_UID, + QR_QTYPE_GID, + QR_QTYPE_UNSPEC, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_OTHER, + QR_QTYPE_TKEY, + QR_QTYPE_TSIG, + QR_QTYPE_IXFR, + QR_QTYPE_AXFR, + QR_QTYPE_MAILB, + QR_QTYPE_MAILA, + QR_QTYPE_OTHER, + QR_QTYPE_URI, + QR_QTYPE_CAA +}; +const int QRRCodeToQRCounterType[23] = { + QR_RCODE_NOERROR, + QR_RCODE_FORMERR, + QR_RCODE_SERVFAIL, + QR_RCODE_NXDOMAIN, + QR_RCODE_NOTIMP, + QR_RCODE_REFUSED, + QR_RCODE_YXDOMAIN, + QR_RCODE_YXRRSET, + QR_RCODE_NXRRSET, + QR_RCODE_NOTAUTH, + QR_RCODE_NOTZONE, + QR_RCODE_OTHER, + QR_RCODE_OTHER, + QR_RCODE_OTHER, + QR_RCODE_OTHER, + QR_RCODE_OTHER, + QR_RCODE_BADSIGVERS, + QR_RCODE_BADKEY, + QR_RCODE_BADTIME, + QR_RCODE_BADMODE, + QR_RCODE_BADNAME, + QR_RCODE_BADALG, + QR_RCODE_BADTRUNC +}; + } // anonymous namespace #endif // __STATISTICS_ITEMS_H diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc index 65d0e58de5..e59db6d33e 100644 --- a/src/bin/auth/tests/auth_srv_unittest.cc +++ b/src/bin/auth/tests/auth_srv_unittest.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -119,29 +120,58 @@ protected: // Helper for checking Rcode statistic counters; // Checks for one specific Rcode statistics counter value - void checkRcodeCounter(const Rcode& rcode, int expected_value) const { - EXPECT_EQ(expected_value, server.getCounter(rcode)) << - "Expected Rcode count for " << rcode.toText() << - " " << expected_value << ", was: " << - server.getCounter(rcode); + void checkRcodeCounter(const std::string& rcode_name, const int rcode_value, + const int expected_value) const + { + EXPECT_EQ(expected_value, rcode_value) << + "Expected Rcode count for " << rcode_name << + " " << expected_value << ", was: " << + rcode_value; } // Checks whether all Rcode counters are set to zero void checkAllRcodeCountersZero() const { - for (int i = 0; i < 17; i++) { - checkRcodeCounter(Rcode(i), 0); + const std::map + stats_map(server.getStatistics()->mapValue()); + + const std::string rcode_prefix("rcode."); + for (std::map::const_iterator + i = stats_map.begin(), e = stats_map.end(); + i != e; + ++i) + { + if (i->first.compare(0, rcode_prefix.size(), rcode_prefix) == 0) { + checkRcodeCounter(i->first, i->second->intValue(), 0); + } } } // Checks whether all Rcode counters are set to zero except the given // rcode (it is checked to be set to 'value') void checkAllRcodeCountersZeroExcept(const Rcode& rcode, int value) const { - for (int i = 0; i < 17; i++) { - const Rcode rc(i); - if (rc == rcode) { - checkRcodeCounter(Rcode(i), value); - } else { - checkRcodeCounter(Rcode(i), 0); + std::string target_rcode_name = rcode.toText(); + std::transform(target_rcode_name.begin(), target_rcode_name.end(), + target_rcode_name.begin(), ::tolower); + // rcode 16 is registered as both BADVERS and BADSIG + if (target_rcode_name == "badvers") { + target_rcode_name = "badsigvers"; + } + + const std::map + stats_map(server.getStatistics()->mapValue()); + + const std::string rcode_prefix("rcode."); + for (std::map::const_iterator + i = stats_map.begin(), e = stats_map.end(); + i != e; + ++i) + { + if (i->first.compare(0, rcode_prefix.size(), rcode_prefix) == 0) { + if (i->first.compare(rcode_prefix + target_rcode_name) == 0) { + checkRcodeCounter(i->first, i->second->intValue(), value); + } else { + checkRcodeCounter(i->first, i->second->intValue(), 0); + } } } } @@ -218,6 +248,20 @@ createBuiltinVersionResponse(const qid_t qid, vector& data) { renderer.getLength()); } +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(); + } +} + // We did not configure any client lists. Therefore it should be REFUSED TEST_F(AuthSrvTest, noClientList) { UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(), @@ -401,7 +445,9 @@ TEST_F(AuthSrvTest, TSIGCheckFirst) { "It should be unsigned with this error"; // TSIG should have failed, and so the per opcode counter shouldn't be // incremented. - EXPECT_EQ(0, server.getCounter(Opcode::RESERVED14())); + ConstElementPtr stats = server.getStatistics(); + expectCounterItem(stats, "opcode.normal", 0); + expectCounterItem(stats, "opcode.other", 0); checkAllRcodeCountersZeroExcept(Rcode::NOTAUTH(), 1); } @@ -1029,8 +1075,12 @@ TEST_F(AuthSrvTest, // Submit UDP normal query and check query counter TEST_F(AuthSrvTest, queryCounterUDPNormal) { - // The counter should be initialized to 0. - EXPECT_EQ(0, server.getCounter(Counters::SERVER_UDP_QUERY)); + // The counters should be initialized to 0. + ConstElementPtr stats_init = server.getStatistics(); + expectCounterItem(stats_init, "queries.udp", 0); + expectCounterItem(stats_init, "queries.tcp", 0); + expectCounterItem(stats_init, "opcode.query", 0); + expectCounterItem(stats_init, "rcode.refused", 0); // Create UDP message and process. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(), default_qid, Name("example.com"), @@ -1038,18 +1088,25 @@ TEST_F(AuthSrvTest, queryCounterUDPNormal) { createRequestPacket(request_message, IPPROTO_UDP); server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv); - // After processing UDP query, the counter should be 1. - EXPECT_EQ(1, server.getCounter(Counters::SERVER_UDP_QUERY)); - // The counter for opcode Query should also be one - EXPECT_EQ(1, server.getCounter(Opcode::QUERY())); - // The counter for REFUSED responses should also be one, the rest zero - checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1); + // After processing the UDP query, these counters should be incremented: + // 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); + expectCounterItem(stats_after, "opcode.query", 1); + expectCounterItem(stats_after, "rcode.refused", 1); } // Submit TCP normal query and check query counter TEST_F(AuthSrvTest, queryCounterTCPNormal) { - // The counter should be initialized to 0. - EXPECT_EQ(0, server.getCounter(Counters::SERVER_TCP_QUERY)); + // The counters should be initialized to 0. + ConstElementPtr stats_init = server.getStatistics(); + expectCounterItem(stats_init, "queries.udp", 0); + expectCounterItem(stats_init, "queries.tcp", 0); + expectCounterItem(stats_init, "opcode.query", 0); + expectCounterItem(stats_init, "rcode.refused", 0); // Create TCP message and process. UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(), default_qid, Name("example.com"), @@ -1057,18 +1114,24 @@ TEST_F(AuthSrvTest, queryCounterTCPNormal) { createRequestPacket(request_message, IPPROTO_TCP); server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv); - // After processing TCP query, the counter should be 1. - EXPECT_EQ(1, server.getCounter(Counters::SERVER_TCP_QUERY)); - // The counter for SUCCESS responses should also be one - EXPECT_EQ(1, server.getCounter(Opcode::QUERY())); - // The counter for REFUSED responses should also be one, the rest zero - checkAllRcodeCountersZeroExcept(Rcode::REFUSED(), 1); + // After processing the TCP query, these counters should be incremented: + // 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); + expectCounterItem(stats_after, "opcode.query", 1); + expectCounterItem(stats_after, "rcode.refused", 1); } // Submit TCP AXFR query and check query counter TEST_F(AuthSrvTest, queryCounterTCPAXFR) { - // The counter should be initialized to 0. - EXPECT_EQ(0, server.getCounter(Counters::SERVER_TCP_QUERY)); + // The counters should be initialized to 0. + ConstElementPtr stats_init = server.getStatistics(); + expectCounterItem(stats_init, "queries.udp", 0); + expectCounterItem(stats_init, "queries.tcp", 0); + expectCounterItem(stats_init, "opcode.query", 0); UnitTestUtil::createRequestMessage(request_message, opcode, default_qid, Name("example.com"), RRClass::IN(), RRType::AXFR()); createRequestPacket(request_message, IPPROTO_TCP); @@ -1077,16 +1140,24 @@ TEST_F(AuthSrvTest, queryCounterTCPAXFR) { server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv); EXPECT_FALSE(dnsserv.hasAnswer()); - // After processing TCP AXFR query, the counter should be 1. - EXPECT_EQ(1, server.getCounter(Counters::SERVER_TCP_QUERY)); - // No rcodes should be incremented - checkAllRcodeCountersZero(); + // After processing the TCP AXFR query, these counters should be + // incremented: + // 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); + expectCounterItem(stats_after, "opcode.query", 1); } // Submit TCP IXFR query and check query counter TEST_F(AuthSrvTest, queryCounterTCPIXFR) { - // The counter should be initialized to 0. - EXPECT_EQ(0, server.getCounter(Counters::SERVER_TCP_QUERY)); + // The counters should be initialized to 0. + ConstElementPtr stats_init = server.getStatistics(); + expectCounterItem(stats_init, "queries.udp", 0); + expectCounterItem(stats_init, "queries.tcp", 0); + expectCounterItem(stats_init, "opcode.query", 0); UnitTestUtil::createRequestMessage(request_message, opcode, default_qid, Name("example.com"), RRClass::IN(), RRType::IXFR()); createRequestPacket(request_message, IPPROTO_TCP); @@ -1095,14 +1166,24 @@ TEST_F(AuthSrvTest, queryCounterTCPIXFR) { server.processMessage(*io_message, *parse_message, *response_obuffer, &dnsserv); EXPECT_FALSE(dnsserv.hasAnswer()); - // After processing TCP IXFR query, the counter should be 1. - EXPECT_EQ(1, server.getCounter(Counters::SERVER_TCP_QUERY)); + // After processing the TCP IXFR query, these counters should be + // incremented: + // 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); + expectCounterItem(stats_after, "opcode.query", 1); } TEST_F(AuthSrvTest, queryCounterOpcodes) { - for (int i = 0; i < 16; ++i) { + // Check for 0..2, 3(=other), 4..5 + // The counter should be initialized to 0. + for (int i = 0; i < 6; ++i) { // The counter should be initialized to 0. - EXPECT_EQ(0, server.getCounter(Opcode(i))); + expectCounterItem(server.getStatistics(), + QRCounterItemName[QROpCodeToQRCounterType[i]], 0); // For each possible opcode, create a request message and send it UnitTestUtil::createRequestMessage(request_message, Opcode(i), @@ -1120,7 +1201,39 @@ TEST_F(AuthSrvTest, queryCounterOpcodes) { } // Confirm the counter. - EXPECT_EQ(i + 1, server.getCounter(Opcode(i))); + expectCounterItem(server.getStatistics(), + QRCounterItemName[QROpCodeToQRCounterType[i]], + i + 1); + } + // Check for 6..15 + // they are treated as the 'other' opcode + // the 'other' opcode counter is 4 at this point + int expected = 4; + for (int i = 6; i < 16; ++i) { + // The counter should be initialized to 0. + expectCounterItem(server.getStatistics(), + QRCounterItemName[QROpCodeToQRCounterType[i]], + expected); + + // For each possible opcode, create a request message and send it + UnitTestUtil::createRequestMessage(request_message, Opcode(i), + default_qid, Name("example.com"), + RRClass::IN(), RRType::NS()); + createRequestPacket(request_message, IPPROTO_UDP); + + // "send" the request once + parse_message->clear(Message::PARSE); + server.processMessage(*io_message, *parse_message, + *response_obuffer, + &dnsserv); + + // the 'other' opcode counter should be incremented + ++expected; + + // Confirm the counter. + expectCounterItem(server.getStatistics(), + QRCounterItemName[QROpCodeToQRCounterType[i]], + expected); } } diff --git a/src/bin/auth/tests/statistics_unittest.cc b/src/bin/auth/tests/statistics_unittest.cc index 23ed878e7a..a845aaa04a 100644 --- a/src/bin/auth/tests/statistics_unittest.cc +++ b/src/bin/auth/tests/statistics_unittest.cc @@ -31,249 +31,92 @@ #include +#include +#include +#include +#include +#include + using namespace std; using namespace isc::cc; using namespace isc::dns; using namespace isc::data; using isc::auth::statistics::Counters; +using isc::auth::statistics::QRAttributes; namespace { class CountersTest : public ::testing::Test { protected: - CountersTest() : counters() { - } - ~CountersTest() { - } + CountersTest() : counters() {} + ~CountersTest() {} Counters counters; - // no need to be inherited from the original class here. - class MockModuleSpec { - public: - bool validateStatistics(ConstElementPtr, const bool valid) const - { return (valid); } - }; - MockModuleSpec module_spec_; }; -TEST_F(CountersTest, incrementUDPCounter) { - // The counter should be initialized to 0. - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_UDP_QUERY)); - EXPECT_NO_THROW(counters.inc(Counters::SERVER_UDP_QUERY)); - // After increment, the counter should be 1. - EXPECT_EQ(1, counters.getCounter(Counters::SERVER_UDP_QUERY)); -} - -TEST_F(CountersTest, incrementTCPCounter) { - // The counter should be initialized to 0. - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_TCP_QUERY)); - EXPECT_NO_THROW(counters.inc(Counters::SERVER_TCP_QUERY)); - // After increment, the counter should be 1. - EXPECT_EQ(1, counters.getCounter(Counters::SERVER_TCP_QUERY)); -} - -TEST_F(CountersTest, incrementInvalidCounter) { - // Expect to throw an isc::OutOfRange - EXPECT_THROW(counters.inc(Counters::SERVER_COUNTER_TYPES), - isc::OutOfRange); -} - -TEST_F(CountersTest, incrementOpcodeCounter) { - // The counter should be initialized to 0. If we increment it by 1 - // the counter should be 1. - for (int i = 0; i < 16; ++i) { - EXPECT_EQ(0, counters.getCounter(Opcode(i))); - counters.inc(Opcode(i)); - EXPECT_EQ(1, counters.getCounter(Opcode(i))); - } -} - -TEST_F(CountersTest, incrementRcodeCounter) { - // The counter should be initialized to 0. If we increment it by 1 - // the counter should be 1. - for (int i = 0; i < 17; ++i) { - EXPECT_EQ(0, counters.getCounter(Rcode(i))); - counters.inc(Rcode(i)); - EXPECT_EQ(1, counters.getCounter(Rcode(i))); - } -} - -void -opcodeDataCheck(ConstElementPtr data, const int expected[16]) { - const char* item_names[] = { - "query", "iquery", "status", "reserved3", "notify", "update", - "reserved6", "reserved7", "reserved8", "reserved9", "reserved10", - "reserved11", "reserved12", "reserved13", "reserved14", "reserved15", - NULL - }; - int i; - for (i = 0; i < 16; ++i) { - ASSERT_NE(static_cast(NULL), item_names[i]); - const string item_name = "opcode." + string(item_names[i]); - if (expected[i] == 0) { - EXPECT_FALSE(data->get(item_name)); - } else { - EXPECT_EQ(expected[i], data->get(item_name)->intValue()); +bool +checkCountersAllZeroExcept(const isc::data::ConstElementPtr counters, + const std::set& except_for) { + std::map stats_map = counters->mapValue(); + + for (std::map::const_iterator + i = stats_map.begin(), e = stats_map.end(); + i != e; + ++i) + { + int expect = 0; + if (except_for.count(i->first) != 0) { + expect = 1; } + EXPECT_EQ(expect, i->second->intValue()) << "Expected counter " + << i->first << " = " << expect << ", actual: " + << i->second->intValue(); } - // We should have examined all names - ASSERT_EQ(static_cast(NULL), item_names[i]); -} -void -rcodeDataCheck(ConstElementPtr data, const int expected[17]) { - const char* item_names[] = { - "noerror", "formerr", "servfail", "nxdomain", "notimp", "refused", - "yxdomain", "yxrrset", "nxrrset", "notauth", "notzone", "reserved11", - "reserved12", "reserved13", "reserved14", "reserved15", "badvers", - NULL - }; - int i; - for (i = 0; i < 17; ++i) { - ASSERT_NE(static_cast(NULL), item_names[i]); - const string item_name = "rcode." + string(item_names[i]); - if (expected[i] == 0) { - EXPECT_FALSE(data->get(item_name)); - } else { - EXPECT_EQ(expected[i], data->get(item_name)->intValue()); - } - } - // We should have examined all names - ASSERT_EQ(static_cast(NULL), item_names[i]); + return false; } -TEST_F(CountersTest, getStatisticsWithoutValidator) { - // Get statistics data. - // Validate if it answers correct data. +TEST_F(CountersTest, incrementNormalQuery) { + Message response(Message::RENDER); + QRAttributes qrattrs; + std::set expect_nonzero; - // Counters should be initialized to 0. - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_UDP_QUERY)); - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_TCP_QUERY)); + expect_nonzero.clear(); + checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero); - // UDP query counter is set to 2. - counters.inc(Counters::SERVER_UDP_QUERY); - counters.inc(Counters::SERVER_UDP_QUERY); - // TCP query counter is set to 1. - counters.inc(Counters::SERVER_TCP_QUERY); - ConstElementPtr statistics_data = counters.getStatistics(); + qrattrs.setQueryIPVersion(AF_INET6); + qrattrs.setQueryTransportProtocol(IPPROTO_UDP); + qrattrs.setQueryOpCode(Opcode::QUERY_CODE); + qrattrs.setQueryEDNS(true, false); + qrattrs.setQueryDO(true); + qrattrs.answerWasSent(); - // UDP query counter is 2 and TCP query counter is 1. - EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue()); - EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue()); + response.setRcode(Rcode::REFUSED()); + response.addQuestion(Question(Name("example.com"), + RRClass::IN(), RRType::AAAA())); - // By default opcode counters are all 0 and omitted - const int opcode_results[16] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; - opcodeDataCheck(statistics_data, opcode_results); - // By default rcode counters are all 0 and omitted - const int rcode_results[17] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; - rcodeDataCheck(statistics_data, rcode_results); -} + counters.inc(qrattrs, response); -void -updateOpcodeCounters(Counters &counters, const int expected[16]) { - for (int i = 0; i < 16; ++i) { - for (int j = 0; j < expected[i]; ++j) { - counters.inc(Opcode(i)); - } - } + expect_nonzero.clear(); + expect_nonzero.insert("opcode.query"); + expect_nonzero.insert("queries.udp"); + expect_nonzero.insert("rcode.refused"); + checkCountersAllZeroExcept(counters.getStatistics(), expect_nonzero); } -void -updateRcodeCounters(Counters &counters, const int expected[17]) { - for (int i = 0; i < 17; ++i) { - for (int j = 0; j < expected[i]; ++j) { - counters.inc(Rcode(i)); - } +TEST_F(CountersTest, getStatistics) { + std::map stats_map = + counters.getStatistics()->mapValue(); + for (std::map::const_iterator + i = stats_map.begin(), e = stats_map.end(); + i != e; + ++i) + { + // item type check + EXPECT_NO_THROW(i->second->intValue()) + << "Item " << i->first << " is not IntElement"; } } -TEST_F(CountersTest, getStatisticsWithOpcodeCounters) { - // Increment some of the opcode counters. Then they should appear in the - // submitted data; others shouldn't - const int opcode_results[16] = { 1, 2, 3, 0, 4, 5, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; - updateOpcodeCounters(counters, opcode_results); - ConstElementPtr statistics_data = counters.getStatistics(); - opcodeDataCheck(statistics_data, opcode_results); -} - -TEST_F(CountersTest, getStatisticsWithAllOpcodeCounters) { - // Increment all opcode counters. Then they should appear in the - // submitted data. - const int opcode_results[16] = { 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 }; - updateOpcodeCounters(counters, opcode_results); - ConstElementPtr statistics_data = counters.getStatistics(); - opcodeDataCheck(statistics_data, opcode_results); -} - -TEST_F(CountersTest, getStatisticsWithRcodeCounters) { - // Increment some of the rcode counters. Then they should appear in the - // submitted data; others shouldn't - const int rcode_results[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 0, 0, 0, 0, 0, 0, 11 }; - updateRcodeCounters(counters, rcode_results); - ConstElementPtr statistics_data = counters.getStatistics(); - rcodeDataCheck(statistics_data, rcode_results); -} - -TEST_F(CountersTest, getStatisticsWithAllRcodeCounters) { - // Increment all rcode counters. Then they should appear in the - // submitted data. - const int rcode_results[17] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 }; - updateOpcodeCounters(counters, rcode_results); - ConstElementPtr statistics_data = counters.getStatistics(); - opcodeDataCheck(statistics_data, rcode_results); -} - -TEST_F(CountersTest, getStatisticsWithValidator) { - - //a validator for the unittest - Counters::validator_type validator; - ConstElementPtr el; - - // Get statistics data with correct statistics validator. - validator = boost::bind( - &CountersTest::MockModuleSpec::validateStatistics, - &module_spec_, _1, true); - - EXPECT_TRUE(validator(el)); - - // register validator to Counters - counters.registerStatisticsValidator(validator); - - // Counters should be initialized to 0. - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_UDP_QUERY)); - EXPECT_EQ(0, counters.getCounter(Counters::SERVER_TCP_QUERY)); - - // UDP query counter is set to 2. - counters.inc(Counters::SERVER_UDP_QUERY); - counters.inc(Counters::SERVER_UDP_QUERY); - // TCP query counter is set to 1. - counters.inc(Counters::SERVER_TCP_QUERY); - - // checks the value returned by getStatistics - ConstElementPtr statistics_data = counters.getStatistics(); - - // UDP query counter is 2 and TCP query counter is 1. - EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue()); - EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue()); - - // Get statistics data with incorrect statistics validator. - validator = boost::bind( - &CountersTest::MockModuleSpec::validateStatistics, - &module_spec_, _1, false); - - EXPECT_FALSE(validator(el)); - - counters.registerStatisticsValidator(validator); - - // checks the value returned by getStatistics - EXPECT_FALSE(counters.getStatistics()); -} - TEST(StatisticsItemsTest, QRItemNamesCheck) { // check the number of elements in the array EXPECT_EQ(sizeof(QRCounterItemName) / sizeof(QRCounterItemName[0]),