unbound_munin_ revision 356345
1228753Smm#!/bin/sh
2228753Smm#
3228753Smm# plugin for munin to monitor usage of unbound servers.
4228753Smm# To install copy this to /usr/local/share/munin/plugins/unbound_munin_
5228753Smm# and use munin-node-configure (--suggest, --shell).
6228753Smm#
7228753Smm# (C) 2008 W.C.A. Wijngaards.  BSD Licensed.
8228753Smm#
9228753Smm# To install; enable statistics and unbound-control in unbound.conf
10228753Smm#	server:		extended-statistics: yes
11228753Smm#			statistics-cumulative: no
12228753Smm#			statistics-interval: 0
13228753Smm#	remote-control:	control-enable: yes
14228753Smm# Run the command unbound-control-setup to generate the key files.
15228753Smm#
16228753Smm# Environment variables for this script
17228753Smm#	statefile	- where to put temporary statefile.
18228753Smm#	unbound_conf	- where the unbound.conf file is located.
19228753Smm#	unbound_control	- where to find unbound-control executable.
20228753Smm#	spoof_warn	- what level to warn about spoofing
21228753Smm#	spoof_crit	- what level to crit about spoofing
22228753Smm#
23228753Smm# You can set them in your munin/plugin-conf.d/plugins.conf file
24228753Smm# with:
25228753Smm# [unbound*]
26228753Smm# user root
27228753Smm# env.statefile /usr/local/var/munin/plugin-state/unbound-state
28228753Smm# env.unbound_conf /usr/local/etc/unbound/unbound.conf
29228753Smm# env.unbound_control /usr/local/sbin/unbound-control
30228753Smm# env.spoof_warn 1000
31228753Smm# env.spoof_crit 100000
32228753Smm#
33228753Smm# This plugin can create different graphs depending on what name
34228753Smm# you link it as (with ln -s) into the plugins directory
35228753Smm# You can link it multiple times.
36228753Smm# If you are only a casual user, the _hits and _by_type are most interesting,
37228753Smm# possibly followed by _by_rcode.
38228753Smm#
39228753Smm#	unbound_munin_hits	- base volume, cache hits, unwanted traffic
40228753Smm#	unbound_munin_queue	- to monitor the internal requestlist
41228753Smm#	unbound_munin_memory	- memory usage
42228753Smm#	unbound_munin_by_type	- incoming queries by type
43228753Smm#	unbound_munin_by_class	- incoming queries by class
44228753Smm#	unbound_munin_by_opcode	- incoming queries by opcode
45228753Smm#	unbound_munin_by_rcode	- answers by rcode, validation status
46228753Smm#	unbound_munin_by_flags	- incoming queries by flags
47228753Smm#	unbound_munin_histogram	- histogram of query resolving times
48228753Smm#
49228753Smm# Magic markers - optional - used by installation scripts and
50228753Smm# munin-config:  (originally contrib family but munin-node-configure ignores it)
51228753Smm#
52228753Smm#%# family=auto
53228753Smm#%# capabilities=autoconf suggest
54228753Smm
55228753Smm# POD documentation
56228753Smm: <<=cut
57228753Smm=head1 NAME
58228753Smm
59228753Smmunbound_munin_ - Munin plugin to monitor the Unbound DNS resolver.
60228753Smm
61228753Smm=head1 APPLICABLE SYSTEMS
62228753Smm
63228753SmmSystem with unbound daemon.
64228753Smm
65228753Smm=head1 CONFIGURATION
66228753Smm
67228753Smm  [unbound*]
68228753Smm  user root
69228753Smm  env.statefile /usr/local/var/munin/plugin-state/unbound-state
70228753Smm  env.unbound_conf /usr/local/etc/unbound/unbound.conf
71228753Smm  env.unbound_control /usr/local/sbin/unbound-control
72228753Smm  env.spoof_warn 1000
73228753Smm  env.spoof_crit 100000
74228753Smm
75228753SmmUse the .env settings to override the defaults.
76228753Smm
77228753Smm=head1 USAGE
78228753Smm
79228753SmmCan be used to present different graphs. Use ln -s for that name in
80228753Smmthe plugins directory to enable the graph.
81228753Smmunbound_munin_hits	- base volume, cache hits, unwanted traffic
82228753Smmunbound_munin_queue	- to monitor the internal requestlist
83228753Smmunbound_munin_memory	- memory usage
84228753Smmunbound_munin_by_type	- incoming queries by type
85228753Smmunbound_munin_by_class	- incoming queries by class
86228753Smmunbound_munin_by_opcode	- incoming queries by opcode
87228753Smmunbound_munin_by_rcode	- answers by rcode, validation status
88228753Smmunbound_munin_by_flags	- incoming queries by flags
89228753Smmunbound_munin_histogram - histogram of query resolving times
90228753Smm
91228753Smm=head1 AUTHOR
92228753Smm
93228753SmmCopyright 2008 W.C.A. Wijngaards
94228753Smm
95228753Smm=head1 LICENSE
96228753Smm
97228753SmmBSD
98228753Smm
99228753Smm=cut
100228753Smm
101228753Smmstate=${statefile:-/usr/local/var/munin/plugin-state/unbound-state}
102228753Smmconf=${unbound_conf:-/usr/local/etc/unbound/unbound.conf}
103228753Smmctrl=${unbound_control:-/usr/local/sbin/unbound-control}
104228753Smmwarn=${spoof_warn:-1000}
105228753Smmcrit=${spoof_crit:-100000}
106228753Smmlock=$state.lock
107228753Smm
108228753Smm# number of seconds between polling attempts.
109228753Smm# makes the statefile hang around for at least this many seconds,
110228753Smm# so that multiple links of this script can share the results.
111228753Smmlee=55
112228753Smm
113228753Smm# to keep things within 19 characters
114228753SmmABBREV="-e s/total/t/ -e s/thread/t/ -e s/num/n/ -e s/query/q/ -e s/answer/a/ -e s/unwanted/u/ -e s/requestlist/ql/ -e s/type/t/ -e s/class/c/ -e s/opcode/o/ -e s/rcode/r/ -e s/edns/e/ -e s/mem/m/ -e s/cache/c/ -e s/mod/m/"
115228753Smm
116228753Smm# get value from $1 into return variable $value
117228753Smmget_value ( ) {
118228753Smm	value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`"
119228753Smm	if test "$value"x = ""x; then
120228753Smm		value="0"
121228753Smm	fi
122228753Smm}
123228753Smm
124228753Smm# download the state from the unbound server.
125228753Smmget_state ( ) {
126228753Smm	# obtain lock for fetching the state
127228753Smm	# because there is a race condition in fetching and writing to file
128228753Smm
129228753Smm	# see if the lock is stale, if so, take it 
130228753Smm	if test -f $lock ; then
131228753Smm		pid="`cat $lock 2>&1`"
132228753Smm		kill -0 "$pid" >/dev/null 2>&1
133228753Smm		if test $? -ne 0 -a "$pid" != $$ ; then
134228753Smm			echo $$ >$lock
135228753Smm		fi
136228753Smm	fi
137228753Smm
138228753Smm	i=0
139228753Smm	while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do
140228753Smm		while test -f $lock; do
141228753Smm			# wait
142228753Smm			i=`expr $i + 1`
143228753Smm			if test $i -gt 1000; then
144228753Smm				sleep 1;
145228753Smm			fi
146228753Smm			if test $i -gt 1500; then
147228753Smm				echo "error locking $lock" "=" `cat $lock`
148228753Smm				rm -f $lock
149228753Smm				exit 1
150228753Smm			fi
151228753Smm		done
152228753Smm		# try to get it
153228753Smm		if echo $$ >$lock ; then : ; else break; fi
154228753Smm	done
155228753Smm	# do not refetch if the file exists and only LEE seconds old
156228753Smm	if test -f $state; then
157228753Smm		now=`date +%s`
158228753Smm		get_value "time.now"
159228753Smm		value="`echo $value | sed -e 's/\..*$//'`"
160228753Smm		if test $now -lt `expr $value + $lee`; then
161228753Smm			rm -f $lock
162228753Smm			return
163228753Smm		fi
164228753Smm	fi
165228753Smm	$ctrl -c $conf stats > $state
166228753Smm	if test $? -ne 0; then
167228753Smm		echo "error retrieving data from unbound server"
168228753Smm		rm -f $lock
169228753Smm		exit 1
170228753Smm	fi
171228753Smm	rm -f $lock
172228753Smm}
173228753Smm
174228753Smmif test "$1" = "autoconf" ; then
175228753Smm	if test ! -f $conf; then
176228753Smm		echo no "($conf does not exist)"
177228753Smm		exit 1
178228753Smm	fi
179228753Smm	if test ! -d `dirname $state`; then
180228753Smm		echo no "(`dirname $state` directory does not exist)"
181228753Smm		exit 1
182228753Smm	fi
183228753Smm	echo yes
184228753Smm	exit 0
185228753Smmfi
186228753Smm
187228753Smmif test "$1" = "suggest" ; then
188228753Smm	echo "hits"
189228753Smm	echo "queue"
190228753Smm	echo "memory"
191228753Smm	echo "by_type"
192228753Smm	echo "by_class"
193228753Smm	echo "by_opcode"
194228753Smm	echo "by_rcode"
195228753Smm	echo "by_flags"
196228753Smm	echo "histogram"
197228753Smm	exit 0
198228753Smmfi
199228753Smm
200228753Smm# determine my type, by name
201228753Smmid=`echo $0 | sed -e 's/^.*unbound_munin_//'`
202228753Smmif test "$id"x = ""x; then
203228753Smm	# some default to keep people sane.
204228753Smm	id="hits"
205228753Smmfi
206228753Smm
207228753Smm# if $1 exists in statefile, config is echoed with label $2
208228753Smmexist_config ( ) {
209228753Smm	mn=`echo $1 | sed $ABBREV | tr . _`
210228753Smm	if grep '^'$1'=' $state >/dev/null 2>&1; then
211228753Smm		echo "$mn.label $2"
212228753Smm		echo "$mn.min 0"
213228753Smm		echo "$mn.type ABSOLUTE"
214228753Smm	fi
215228753Smm}
216228753Smm
217228753Smm# print label and min 0 for a name $1 in unbound format
218228753Smmp_config ( ) {
219228753Smm	mn=`echo $1 | sed $ABBREV | tr . _`
220228753Smm	echo $mn.label "$2"
221228753Smm	echo $mn.min 0
222228753Smm	echo $mn.type $3
223228753Smm}
224228753Smm
225228753Smmif test "$1" = "config" ; then
226228753Smm	if test ! -f $state; then
227228753Smm		get_state
228228753Smm	fi
229228753Smm	case $id in
230228753Smm	hits)
231228753Smm		echo "graph_title Unbound DNS traffic and cache hits"
232228753Smm		echo "graph_args --base 1000 -l 0"
233228753Smm		echo "graph_vlabel queries / \${graph_period}"
234228753Smm		echo "graph_scale no"
235228753Smm		echo "graph_category DNS"
236228753Smm		for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state |
237228753Smm			sed -e 's/=.*//'`; do
238228753Smm			exist_config $x "queries handled by `basename $x .num.queries`"
239228753Smm		done
240228753Smm		p_config "total.num.queries" "total queries from clients" "ABSOLUTE"
241228753Smm		p_config "total.num.cachehits" "cache hits" "ABSOLUTE"
242228753Smm		p_config "total.num.prefetch" "cache prefetch" "ABSOLUTE"
243228753Smm		p_config "num.query.tcp" "TCP queries" "ABSOLUTE"
244228753Smm		p_config "num.query.tcpout" "TCP out queries" "ABSOLUTE"
245228753Smm		p_config "num.query.ipv6" "IPv6 queries" "ABSOLUTE"
246228753Smm		p_config "unwanted.queries" "queries that failed acl" "ABSOLUTE"
247228753Smm		p_config "unwanted.replies" "unwanted or unsolicited replies" "ABSOLUTE"
248228753Smm		echo "u_replies.warning $warn"
249228753Smm		echo "u_replies.critical $crit"
250228753Smm		echo "graph_info DNS queries to the recursive resolver. The unwanted replies could be innocent duplicate packets, late replies, or spoof threats."
251228753Smm		;;
252228753Smm	queue)
253228753Smm		echo "graph_title Unbound requestlist size"
254228753Smm		echo "graph_args --base 1000 -l 0"
255228753Smm		echo "graph_vlabel number of queries"
256228753Smm		echo "graph_scale no"
257228753Smm		echo "graph_category DNS"
258228753Smm		p_config "total.requestlist.avg" "Average size of queue on insert" "GAUGE"
259228753Smm		p_config "total.requestlist.max" "Max size of queue (in 5 min)" "GAUGE"
260228753Smm		p_config "total.requestlist.overwritten" "Number of queries replaced by new ones" "GAUGE"
261228753Smm		p_config "total.requestlist.exceeded" "Number of queries dropped due to lack of space" "GAUGE"
262228753Smm		echo "graph_info The queries that did not hit the cache and need recursion service take up space in the requestlist. If there are too many queries, first queries get overwritten, and at last resort dropped."
263228753Smm		;;
264228753Smm	memory)
265228753Smm		echo "graph_title Unbound memory usage"
266228753Smm		echo "graph_args --base 1024 -l 0"
267228753Smm		echo "graph_vlabel memory used in bytes"
268228753Smm		echo "graph_category DNS"
269228753Smm		p_config "mem.cache.rrset" "RRset cache memory" "GAUGE"
270228753Smm		p_config "mem.cache.message" "Message cache memory" "GAUGE"
271228753Smm		p_config "mem.mod.iterator" "Iterator module memory" "GAUGE"
272228753Smm		p_config "mem.mod.validator" "Validator module and key cache memory" "GAUGE"
273228753Smm		p_config "msg.cache.count" "msg cache count" "GAUGE"
274228753Smm		p_config "rrset.cache.count" "rrset cache count" "GAUGE"
275228753Smm		p_config "infra.cache.count" "infra cache count" "GAUGE"
276228753Smm		p_config "key.cache.count" "key cache count" "GAUGE"
277228753Smm		echo "graph_info The memory used by unbound."
278228753Smm		;;
279228753Smm	by_type)
280228753Smm		echo "graph_title Unbound DNS queries by type"
281228753Smm		echo "graph_args --base 1000 -l 0"
282228753Smm		echo "graph_vlabel queries / \${graph_period}"
283228753Smm		echo "graph_scale no"
284228753Smm		echo "graph_category DNS"
285228753Smm		for x in `grep "^num.query.type" $state`; do
286228753Smm			nm=`echo $x | sed -e 's/=.*$//'`
287228753Smm			tp=`echo $nm | sed -e s/num.query.type.//`
288228753Smm			p_config "$nm" "$tp" "ABSOLUTE"
289228753Smm		done
290228753Smm		echo "graph_info queries by DNS RR type queried for"
291228753Smm		;;
292228753Smm	by_class)
293228753Smm		echo "graph_title Unbound DNS queries by class"
294228753Smm		echo "graph_args --base 1000 -l 0"
295228753Smm		echo "graph_vlabel queries / \${graph_period}"
296228753Smm		echo "graph_scale no"
297228753Smm		echo "graph_category DNS"
298228753Smm		for x in `grep "^num.query.class" $state`; do
299228753Smm			nm=`echo $x | sed -e 's/=.*$//'`
300228753Smm			tp=`echo $nm | sed -e s/num.query.class.//`
301228753Smm			p_config "$nm" "$tp" "ABSOLUTE"
302228753Smm		done
303228753Smm		echo "graph_info queries by DNS RR class queried for."
304228753Smm		;;
305228753Smm	by_opcode)
306228753Smm		echo "graph_title Unbound DNS queries by opcode"
307228753Smm		echo "graph_args --base 1000 -l 0"
308228753Smm		echo "graph_vlabel queries / \${graph_period}"
309228753Smm		echo "graph_scale no"
310228753Smm		echo "graph_category DNS"
311228753Smm		for x in `grep "^num.query.opcode" $state`; do
312228753Smm			nm=`echo $x | sed -e 's/=.*$//'`
313228753Smm			tp=`echo $nm | sed -e s/num.query.opcode.//`
314228753Smm			p_config "$nm" "$tp" "ABSOLUTE"
315228753Smm		done
316228753Smm		echo "graph_info queries by opcode in the query packet."
317228753Smm		;;
318228753Smm	by_rcode)
319228753Smm		echo "graph_title Unbound DNS answers by return code"
320228753Smm		echo "graph_args --base 1000 -l 0"
321228753Smm		echo "graph_vlabel answer packets / \${graph_period}"
322228753Smm		echo "graph_scale no"
323228753Smm		echo "graph_category DNS"
324228753Smm		for x in `grep "^num.answer.rcode" $state`; do
325228753Smm			nm=`echo $x | sed -e 's/=.*$//'`
326228753Smm			tp=`echo $nm | sed -e s/num.answer.rcode.//`
327228753Smm			p_config "$nm" "$tp" "ABSOLUTE"
328228753Smm		done
329228753Smm		p_config "num.answer.secure" "answer secure" "ABSOLUTE"
330228753Smm		p_config "num.answer.bogus" "answer bogus" "ABSOLUTE"
331228753Smm		p_config "num.rrset.bogus" "num rrsets marked bogus" "ABSOLUTE"
332228753Smm		echo "graph_info answers sorted by return value. rrsets bogus is the number of rrsets marked bogus per \${graph_period} by the validator"
333228753Smm		;;
334228753Smm	by_flags)
335228753Smm		echo "graph_title Unbound DNS incoming queries by flags"
336228753Smm		echo "graph_args --base 1000 -l 0"
337228753Smm		echo "graph_vlabel queries / \${graph_period}"
338228753Smm		echo "graph_scale no"
339228753Smm		echo "graph_category DNS"
340228753Smm		p_config "num.query.flags.QR" "QR (query reply) flag" "ABSOLUTE"
341228753Smm		p_config "num.query.flags.AA" "AA (auth answer) flag" "ABSOLUTE"
342228753Smm		p_config "num.query.flags.TC" "TC (truncated) flag" "ABSOLUTE"
343228753Smm		p_config "num.query.flags.RD" "RD (recursion desired) flag" "ABSOLUTE"
344228753Smm		p_config "num.query.flags.RA" "RA (rec avail) flag" "ABSOLUTE"
345228753Smm		p_config "num.query.flags.Z" "Z (zero) flag" "ABSOLUTE"
346228753Smm		p_config "num.query.flags.AD" "AD (auth data) flag" "ABSOLUTE"
347228753Smm		p_config "num.query.flags.CD" "CD (check disabled) flag" "ABSOLUTE"
348228753Smm		p_config "num.query.edns.present" "EDNS OPT present" "ABSOLUTE"
349228753Smm		p_config "num.query.edns.DO" "DO (DNSSEC OK) flag" "ABSOLUTE"
350228753Smm		echo "graph_info This graphs plots the flags inside incoming queries. For example, if QR, AA, TC, RA, Z flags are set, the query can be rejected. RD, AD, CD and DO are legitimately set by some software."
351228753Smm		;;
352228753Smm	histogram)
353228753Smm		echo "graph_title Unbound DNS histogram of reply time"
354228753Smm		echo "graph_args --base 1000 -l 0"
355228753Smm		echo "graph_vlabel queries / \${graph_period}"
356228753Smm		echo "graph_scale no"
357228753Smm		echo "graph_category DNS"
358228753Smm		echo hcache.label "cache hits"
359228753Smm		echo hcache.min 0
360228753Smm		echo hcache.type ABSOLUTE
361228753Smm		echo hcache.draw AREA
362228753Smm		echo hcache.colour 999999
363228753Smm		echo h64ms.label "0 msec - 66 msec"
364228753Smm		echo h64ms.min 0
365228753Smm		echo h64ms.type ABSOLUTE
366228753Smm		echo h64ms.draw STACK
367228753Smm		echo h64ms.colour 0000FF
368228753Smm		echo h128ms.label "66 msec - 131 msec"
369228753Smm		echo h128ms.min 0
370228753Smm		echo h128ms.type ABSOLUTE
371228753Smm		echo h128ms.colour 1F00DF
372228753Smm		echo h128ms.draw STACK
373228753Smm		echo h256ms.label "131 msec - 262 msec"
374228753Smm		echo h256ms.min 0
375228753Smm		echo h256ms.type ABSOLUTE
376228753Smm		echo h256ms.draw STACK
377228753Smm		echo h256ms.colour 3F00BF
378228753Smm		echo h512ms.label "262 msec - 524 msec"
379228753Smm		echo h512ms.min 0
380228753Smm		echo h512ms.type ABSOLUTE
381228753Smm		echo h512ms.draw STACK
382228753Smm		echo h512ms.colour 5F009F
383228753Smm		echo h1s.label "524 msec - 1 sec"
384228753Smm		echo h1s.min 0
385228753Smm		echo h1s.type ABSOLUTE
386228753Smm		echo h1s.draw STACK
387228753Smm		echo h1s.colour 7F007F
388228753Smm		echo h2s.label "1 sec - 2 sec"
389228753Smm		echo h2s.min 0
390228753Smm		echo h2s.type ABSOLUTE
391228753Smm		echo h2s.draw STACK
392228753Smm		echo h2s.colour 9F005F
393228753Smm		echo h4s.label "2 sec - 4 sec"
394228753Smm		echo h4s.min 0
395228753Smm		echo h4s.type ABSOLUTE
396228753Smm		echo h4s.draw STACK
397228753Smm		echo h4s.colour BF003F
398228753Smm		echo h8s.label "4 sec - 8 sec"
399228753Smm		echo h8s.min 0
400228753Smm		echo h8s.type ABSOLUTE
401228753Smm		echo h8s.draw STACK
402228753Smm		echo h8s.colour DF001F
403228753Smm		echo h16s.label "8 sec - ..."
404228753Smm		echo h16s.min 0
405228753Smm		echo h16s.type ABSOLUTE
406228753Smm		echo h16s.draw STACK
407228753Smm		echo h16s.colour FF0000
408228753Smm		echo "graph_info Histogram of the reply times for queries."
409228753Smm		;;
410228753Smm	esac
411228753Smm
412228753Smm	exit 0
413228753Smmfi
414228753Smm
415228753Smm# do the stats itself
416228753Smmget_state
417228753Smm
418228753Smm# get the time elapsed
419228753Smmget_value "time.elapsed"
420228753Smmif test $value = 0 || test $value = "0.000000"; then
421228753Smm	echo "error: time elapsed 0 or could not retrieve data"
422228753Smm	exit 1
423228753Smmfi
424228753Smmelapsed="$value"
425228753Smm
426228753Smm# print value for $1
427228753Smmprint_value ( ) {
428228753Smm	mn=`echo $1 | sed $ABBREV | tr . _`
429228753Smm	get_value $1
430228753Smm	echo "$mn.value" $value
431228753Smm}
432228753Smm
433228753Smm# print value if line already found in $2
434228753Smmprint_value_line ( ) {
435228753Smm	mn=`echo $1 | sed $ABBREV | tr . _`
436228753Smm	value="`echo $2 | sed -e 's/^.*=//'`"
437228753Smm	echo "$mn.value" $value
438228753Smm}
439228753Smm
440228753Smm
441228753Smmcase $id in
442228753Smmhits)
443228753Smm	for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state |
444228753Smm		sed -e 's/=.*//'` total.num.queries \
445228753Smm		total.num.cachehits total.num.prefetch num.query.tcp \
446228753Smm		num.query.tcpout num.query.ipv6 unwanted.queries \
447228753Smm		unwanted.replies; do
448228753Smm		if grep "^"$x"=" $state >/dev/null 2>&1; then
449228753Smm			print_value $x
450228753Smm		fi
451228753Smm	done
452228753Smm	;;
453228753Smmqueue)
454228753Smm	for x in total.requestlist.avg total.requestlist.max \
455228753Smm		total.requestlist.overwritten total.requestlist.exceeded; do
456228753Smm		print_value $x
457228753Smm	done
458228753Smm	;;
459228753Smmmemory)
460228753Smm	for x in mem.cache.rrset mem.cache.message mem.mod.iterator \
461228753Smm		mem.mod.validator msg.cache.count rrset.cache.count \
462228753Smm		infra.cache.count key.cache.count; do
463228753Smm		print_value $x
464228753Smm	done
465228753Smm	;;
466228753Smmby_type)
467228753Smm	for x in `grep "^num.query.type" $state`; do
468228753Smm		nm=`echo $x | sed -e 's/=.*$//'`
469228753Smm		print_value_line $nm $x
470228753Smm	done
471228753Smm	;;
472228753Smmby_class)
473228753Smm	for x in `grep "^num.query.class" $state`; do
474228753Smm		nm=`echo $x | sed -e 's/=.*$//'`
475228753Smm		print_value_line $nm $x
476228753Smm	done
477228753Smm	;;
478228753Smmby_opcode)
479228753Smm	for x in `grep "^num.query.opcode" $state`; do
480228753Smm		nm=`echo $x | sed -e 's/=.*$//'`
481228753Smm		print_value_line $nm $x
482228753Smm	done
483228753Smm	;;
484228753Smmby_rcode)
485228753Smm	for x in `grep "^num.answer.rcode" $state`; do
486228753Smm		nm=`echo $x | sed -e 's/=.*$//'`
487228753Smm		print_value_line $nm $x
488228753Smm	done
489228753Smm	print_value "num.answer.secure"
490228753Smm	print_value "num.answer.bogus"
491228753Smm	print_value "num.rrset.bogus"
492228753Smm	;;
493228753Smmby_flags)
494228753Smm	for x in num.query.flags.QR num.query.flags.AA num.query.flags.TC num.query.flags.RD num.query.flags.RA num.query.flags.Z num.query.flags.AD num.query.flags.CD num.query.edns.present num.query.edns.DO; do
495228753Smm		print_value $x
496228753Smm	done
497228753Smm	;;
498228753Smmhistogram)
499228753Smm	get_value total.num.cachehits
500228753Smm	echo hcache.value $value
501228753Smm	r=0
502228753Smm	for x in histogram.000000.000000.to.000000.000001 \
503228753Smm		histogram.000000.000001.to.000000.000002 \
504228753Smm		histogram.000000.000002.to.000000.000004 \
505228753Smm		histogram.000000.000004.to.000000.000008 \
506228753Smm		histogram.000000.000008.to.000000.000016 \
507228753Smm		histogram.000000.000016.to.000000.000032 \
508228753Smm		histogram.000000.000032.to.000000.000064 \
509228753Smm		histogram.000000.000064.to.000000.000128 \
510228753Smm		histogram.000000.000128.to.000000.000256 \
511228753Smm		histogram.000000.000256.to.000000.000512 \
512228753Smm		histogram.000000.000512.to.000000.001024 \
513228753Smm		histogram.000000.001024.to.000000.002048 \
514228753Smm		histogram.000000.002048.to.000000.004096 \
515228753Smm		histogram.000000.004096.to.000000.008192 \
516228753Smm		histogram.000000.008192.to.000000.016384 \
517228753Smm		histogram.000000.016384.to.000000.032768 \
518228753Smm		histogram.000000.032768.to.000000.065536; do
519228753Smm		get_value $x
520228753Smm		r=`expr $r + $value`
521228753Smm	done
522228753Smm	echo h64ms.value $r
523228753Smm	get_value histogram.000000.065536.to.000000.131072
524228753Smm	echo h128ms.value $value
525228753Smm	get_value histogram.000000.131072.to.000000.262144
526228753Smm	echo h256ms.value $value
527228753Smm	get_value histogram.000000.262144.to.000000.524288
528228753Smm	echo h512ms.value $value
529228753Smm	get_value histogram.000000.524288.to.000001.000000
530228753Smm	echo h1s.value $value
531228753Smm	get_value histogram.000001.000000.to.000002.000000
532228753Smm	echo h2s.value $value
533228753Smm	get_value histogram.000002.000000.to.000004.000000
534228753Smm	echo h4s.value $value
535228753Smm	get_value histogram.000004.000000.to.000008.000000
536228753Smm	echo h8s.value $value
537228753Smm	r=0
538228753Smm	for x in histogram.000008.000000.to.000016.000000 \
539228753Smm		histogram.000016.000000.to.000032.000000 \
540228753Smm		histogram.000032.000000.to.000064.000000 \
541228753Smm		histogram.000064.000000.to.000128.000000 \
542228753Smm		histogram.000128.000000.to.000256.000000 \
543228753Smm		histogram.000256.000000.to.000512.000000 \
544228753Smm		histogram.000512.000000.to.001024.000000 \
545228753Smm		histogram.001024.000000.to.002048.000000 \
546228753Smm		histogram.002048.000000.to.004096.000000 \
547228753Smm		histogram.004096.000000.to.008192.000000 \
548228753Smm		histogram.008192.000000.to.016384.000000 \
549228753Smm		histogram.016384.000000.to.032768.000000 \
550228753Smm		histogram.032768.000000.to.065536.000000 \
551228753Smm		histogram.065536.000000.to.131072.000000 \
552228753Smm		histogram.131072.000000.to.262144.000000 \
553228753Smm		histogram.262144.000000.to.524288.000000; do
554228753Smm		get_value $x
555228753Smm		r=`expr $r + $value`
556228753Smm	done
557228753Smm	echo h16s.value $r
558228753Smm	;;
559228753Smmesac
560228753Smm