5f4e7f
#!/bin/sh
5f4e7f
#
5f4e7f
# plugin for munin to monitor usage of unbound servers.
5f4e7f
#
5f4e7f
# (C) 2008 W.C.A. Wijngaards.  BSD Licensed.
5f4e7f
#
5f4e7f
# To install; enable statistics and unbound-control in unbound.conf
5f4e7f
#	server:		extended-statistics: yes
5f4e7f
#			statistics-cumulative: no
5f4e7f
#			statistics-interval: 0
5f4e7f
#	remote-control:	control-enable: yes
5f4e7f
# Run the command unbound-control-setup to generate the key files.
5f4e7f
#
5f4e7f
# Environment variables for this script
5f4e7f
#	statefile	- where to put temporary statefile.
5f4e7f
#	unbound_conf	- where the unbound.conf file is located.
5f4e7f
#	unbound_control	- where to find unbound-control executable.
5f4e7f
#	spoof_warn	- what level to warn about spoofing
5f4e7f
#	spoof_crit	- what level to crit about spoofing
5f4e7f
#
5f4e7f
# You can set them in your munin/plugin-conf.d/plugins.conf file
5f4e7f
# with:
5f4e7f
# [unbound*]
5f4e7f
# user root
5f4e7f
# env.statefile /usr/local/var/munin/plugin-state/unbound-state
5f4e7f
# env.unbound_conf /usr/local/etc/unbound/unbound.conf
5f4e7f
# env.unbound_control /usr/local/sbin/unbound-control
5f4e7f
# env.spoof_warn 1000
5f4e7f
# env.spoof_crit 100000
5f4e7f
#
5f4e7f
# This plugin can create different graphs depending on what name
5f4e7f
# you link it as (with ln -s) into the plugins directory
5f4e7f
# You can link it multiple times.
5f4e7f
# If you are only a casual user, the _hits and _by_type are most interesting,
5f4e7f
# possibly followed by _by_rcode.
5f4e7f
#
5f4e7f
#	unbound_munin_hits	- base volume, cache hits, unwanted traffic
5f4e7f
#	unbound_munin_queue	- to monitor the internal requestlist
5f4e7f
#	unbound_munin_memory	- memory usage
5f4e7f
#	unbound_munin_by_type	- incoming queries by type
5f4e7f
#	unbound_munin_by_class	- incoming queries by class
5f4e7f
#	unbound_munin_by_opcode	- incoming queries by opcode
5f4e7f
#	unbound_munin_by_rcode	- answers by rcode, validation status
5f4e7f
#	unbound_munin_by_flags	- incoming queries by flags
5f4e7f
#	unbound_munin_histogram	- histogram of query resolving times
5f4e7f
#
5f4e7f
# Magic markers - optional - used by installation scripts and
5f4e7f
# munin-config:
5f4e7f
#
5f4e7f
#%# family=contrib
5f4e7f
#%# capabilities=autoconf suggest
5f4e7f
5f4e7f
# POD documentation
5f4e7f
: <<=cut
5f4e7f
=head1 NAME
5f4e7f
5f4e7f
unbound_munin_ - Munin plugin to monitor the Unbound DNS resolver.
5f4e7f
5f4e7f
=head1 APPLICABLE SYSTEMS
5f4e7f
5f4e7f
System with unbound daemon.
5f4e7f
5f4e7f
=head1 CONFIGURATION
5f4e7f
5f4e7f
  [unbound*]
5f4e7f
  user root
5f4e7f
  env.statefile /var/lib/munin/plugin-state/unbound-state
5f4e7f
  env.unbound_conf /etc/unbound/unbound.conf
5f4e7f
  env.unbound_control /usr/sbin/unbound-control
5f4e7f
  env.spoof_warn 1000
5f4e7f
  env.spoof_crit 100000
5f4e7f
5f4e7f
Use the .env settings to override the defaults.
5f4e7f
5f4e7f
=head1 USAGE
5f4e7f
5f4e7f
Can be used to present different graphs. Use ln -s for that name in
5f4e7f
the plugins directory to enable the graph.
5f4e7f
unbound_munin_hits	- base volume, cache hits, unwanted traffic
5f4e7f
unbound_munin_queue	- to monitor the internal requestlist
5f4e7f
unbound_munin_memory	- memory usage
5f4e7f
unbound_munin_by_type	- incoming queries by type
5f4e7f
unbound_munin_by_class	- incoming queries by class
5f4e7f
unbound_munin_by_opcode	- incoming queries by opcode
5f4e7f
unbound_munin_by_rcode	- answers by rcode, validation status
5f4e7f
unbound_munin_by_flags	- incoming queries by flags
5f4e7f
unbound_munin_histogram - histogram of query resolving times
5f4e7f
5f4e7f
=head1 AUTHOR
5f4e7f
5f4e7f
Copyright 2008 W.C.A. Wijngaards
5f4e7f
5f4e7f
=head1 LICENSE
5f4e7f
5f4e7f
BSD
5f4e7f
5f4e7f
=cut
5f4e7f
5f4e7f
state=${statefile:-/var/lib/munin/plugin-state/unbound-state}
5f4e7f
conf=${unbound_conf:-/etc/unbound/unbound.conf}
5f4e7f
ctrl=${unbound_control:-/usr/sbin/unbound-control}
5f4e7f
warn=${spoof_warn:-1000}
5f4e7f
crit=${spoof_crit:-100000}
5f4e7f
lock=$state.lock
5f4e7f
5f4e7f
# number of seconds between polling attempts.
5f4e7f
# makes the statefile hang around for at least this many seconds,
5f4e7f
# so that multiple links of this script can share the results.
5f4e7f
lee=55
5f4e7f
5f4e7f
# to keep things within 19 characters
5f4e7f
ABBREV="-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/"
5f4e7f
5f4e7f
# get value from $1 into return variable $value
5f4e7f
get_value ( ) {
5f4e7f
	value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`"
5f4e7f
	if test "$value"x = ""x; then
5f4e7f
		value="0"
5f4e7f
	fi
5f4e7f
}
5f4e7f
5f4e7f
# download the state from the unbound server.
5f4e7f
get_state ( ) {
5f4e7f
	# obtain lock for fetching the state
5f4e7f
	# because there is a race condition in fetching and writing to file
5f4e7f
5f4e7f
	# see if the lock is stale, if so, take it 
5f4e7f
	if test -f $lock ; then
5f4e7f
		pid="`cat $lock 2>&1`"
5f4e7f
		kill -0 "$pid" >/dev/null 2>&1
5f4e7f
		if test $? -ne 0 -a "$pid" != $$ ; then
5f4e7f
			echo $$ >$lock
5f4e7f
		fi
5f4e7f
	fi
5f4e7f
5f4e7f
	i=0
5f4e7f
	while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do
5f4e7f
		while test -f $lock; do
5f4e7f
			# wait
5f4e7f
			i=`expr $i + 1`
5f4e7f
			if test $i -gt 1000; then
5f4e7f
				sleep 1;
5f4e7f
			fi
5f4e7f
			if test $i -gt 1500; then
5f4e7f
				echo "error locking $lock" "=" `cat $lock`
5f4e7f
				rm -f $lock
5f4e7f
				exit 1
5f4e7f
			fi
5f4e7f
		done
5f4e7f
		# try to get it
5f4e7f
		echo $$ >$lock
5f4e7f
	done
5f4e7f
	# do not refetch if the file exists and only LEE seconds old
5f4e7f
	if test -f $state; then
5f4e7f
		now=`date +%s`
5f4e7f
		get_value "time.now"
5f4e7f
		value="`echo $value | sed -e 's/\..*$//'`"
5f4e7f
		if test $now -lt `expr $value + $lee`; then
5f4e7f
			rm -f $lock
5f4e7f
			return
5f4e7f
		fi
5f4e7f
	fi
5f4e7f
	$ctrl -c $conf stats > $state
5f4e7f
	if test $? -ne 0; then
5f4e7f
		echo "error retrieving data from unbound server"
5f4e7f
		rm -f $lock
5f4e7f
		exit 1
5f4e7f
	fi
5f4e7f
	rm -f $lock
5f4e7f
}
5f4e7f
5f4e7f
if test "$1" = "autoconf" ; then
5f4e7f
	if test ! -f $conf; then
5f4e7f
		echo no "($conf does not exist)"
5f4e7f
		exit 1
5f4e7f
	fi
5f4e7f
	if test ! -d `dirname $state`; then
5f4e7f
		echo no "($state directory does not exist)"
5f4e7f
		exit 1
5f4e7f
	fi
5f4e7f
	echo yes
5f4e7f
	exit 0
5f4e7f
fi
5f4e7f
5f4e7f
if test "$1" = "suggest" ; then
5f4e7f
	echo "hits"
5f4e7f
	echo "queue"
5f4e7f
	echo "memory"
5f4e7f
	echo "by_type"
5f4e7f
	echo "by_class"
5f4e7f
	echo "by_opcode"
5f4e7f
	echo "by_rcode"
5f4e7f
	echo "by_flags"
5f4e7f
	echo "histogram"
5f4e7f
	exit 0
5f4e7f
fi
5f4e7f
5f4e7f
# determine my type, by name
5f4e7f
id=`echo $0 | sed -e 's/^.*unbound_munin_//'`
5f4e7f
if test "$id"x = ""x; then
5f4e7f
	# some default to keep people sane.
5f4e7f
	id="hits"
5f4e7f
fi
5f4e7f
5f4e7f
# if $1 exists in statefile, config is echoed with label $2
5f4e7f
exist_config ( ) {
5f4e7f
	mn=`echo $1 | sed $ABBREV | tr . _`
5f4e7f
	if grep '^'$1'=' $state >/dev/null 2>&1; then
5f4e7f
		echo "$mn.label $2"
5f4e7f
		echo "$mn.min 0"
5f4e7f
	fi
5f4e7f
}
5f4e7f
5f4e7f
# print label and min 0 for a name $1 in unbound format
5f4e7f
p_config ( ) {
5f4e7f
	mn=`echo $1 | sed $ABBREV | tr . _`
5f4e7f
	echo $mn.label "$2"
5f4e7f
	echo $mn.min 0
5f4e7f
}
5f4e7f
5f4e7f
if test "$1" = "config" ; then
5f4e7f
	if test ! -f $state; then
5f4e7f
		get_state
5f4e7f
	fi
5f4e7f
	case $id in
5f4e7f
	hits)
5f4e7f
		echo "graph_title Unbound DNS traffic and cache hits"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		for x in thread0.num.queries thread1.num.queries \
5f4e7f
		thread2.num.queries thread3.num.queries thread4.num.queries \
5f4e7f
		thread5.num.queries thread6.num.queries thread7.num.queries; do
5f4e7f
			exist_config $x "queries handled by `basename $x .num.queries`"
5f4e7f
		done
5f4e7f
		p_config "total.num.queries" "total queries from clients"
5f4e7f
		p_config "total.num.cachehits" "cache hits"
5f4e7f
		p_config "total.num.prefetch" "cache prefetch"
5f4e7f
		p_config "num.query.tcp" "TCP queries"
5f4e7f
		p_config "num.query.ipv6" "IPv6 queries"
5f4e7f
		p_config "unwanted.queries" "queries that failed acl"
5f4e7f
		p_config "unwanted.replies" "unwanted or unsolicited replies"
5f4e7f
		echo "u_replies.warning $warn"
5f4e7f
		echo "u_replies.critical $crit"
5f4e7f
		echo "graph_info DNS queries to the recursive resolver. The unwanted replies could be innocent duplicate packets, late replies, or spoof threats."
5f4e7f
		;;
5f4e7f
	queue)
5f4e7f
		echo "graph_title Unbound requestlist size"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel number of queries"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		p_config "total.requestlist.avg" "Average size of queue on insert"
5f4e7f
		p_config "total.requestlist.max" "Max size of queue (in 5 min)"
5f4e7f
		p_config "total.requestlist.overwritten" "Number of queries replaced by new ones"
5f4e7f
		p_config "total.requestlist.exceeded" "Number of queries dropped due to lack of space"
5f4e7f
		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."
5f4e7f
		;;
5f4e7f
	memory)
5f4e7f
		echo "graph_title Unbound memory usage"
5f4e7f
		echo "graph_args --base 1024 -l 0"
5f4e7f
		echo "graph_vlabel memory used in bytes"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		p_config "mem.total.sbrk" "Total memory"
5f4e7f
		p_config "mem.cache.rrset" "RRset cache memory"
5f4e7f
		p_config "mem.cache.message" "Message cache memory"
5f4e7f
		p_config "mem.mod.iterator" "Iterator module memory"
5f4e7f
		p_config "mem.mod.validator" "Validator module and key cache memory"
5f4e7f
		echo "graph_info The memory used by unbound."
5f4e7f
		;;
5f4e7f
	by_type)
5f4e7f
		echo "graph_title Unbound DNS queries by type"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		for x in `grep "^num.query.type" $state`; do
5f4e7f
			nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
			tp=`echo $nm | sed -e s/num.query.type.//`
5f4e7f
			p_config "$nm" "$tp"
5f4e7f
		done
5f4e7f
		echo "graph_info queries by DNS RR type queried for"
5f4e7f
		;;
5f4e7f
	by_class)
5f4e7f
		echo "graph_title Unbound DNS queries by class"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		for x in `grep "^num.query.class" $state`; do
5f4e7f
			nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
			tp=`echo $nm | sed -e s/num.query.class.//`
5f4e7f
			p_config "$nm" "$tp"
5f4e7f
		done
5f4e7f
		echo "graph_info queries by DNS RR class queried for."
5f4e7f
		;;
5f4e7f
	by_opcode)
5f4e7f
		echo "graph_title Unbound DNS queries by opcode"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		for x in `grep "^num.query.opcode" $state`; do
5f4e7f
			nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
			tp=`echo $nm | sed -e s/num.query.opcode.//`
5f4e7f
			p_config "$nm" "$tp"
5f4e7f
		done
5f4e7f
		echo "graph_info queries by opcode in the query packet."
5f4e7f
		;;
5f4e7f
	by_rcode)
5f4e7f
		echo "graph_title Unbound DNS answers by return code"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel answer packets / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		for x in `grep "^num.answer.rcode" $state`; do
5f4e7f
			nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
			tp=`echo $nm | sed -e s/num.answer.rcode.//`
5f4e7f
			p_config "$nm" "$tp"
5f4e7f
		done
5f4e7f
		p_config "num.answer.secure" "answer secure"
5f4e7f
		p_config "num.answer.bogus" "answer bogus"
5f4e7f
		p_config "num.rrset.bogus" "num rrsets marked bogus"
5f4e7f
		echo "graph_info answers sorted by return value. rrsets bogus is the number of rrsets marked bogus per second by the validator"
5f4e7f
		;;
5f4e7f
	by_flags)
5f4e7f
		echo "graph_title Unbound DNS incoming queries by flags"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		p_config "num.query.flags.QR" "QR (query reply) flag"
5f4e7f
		p_config "num.query.flags.AA" "AA (auth answer) flag"
5f4e7f
		p_config "num.query.flags.TC" "TC (truncated) flag"
5f4e7f
		p_config "num.query.flags.RD" "RD (recursion desired) flag"
5f4e7f
		p_config "num.query.flags.RA" "RA (rec avail) flag"
5f4e7f
		p_config "num.query.flags.Z" "Z (zero) flag"
5f4e7f
		p_config "num.query.flags.AD" "AD (auth data) flag"
5f4e7f
		p_config "num.query.flags.CD" "CD (check disabled) flag"
5f4e7f
		p_config "num.query.edns.present" "EDNS OPT present"
5f4e7f
		p_config "num.query.edns.DO" "DO (DNSSEC OK) flag"
5f4e7f
		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."
5f4e7f
		;;
5f4e7f
	histogram)
5f4e7f
		echo "graph_title Unbound DNS histogram of reply time"
5f4e7f
		echo "graph_args --base 1000 -l 0"
5f4e7f
		echo "graph_vlabel queries / second"
5f4e7f
		echo "graph_category DNS"
5f4e7f
		echo hcache.label "cache hits"
5f4e7f
		echo hcache.min 0
5f4e7f
		echo hcache.draw AREA
5f4e7f
		echo hcache.colour 999999
5f4e7f
		echo h64ms.label "0 msec - 66 msec"
5f4e7f
		echo h64ms.min 0
5f4e7f
		echo h64ms.draw STACK
5f4e7f
		echo h64ms.colour 0000FF
5f4e7f
		echo h128ms.label "66 msec - 131 msec"
5f4e7f
		echo h128ms.min 0
5f4e7f
		echo h128ms.colour 1F00DF
5f4e7f
		echo h128ms.draw STACK
5f4e7f
		echo h256ms.label "131 msec - 262 msec"
5f4e7f
		echo h256ms.min 0
5f4e7f
		echo h256ms.draw STACK
5f4e7f
		echo h256ms.colour 3F00BF
5f4e7f
		echo h512ms.label "262 msec - 524 msec"
5f4e7f
		echo h512ms.min 0
5f4e7f
		echo h512ms.draw STACK
5f4e7f
		echo h512ms.colour 5F009F
5f4e7f
		echo h1s.label "524 msec - 1 sec"
5f4e7f
		echo h1s.min 0
5f4e7f
		echo h1s.draw STACK
5f4e7f
		echo h1s.colour 7F007F
5f4e7f
		echo h2s.label "1 sec - 2 sec"
5f4e7f
		echo h2s.min 0
5f4e7f
		echo h2s.draw STACK
5f4e7f
		echo h2s.colour 9F005F
5f4e7f
		echo h4s.label "2 sec - 4 sec"
5f4e7f
		echo h4s.min 0
5f4e7f
		echo h4s.draw STACK
5f4e7f
		echo h4s.colour BF003F
5f4e7f
		echo h8s.label "4 sec - 8 sec"
5f4e7f
		echo h8s.min 0
5f4e7f
		echo h8s.draw STACK
5f4e7f
		echo h8s.colour DF001F
5f4e7f
		echo h16s.label "8 sec - ..."
5f4e7f
		echo h16s.min 0
5f4e7f
		echo h16s.draw STACK
5f4e7f
		echo h16s.colour FF0000
5f4e7f
		echo "graph_info Histogram of the reply times for queries."
5f4e7f
		;;
5f4e7f
	esac
5f4e7f
5f4e7f
	exit 0
5f4e7f
fi
5f4e7f
5f4e7f
# do the stats itself
5f4e7f
get_state
5f4e7f
5f4e7f
# get the time elapsed
5f4e7f
get_value "time.elapsed"
5f4e7f
if test $value = 0 || test $value = "0.000000"; then
5f4e7f
	echo "error: time elapsed 0 or could not retrieve data"
5f4e7f
	exit 1
5f4e7f
fi
5f4e7f
elapsed="$value"
5f4e7f
5f4e7f
# print value for $1 / elapsed
5f4e7f
print_qps ( ) {
5f4e7f
	mn=`echo $1 | sed $ABBREV | tr . _`
5f4e7f
	get_value $1
5f4e7f
	echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
5f4e7f
}
5f4e7f
5f4e7f
# print qps if line already found in $2
5f4e7f
print_qps_line ( ) {
5f4e7f
	mn=`echo $1 | sed $ABBREV | tr . _`
5f4e7f
	value="`echo $2 | sed -e 's/^.*=//'`"
5f4e7f
	echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
5f4e7f
}
5f4e7f
5f4e7f
# print value for $1
5f4e7f
print_value ( ) {
5f4e7f
	mn=`echo $1 | sed $ABBREV | tr . _`
5f4e7f
	get_value $1
5f4e7f
	echo "$mn.value" $value
5f4e7f
}
5f4e7f
5f4e7f
case $id in
5f4e7f
hits)
5f4e7f
	for x in thread0.num.queries thread1.num.queries thread2.num.queries \
5f4e7f
		thread3.num.queries thread4.num.queries thread5.num.queries \
5f4e7f
		thread6.num.queries thread7.num.queries total.num.queries \
5f4e7f
		total.num.cachehits total.num.prefetch num.query.tcp \
5f4e7f
		num.query.ipv6 unwanted.queries unwanted.replies; do
5f4e7f
		if grep "^"$x"=" $state >/dev/null 2>&1; then
5f4e7f
			print_qps $x
5f4e7f
		fi
5f4e7f
	done
5f4e7f
	;;
5f4e7f
queue)
5f4e7f
	for x in total.requestlist.avg total.requestlist.max \
5f4e7f
		total.requestlist.overwritten total.requestlist.exceeded; do
5f4e7f
		print_value $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
memory)
5f4e7f
	mn=`echo mem.total.sbrk | sed $ABBREV | tr . _`
5f4e7f
	get_value 'mem.total.sbrk'
5f4e7f
	if test $value -eq 0; then
5f4e7f
		chk=`echo $ctrl | sed -e 's/-control$/-checkconf/'`
5f4e7f
		pidf=`$chk -o pidfile $conf 2>&1`
5f4e7f
		pid=`cat $pidf 2>&1`
5f4e7f
		value=`ps -p "$pid" -o rss= 2>&1`
5f4e7f
		if test "`expr $value + 1 - 1 2>&1`" -eq "$value" 2>&1; then
5f4e7f
			value=`expr $value \* 1024` 
5f4e7f
		else
5f4e7f
			value=0
5f4e7f
		fi
5f4e7f
	fi
5f4e7f
	echo "$mn.value" $value
5f4e7f
	for x in mem.cache.rrset mem.cache.message \
5f4e7f
		mem.mod.iterator mem.mod.validator; do
5f4e7f
		print_value $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
by_type)
5f4e7f
	for x in `grep "^num.query.type" $state`; do
5f4e7f
		nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
		print_qps_line $nm $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
by_class)
5f4e7f
	for x in `grep "^num.query.class" $state`; do
5f4e7f
		nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
		print_qps_line $nm $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
by_opcode)
5f4e7f
	for x in `grep "^num.query.opcode" $state`; do
5f4e7f
		nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
		print_qps_line $nm $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
by_rcode)
5f4e7f
	for x in `grep "^num.answer.rcode" $state`; do
5f4e7f
		nm=`echo $x | sed -e 's/=.*$//'`
5f4e7f
		print_qps_line $nm $x
5f4e7f
	done
5f4e7f
	print_qps "num.answer.secure"
5f4e7f
	print_qps "num.answer.bogus"
5f4e7f
	print_qps "num.rrset.bogus"
5f4e7f
	;;
5f4e7f
by_flags)
5f4e7f
	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
5f4e7f
		print_qps $x
5f4e7f
	done
5f4e7f
	;;
5f4e7f
histogram)
5f4e7f
	get_value total.num.cachehits
5f4e7f
	echo hcache.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	r=0
5f4e7f
	for x in histogram.000000.000000.to.000000.000001 \
5f4e7f
		histogram.000000.000001.to.000000.000002 \
5f4e7f
		histogram.000000.000002.to.000000.000004 \
5f4e7f
		histogram.000000.000004.to.000000.000008 \
5f4e7f
		histogram.000000.000008.to.000000.000016 \
5f4e7f
		histogram.000000.000016.to.000000.000032 \
5f4e7f
		histogram.000000.000032.to.000000.000064 \
5f4e7f
		histogram.000000.000064.to.000000.000128 \
5f4e7f
		histogram.000000.000128.to.000000.000256 \
5f4e7f
		histogram.000000.000256.to.000000.000512 \
5f4e7f
		histogram.000000.000512.to.000000.001024 \
5f4e7f
		histogram.000000.001024.to.000000.002048 \
5f4e7f
		histogram.000000.002048.to.000000.004096 \
5f4e7f
		histogram.000000.004096.to.000000.008192 \
5f4e7f
		histogram.000000.008192.to.000000.016384 \
5f4e7f
		histogram.000000.016384.to.000000.032768 \
5f4e7f
		histogram.000000.032768.to.000000.065536; do
5f4e7f
		get_value $x
5f4e7f
		r=`expr $r + $value`
5f4e7f
	done
5f4e7f
	echo h64ms.value `echo scale=6';' $r / $elapsed | bc `
5f4e7f
	get_value histogram.000000.065536.to.000000.131072
5f4e7f
	echo h128ms.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000000.131072.to.000000.262144
5f4e7f
	echo h256ms.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000000.262144.to.000000.524288
5f4e7f
	echo h512ms.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000000.524288.to.000001.000000
5f4e7f
	echo h1s.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000001.000000.to.000002.000000
5f4e7f
	echo h2s.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000002.000000.to.000004.000000
5f4e7f
	echo h4s.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	get_value histogram.000004.000000.to.000008.000000
5f4e7f
	echo h8s.value `echo scale=6';' $value / $elapsed | bc `
5f4e7f
	r=0
5f4e7f
	for x in histogram.000008.000000.to.000016.000000 \
5f4e7f
		histogram.000016.000000.to.000032.000000 \
5f4e7f
		histogram.000032.000000.to.000064.000000 \
5f4e7f
		histogram.000064.000000.to.000128.000000 \
5f4e7f
		histogram.000128.000000.to.000256.000000 \
5f4e7f
		histogram.000256.000000.to.000512.000000 \
5f4e7f
		histogram.000512.000000.to.001024.000000 \
5f4e7f
		histogram.001024.000000.to.002048.000000 \
5f4e7f
		histogram.002048.000000.to.004096.000000 \
5f4e7f
		histogram.004096.000000.to.008192.000000 \
5f4e7f
		histogram.008192.000000.to.016384.000000 \
5f4e7f
		histogram.016384.000000.to.032768.000000 \
5f4e7f
		histogram.032768.000000.to.065536.000000 \
5f4e7f
		histogram.065536.000000.to.131072.000000 \
5f4e7f
		histogram.131072.000000.to.262144.000000 \
5f4e7f
		histogram.262144.000000.to.524288.000000; do
5f4e7f
		get_value $x
5f4e7f
		r=`expr $r + $value`
5f4e7f
	done
5f4e7f
	echo h16s.value `echo scale=6';' $r / $elapsed | bc `
5f4e7f
	;;
5f4e7f
esac