1238106Sdes/*
2238106Sdes * daemon/stats.c - collect runtime performance indicators.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file describes the data structure used to collect runtime performance
40238106Sdes * numbers. These 'statistics' may be of interest to the operator.
41238106Sdes */
42238106Sdes#include "config.h"
43266114Sdes#ifdef HAVE_TIME_H
44266114Sdes#include <time.h>
45266114Sdes#endif
46266114Sdes#include <sys/time.h>
47266114Sdes#include <sys/types.h>
48238106Sdes#include "daemon/stats.h"
49238106Sdes#include "daemon/worker.h"
50238106Sdes#include "daemon/daemon.h"
51238106Sdes#include "services/mesh.h"
52238106Sdes#include "services/outside_network.h"
53287917Sdes#include "services/listen_dnsport.h"
54238106Sdes#include "util/config_file.h"
55238106Sdes#include "util/tube.h"
56238106Sdes#include "util/timehist.h"
57238106Sdes#include "util/net_help.h"
58238106Sdes#include "validator/validator.h"
59356345Scy#include "iterator/iterator.h"
60287917Sdes#include "sldns/sbuffer.h"
61276605Sdes#include "services/cache/rrset.h"
62276605Sdes#include "services/cache/infra.h"
63356345Scy#include "services/authzone.h"
64276605Sdes#include "validator/val_kcache.h"
65356345Scy#include "validator/val_neg.h"
66356345Scy#ifdef CLIENT_SUBNET
67356345Scy#include "edns-subnet/subnetmod.h"
68356345Scy#endif
69356345Scy#ifdef HAVE_SSL
70356345Scy#include <openssl/ssl.h>
71356345Scy#endif
72238106Sdes
73238106Sdes/** add timers and the values do not overflow or become negative */
74238106Sdesstatic void
75356345Scystats_timeval_add(long long* d_sec, long long* d_usec, long long add_sec, long long add_usec)
76238106Sdes{
77238106Sdes#ifndef S_SPLINT_S
78356345Scy	(*d_sec) += add_sec;
79356345Scy	(*d_usec) += add_usec;
80356345Scy	if((*d_usec) >= 1000000) {
81356345Scy		(*d_usec) -= 1000000;
82356345Scy		(*d_sec)++;
83238106Sdes	}
84238106Sdes#endif
85238106Sdes}
86238106Sdes
87356345Scyvoid server_stats_init(struct ub_server_stats* stats, struct config_file* cfg)
88238106Sdes{
89238106Sdes	memset(stats, 0, sizeof(*stats));
90238106Sdes	stats->extended = cfg->stat_extended;
91238106Sdes}
92238106Sdes
93356345Scyvoid server_stats_querymiss(struct ub_server_stats* stats, struct worker* worker)
94238106Sdes{
95238106Sdes	stats->num_queries_missed_cache++;
96238106Sdes	stats->sum_query_list_size += worker->env.mesh->all.count;
97356345Scy	if((long long)worker->env.mesh->all.count > stats->max_query_list_size)
98356345Scy		stats->max_query_list_size = (long long)worker->env.mesh->all.count;
99238106Sdes}
100238106Sdes
101356345Scyvoid server_stats_prefetch(struct ub_server_stats* stats, struct worker* worker)
102238106Sdes{
103238106Sdes	stats->num_queries_prefetch++;
104238106Sdes	/* changes the query list size so account that, like a querymiss */
105238106Sdes	stats->sum_query_list_size += worker->env.mesh->all.count;
106356345Scy	if((long long)worker->env.mesh->all.count > stats->max_query_list_size)
107356345Scy		stats->max_query_list_size = (long long)worker->env.mesh->all.count;
108238106Sdes}
109238106Sdes
110356345Scyvoid server_stats_log(struct ub_server_stats* stats, struct worker* worker,
111238106Sdes	int threadnum)
112238106Sdes{
113238106Sdes	log_info("server stats for thread %d: %u queries, "
114356345Scy		"%u answers from cache, %u recursions, %u prefetch, %u rejected by "
115356345Scy		"ip ratelimiting",
116238106Sdes		threadnum, (unsigned)stats->num_queries,
117238106Sdes		(unsigned)(stats->num_queries -
118238106Sdes			stats->num_queries_missed_cache),
119238106Sdes		(unsigned)stats->num_queries_missed_cache,
120356345Scy		(unsigned)stats->num_queries_prefetch,
121356345Scy		(unsigned)stats->num_queries_ip_ratelimited);
122238106Sdes	log_info("server stats for thread %d: requestlist max %u avg %g "
123238106Sdes		"exceeded %u jostled %u", threadnum,
124238106Sdes		(unsigned)stats->max_query_list_size,
125238106Sdes		(stats->num_queries_missed_cache+stats->num_queries_prefetch)?
126238106Sdes			(double)stats->sum_query_list_size/
127356345Scy			(double)(stats->num_queries_missed_cache+
128238106Sdes			stats->num_queries_prefetch) : 0.0,
129238106Sdes		(unsigned)worker->env.mesh->stats_dropped,
130238106Sdes		(unsigned)worker->env.mesh->stats_jostled);
131238106Sdes}
132238106Sdes
133356345Scy
134356345Scy#ifdef CLIENT_SUBNET
135356345Scy/** Set the EDNS Subnet stats. */
136356345Scystatic void
137356345Scyset_subnet_stats(struct worker* worker, struct ub_server_stats* svr,
138356345Scy	int reset)
139356345Scy{
140356345Scy	int m = modstack_find(&worker->env.mesh->mods, "subnet");
141356345Scy	struct subnet_env* sne;
142356345Scy	if(m == -1)
143356345Scy		return;
144356345Scy	sne = (struct subnet_env*)worker->env.modinfo[m];
145356345Scy	if(reset && !worker->env.cfg->stat_cumulative) {
146356345Scy		lock_rw_wrlock(&sne->biglock);
147356345Scy	} else {
148356345Scy		lock_rw_rdlock(&sne->biglock);
149356345Scy	}
150356345Scy	svr->num_query_subnet = (long long)(sne->num_msg_nocache + sne->num_msg_cache);
151356345Scy	svr->num_query_subnet_cache = (long long)sne->num_msg_cache;
152356345Scy	if(reset && !worker->env.cfg->stat_cumulative) {
153356345Scy		sne->num_msg_cache = 0;
154356345Scy		sne->num_msg_nocache = 0;
155356345Scy	}
156356345Scy	lock_rw_unlock(&sne->biglock);
157356345Scy}
158356345Scy#endif /* CLIENT_SUBNET */
159356345Scy
160356345Scy/** Set the neg cache stats. */
161356345Scystatic void
162356345Scyset_neg_cache_stats(struct worker* worker, struct ub_server_stats* svr,
163356345Scy	int reset)
164356345Scy{
165356345Scy	int m = modstack_find(&worker->env.mesh->mods, "validator");
166356345Scy	struct val_env* ve;
167356345Scy	struct val_neg_cache* neg;
168356345Scy	if(m == -1)
169356345Scy		return;
170356345Scy	ve = (struct val_env*)worker->env.modinfo[m];
171356345Scy	if(!ve->neg_cache)
172356345Scy		return;
173356345Scy	neg = ve->neg_cache;
174356345Scy	lock_basic_lock(&neg->lock);
175356345Scy	svr->num_neg_cache_noerror = (long long)neg->num_neg_cache_noerror;
176356345Scy	svr->num_neg_cache_nxdomain = (long long)neg->num_neg_cache_nxdomain;
177356345Scy	if(reset && !worker->env.cfg->stat_cumulative) {
178356345Scy		neg->num_neg_cache_noerror = 0;
179356345Scy		neg->num_neg_cache_nxdomain = 0;
180356345Scy	}
181356345Scy	lock_basic_unlock(&neg->lock);
182356345Scy}
183356345Scy
184238106Sdes/** get rrsets bogus number from validator */
185238106Sdesstatic size_t
186356345Scyget_rrset_bogus(struct worker* worker, int reset)
187238106Sdes{
188238106Sdes	int m = modstack_find(&worker->env.mesh->mods, "validator");
189238106Sdes	struct val_env* ve;
190238106Sdes	size_t r;
191238106Sdes	if(m == -1)
192238106Sdes		return 0;
193238106Sdes	ve = (struct val_env*)worker->env.modinfo[m];
194238106Sdes	lock_basic_lock(&ve->bogus_lock);
195238106Sdes	r = ve->num_rrset_bogus;
196356345Scy	if(reset && !worker->env.cfg->stat_cumulative)
197238106Sdes		ve->num_rrset_bogus = 0;
198238106Sdes	lock_basic_unlock(&ve->bogus_lock);
199238106Sdes	return r;
200238106Sdes}
201238106Sdes
202356345Scy/** get number of ratelimited queries from iterator */
203356345Scystatic size_t
204356345Scyget_queries_ratelimit(struct worker* worker, int reset)
205356345Scy{
206356345Scy	int m = modstack_find(&worker->env.mesh->mods, "iterator");
207356345Scy	struct iter_env* ie;
208356345Scy	size_t r;
209356345Scy	if(m == -1)
210356345Scy		return 0;
211356345Scy	ie = (struct iter_env*)worker->env.modinfo[m];
212356345Scy	lock_basic_lock(&ie->queries_ratelimit_lock);
213356345Scy	r = ie->num_queries_ratelimited;
214356345Scy	if(reset && !worker->env.cfg->stat_cumulative)
215356345Scy		ie->num_queries_ratelimited = 0;
216356345Scy	lock_basic_unlock(&ie->queries_ratelimit_lock);
217356345Scy	return r;
218356345Scy}
219356345Scy
220356345Scy#ifdef USE_DNSCRYPT
221356345Scy/** get the number of shared secret cache miss */
222356345Scystatic size_t
223356345Scyget_dnscrypt_cache_miss(struct worker* worker, int reset)
224356345Scy{
225356345Scy	size_t r;
226356345Scy	struct dnsc_env* de = worker->daemon->dnscenv;
227356345Scy	if(!de) return 0;
228356345Scy
229356345Scy	lock_basic_lock(&de->shared_secrets_cache_lock);
230356345Scy	r = de->num_query_dnscrypt_secret_missed_cache;
231356345Scy	if(reset && !worker->env.cfg->stat_cumulative)
232356345Scy		de->num_query_dnscrypt_secret_missed_cache = 0;
233356345Scy	lock_basic_unlock(&de->shared_secrets_cache_lock);
234356345Scy	return r;
235356345Scy}
236356345Scy
237356345Scy/** get the number of replayed queries */
238356345Scystatic size_t
239356345Scyget_dnscrypt_replay(struct worker* worker, int reset)
240356345Scy{
241356345Scy	size_t r;
242356345Scy	struct dnsc_env* de = worker->daemon->dnscenv;
243356345Scy
244356345Scy	lock_basic_lock(&de->nonces_cache_lock);
245356345Scy	r = de->num_query_dnscrypt_replay;
246356345Scy	if(reset && !worker->env.cfg->stat_cumulative)
247356345Scy		de->num_query_dnscrypt_replay = 0;
248356345Scy	lock_basic_unlock(&de->nonces_cache_lock);
249356345Scy	return r;
250356345Scy}
251356345Scy#endif /* USE_DNSCRYPT */
252356345Scy
253238106Sdesvoid
254356345Scyserver_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
255238106Sdes{
256238106Sdes	int i;
257287917Sdes	struct listen_list* lp;
258238106Sdes
259238106Sdes	s->svr = worker->stats;
260356345Scy	s->mesh_num_states = (long long)worker->env.mesh->all.count;
261356345Scy	s->mesh_num_reply_states = (long long)worker->env.mesh->num_reply_states;
262356345Scy	s->mesh_jostled = (long long)worker->env.mesh->stats_jostled;
263356345Scy	s->mesh_dropped = (long long)worker->env.mesh->stats_dropped;
264356345Scy	s->mesh_replies_sent = (long long)worker->env.mesh->replies_sent;
265356345Scy	s->mesh_replies_sum_wait_sec = (long long)worker->env.mesh->replies_sum_wait.tv_sec;
266356345Scy	s->mesh_replies_sum_wait_usec = (long long)worker->env.mesh->replies_sum_wait.tv_usec;
267238106Sdes	s->mesh_time_median = timehist_quartile(worker->env.mesh->histogram,
268238106Sdes		0.50);
269238106Sdes
270238106Sdes	/* add in the values from the mesh */
271356345Scy	s->svr.ans_secure += (long long)worker->env.mesh->ans_secure;
272356345Scy	s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus;
273356345Scy	s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata;
274368129Scy	s->svr.ans_expired += (long long)worker->env.mesh->ans_expired;
275361435Scy	for(i=0; i<UB_STATS_RCODE_NUM; i++)
276356345Scy		s->svr.ans_rcode[i] += (long long)worker->env.mesh->ans_rcode[i];
277361435Scy	for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
278361435Scy		s->svr.rpz_action[i] += (long long)worker->env.mesh->rpz_action[i];
279238106Sdes	timehist_export(worker->env.mesh->histogram, s->svr.hist,
280238106Sdes		NUM_BUCKETS_HIST);
281238106Sdes	/* values from outside network */
282356345Scy	s->svr.unwanted_replies = (long long)worker->back->unwanted_replies;
283356345Scy	s->svr.qtcp_outgoing = (long long)worker->back->num_tcp_outgoing;
284238106Sdes
285238106Sdes	/* get and reset validator rrset bogus number */
286356345Scy	s->svr.rrset_bogus = (long long)get_rrset_bogus(worker, reset);
287238106Sdes
288356345Scy	/* get and reset iterator query ratelimit number */
289356345Scy	s->svr.queries_ratelimited = (long long)get_queries_ratelimit(worker, reset);
290356345Scy
291276605Sdes	/* get cache sizes */
292356345Scy	s->svr.msg_cache_count = (long long)count_slabhash_entries(worker->env.msg_cache);
293356345Scy	s->svr.rrset_cache_count = (long long)count_slabhash_entries(&worker->env.rrset_cache->table);
294356345Scy	s->svr.infra_cache_count = (long long)count_slabhash_entries(worker->env.infra_cache->hosts);
295276605Sdes	if(worker->env.key_cache)
296356345Scy		s->svr.key_cache_count = (long long)count_slabhash_entries(worker->env.key_cache->slab);
297276605Sdes	else	s->svr.key_cache_count = 0;
298276605Sdes
299356345Scy#ifdef USE_DNSCRYPT
300356345Scy	if(worker->daemon->dnscenv) {
301356345Scy		s->svr.num_query_dnscrypt_secret_missed_cache =
302356345Scy			(long long)get_dnscrypt_cache_miss(worker, reset);
303356345Scy		s->svr.shared_secret_cache_count = (long long)count_slabhash_entries(
304356345Scy			worker->daemon->dnscenv->shared_secrets_cache);
305356345Scy		s->svr.nonce_cache_count = (long long)count_slabhash_entries(
306356345Scy			worker->daemon->dnscenv->nonces_cache);
307356345Scy		s->svr.num_query_dnscrypt_replay =
308356345Scy			(long long)get_dnscrypt_replay(worker, reset);
309356345Scy	} else {
310356345Scy		s->svr.num_query_dnscrypt_secret_missed_cache = 0;
311356345Scy		s->svr.shared_secret_cache_count = 0;
312356345Scy		s->svr.nonce_cache_count = 0;
313356345Scy		s->svr.num_query_dnscrypt_replay = 0;
314356345Scy	}
315356345Scy#else
316356345Scy	s->svr.num_query_dnscrypt_secret_missed_cache = 0;
317356345Scy	s->svr.shared_secret_cache_count = 0;
318356345Scy	s->svr.nonce_cache_count = 0;
319356345Scy	s->svr.num_query_dnscrypt_replay = 0;
320356345Scy#endif /* USE_DNSCRYPT */
321356345Scy	if(worker->env.auth_zones) {
322356345Scy		if(reset && !worker->env.cfg->stat_cumulative) {
323356345Scy			lock_rw_wrlock(&worker->env.auth_zones->lock);
324356345Scy		} else {
325356345Scy			lock_rw_rdlock(&worker->env.auth_zones->lock);
326356345Scy		}
327356345Scy		s->svr.num_query_authzone_up = (long long)worker->env.
328356345Scy			auth_zones->num_query_up;
329356345Scy		s->svr.num_query_authzone_down = (long long)worker->env.
330356345Scy			auth_zones->num_query_down;
331356345Scy		if(reset && !worker->env.cfg->stat_cumulative) {
332356345Scy			worker->env.auth_zones->num_query_up = 0;
333356345Scy			worker->env.auth_zones->num_query_down = 0;
334356345Scy		}
335356345Scy		lock_rw_unlock(&worker->env.auth_zones->lock);
336356345Scy	}
337356345Scy	s->svr.mem_stream_wait =
338356345Scy		(long long)tcp_req_info_get_stream_buffer_size();
339368129Scy	s->svr.mem_http2_query_buffer =
340368129Scy		(long long)http2_get_query_buffer_size();
341368129Scy	s->svr.mem_http2_response_buffer =
342368129Scy		(long long)http2_get_response_buffer_size();
343356345Scy
344356345Scy	/* Set neg cache usage numbers */
345356345Scy	set_neg_cache_stats(worker, &s->svr, reset);
346356345Scy#ifdef CLIENT_SUBNET
347356345Scy	/* EDNS Subnet usage numbers */
348356345Scy	set_subnet_stats(worker, &s->svr, reset);
349356345Scy#else
350356345Scy	s->svr.num_query_subnet = 0;
351356345Scy	s->svr.num_query_subnet_cache = 0;
352356345Scy#endif
353356345Scy
354287917Sdes	/* get tcp accept usage */
355287917Sdes	s->svr.tcp_accept_usage = 0;
356287917Sdes	for(lp = worker->front->cps; lp; lp = lp->next) {
357287917Sdes		if(lp->com->type == comm_tcp_accept)
358356345Scy			s->svr.tcp_accept_usage += (long long)lp->com->cur_tcp_count;
359287917Sdes	}
360287917Sdes
361238106Sdes	if(reset && !worker->env.cfg->stat_cumulative) {
362238106Sdes		worker_stats_clear(worker);
363238106Sdes	}
364238106Sdes}
365238106Sdes
366238106Sdesvoid server_stats_obtain(struct worker* worker, struct worker* who,
367356345Scy	struct ub_stats_info* s, int reset)
368238106Sdes{
369238106Sdes	uint8_t *reply = NULL;
370238106Sdes	uint32_t len = 0;
371238106Sdes	if(worker == who) {
372238106Sdes		/* just fill it in */
373238106Sdes		server_stats_compile(worker, s, reset);
374238106Sdes		return;
375238106Sdes	}
376238106Sdes	/* communicate over tube */
377238106Sdes	verbose(VERB_ALGO, "write stats cmd");
378238106Sdes	if(reset)
379238106Sdes		worker_send_cmd(who, worker_cmd_stats);
380238106Sdes	else 	worker_send_cmd(who, worker_cmd_stats_noreset);
381238106Sdes	verbose(VERB_ALGO, "wait for stats reply");
382238106Sdes	if(!tube_read_msg(worker->cmd, &reply, &len, 0))
383238106Sdes		fatal_exit("failed to read stats over cmd channel");
384238106Sdes	if(len != (uint32_t)sizeof(*s))
385238106Sdes		fatal_exit("stats on cmd channel wrong length %d %d",
386238106Sdes			(int)len, (int)sizeof(*s));
387238106Sdes	memcpy(s, reply, (size_t)len);
388238106Sdes	free(reply);
389238106Sdes}
390238106Sdes
391238106Sdesvoid server_stats_reply(struct worker* worker, int reset)
392238106Sdes{
393356345Scy	struct ub_stats_info s;
394238106Sdes	server_stats_compile(worker, &s, reset);
395238106Sdes	verbose(VERB_ALGO, "write stats replymsg");
396238106Sdes	if(!tube_write_msg(worker->daemon->workers[0]->cmd,
397238106Sdes		(uint8_t*)&s, sizeof(s), 0))
398238106Sdes		fatal_exit("could not write stat values over cmd channel");
399238106Sdes}
400238106Sdes
401356345Scyvoid server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
402238106Sdes{
403238106Sdes	total->svr.num_queries += a->svr.num_queries;
404356345Scy	total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited;
405238106Sdes	total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
406238106Sdes	total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
407238106Sdes	total->svr.sum_query_list_size += a->svr.sum_query_list_size;
408361435Scy	total->svr.ans_expired += a->svr.ans_expired;
409356345Scy#ifdef USE_DNSCRYPT
410356345Scy	total->svr.num_query_dnscrypt_crypted += a->svr.num_query_dnscrypt_crypted;
411356345Scy	total->svr.num_query_dnscrypt_cert += a->svr.num_query_dnscrypt_cert;
412356345Scy	total->svr.num_query_dnscrypt_cleartext += \
413356345Scy		a->svr.num_query_dnscrypt_cleartext;
414356345Scy	total->svr.num_query_dnscrypt_crypted_malformed += \
415356345Scy		a->svr.num_query_dnscrypt_crypted_malformed;
416356345Scy#endif /* USE_DNSCRYPT */
417238106Sdes	/* the max size reached is upped to higher of both */
418238106Sdes	if(a->svr.max_query_list_size > total->svr.max_query_list_size)
419238106Sdes		total->svr.max_query_list_size = a->svr.max_query_list_size;
420238106Sdes
421238106Sdes	if(a->svr.extended) {
422238106Sdes		int i;
423238106Sdes		total->svr.qtype_big += a->svr.qtype_big;
424238106Sdes		total->svr.qclass_big += a->svr.qclass_big;
425238106Sdes		total->svr.qtcp += a->svr.qtcp;
426276605Sdes		total->svr.qtcp_outgoing += a->svr.qtcp_outgoing;
427356345Scy		total->svr.qtls += a->svr.qtls;
428356345Scy		total->svr.qtls_resume += a->svr.qtls_resume;
429368129Scy		total->svr.qhttps += a->svr.qhttps;
430238106Sdes		total->svr.qipv6 += a->svr.qipv6;
431238106Sdes		total->svr.qbit_QR += a->svr.qbit_QR;
432238106Sdes		total->svr.qbit_AA += a->svr.qbit_AA;
433238106Sdes		total->svr.qbit_TC += a->svr.qbit_TC;
434238106Sdes		total->svr.qbit_RD += a->svr.qbit_RD;
435238106Sdes		total->svr.qbit_RA += a->svr.qbit_RA;
436238106Sdes		total->svr.qbit_Z += a->svr.qbit_Z;
437238106Sdes		total->svr.qbit_AD += a->svr.qbit_AD;
438238106Sdes		total->svr.qbit_CD += a->svr.qbit_CD;
439238106Sdes		total->svr.qEDNS += a->svr.qEDNS;
440238106Sdes		total->svr.qEDNS_DO += a->svr.qEDNS_DO;
441238106Sdes		total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
442238106Sdes		total->svr.ans_secure += a->svr.ans_secure;
443238106Sdes		total->svr.ans_bogus += a->svr.ans_bogus;
444238106Sdes		total->svr.unwanted_replies += a->svr.unwanted_replies;
445238106Sdes		total->svr.unwanted_queries += a->svr.unwanted_queries;
446287917Sdes		total->svr.tcp_accept_usage += a->svr.tcp_accept_usage;
447356345Scy		for(i=0; i<UB_STATS_QTYPE_NUM; i++)
448238106Sdes			total->svr.qtype[i] += a->svr.qtype[i];
449356345Scy		for(i=0; i<UB_STATS_QCLASS_NUM; i++)
450238106Sdes			total->svr.qclass[i] += a->svr.qclass[i];
451356345Scy		for(i=0; i<UB_STATS_OPCODE_NUM; i++)
452238106Sdes			total->svr.qopcode[i] += a->svr.qopcode[i];
453356345Scy		for(i=0; i<UB_STATS_RCODE_NUM; i++)
454238106Sdes			total->svr.ans_rcode[i] += a->svr.ans_rcode[i];
455238106Sdes		for(i=0; i<NUM_BUCKETS_HIST; i++)
456238106Sdes			total->svr.hist[i] += a->svr.hist[i];
457361435Scy		for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
458361435Scy			total->svr.rpz_action[i] += a->svr.rpz_action[i];
459238106Sdes	}
460238106Sdes
461238106Sdes	total->mesh_num_states += a->mesh_num_states;
462238106Sdes	total->mesh_num_reply_states += a->mesh_num_reply_states;
463238106Sdes	total->mesh_jostled += a->mesh_jostled;
464238106Sdes	total->mesh_dropped += a->mesh_dropped;
465238106Sdes	total->mesh_replies_sent += a->mesh_replies_sent;
466356345Scy	stats_timeval_add(&total->mesh_replies_sum_wait_sec, &total->mesh_replies_sum_wait_usec, a->mesh_replies_sum_wait_sec, a->mesh_replies_sum_wait_usec);
467238106Sdes	/* the medians are averaged together, this is not as accurate as
468238106Sdes	 * taking the median over all of the data, but is good and fast
469238106Sdes	 * added up here, division later*/
470238106Sdes	total->mesh_time_median += a->mesh_time_median;
471238106Sdes}
472238106Sdes
473356345Scyvoid server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
474238106Sdes	uint16_t qtype, uint16_t qclass, struct edns_data* edns,
475238106Sdes	struct comm_reply* repinfo)
476238106Sdes{
477266114Sdes	uint16_t flags = sldns_buffer_read_u16_at(c->buffer, 2);
478356345Scy	if(qtype < UB_STATS_QTYPE_NUM)
479238106Sdes		stats->qtype[qtype]++;
480238106Sdes	else	stats->qtype_big++;
481356345Scy	if(qclass < UB_STATS_QCLASS_NUM)
482238106Sdes		stats->qclass[qclass]++;
483238106Sdes	else	stats->qclass_big++;
484266114Sdes	stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++;
485356345Scy	if(c->type != comm_udp) {
486238106Sdes		stats->qtcp++;
487356345Scy		if(c->ssl != NULL) {
488356345Scy			stats->qtls++;
489356345Scy#ifdef HAVE_SSL
490356345Scy			if(SSL_session_reused(c->ssl))
491356345Scy				stats->qtls_resume++;
492356345Scy#endif
493368129Scy			if(c->type == comm_http)
494368129Scy				stats->qhttps++;
495356345Scy		}
496356345Scy	}
497238106Sdes	if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
498238106Sdes		stats->qipv6++;
499238106Sdes	if( (flags&BIT_QR) )
500238106Sdes		stats->qbit_QR++;
501238106Sdes	if( (flags&BIT_AA) )
502238106Sdes		stats->qbit_AA++;
503238106Sdes	if( (flags&BIT_TC) )
504238106Sdes		stats->qbit_TC++;
505238106Sdes	if( (flags&BIT_RD) )
506238106Sdes		stats->qbit_RD++;
507238106Sdes	if( (flags&BIT_RA) )
508238106Sdes		stats->qbit_RA++;
509238106Sdes	if( (flags&BIT_Z) )
510238106Sdes		stats->qbit_Z++;
511238106Sdes	if( (flags&BIT_AD) )
512238106Sdes		stats->qbit_AD++;
513238106Sdes	if( (flags&BIT_CD) )
514238106Sdes		stats->qbit_CD++;
515238106Sdes	if(edns->edns_present) {
516238106Sdes		stats->qEDNS++;
517238106Sdes		if( (edns->bits & EDNS_DO) )
518238106Sdes			stats->qEDNS_DO++;
519238106Sdes	}
520238106Sdes}
521238106Sdes
522356345Scyvoid server_stats_insrcode(struct ub_server_stats* stats, sldns_buffer* buf)
523238106Sdes{
524266114Sdes	if(stats->extended && sldns_buffer_limit(buf) != 0) {
525266114Sdes		int r = (int)LDNS_RCODE_WIRE( sldns_buffer_begin(buf) );
526238106Sdes		stats->ans_rcode[r] ++;
527266114Sdes		if(r == 0 && LDNS_ANCOUNT( sldns_buffer_begin(buf) ) == 0)
528238106Sdes			stats->ans_rcode_nodata ++;
529238106Sdes	}
530238106Sdes}
531