Repository
Munin (contrib)
Last change
2021-06-08
Graph Categories
Family
auto
Capabilities
Keywords
Language
Shell
License
GPL-3.0-or-later
Authors

upnpc_

Name

upnpc_ - Plugin to monitor routers via UPnP

This plugin uses the upnpc utility (package miniupnpc in Debian), to monitor an router using UPnP. It can monitor the following aspects, and plot them as separate graphs, or a single multigraph (if linked at upnpc or upnpc_multi: * uptime: how long the link has been up; * bitrate: the up and downlink bitrate (e.g., sync speed for DSL); * traffic: the actual up and downstream traffic rate; * pkts: the number of packets coming in and out.

Applicable Systems

Linux systems with upnpc installed (miniupnpc package).

Configuration

If you do not want to show the link maximum bitrates, add the following plugin-configuration:

[upnpc*]
  env.traffic_remove_max true

You can display the graph on another host (e.g., the actual router) than the one running upnpc. To do so, first configure the plugin to use a different hostname.

env.host_name router

Then configure munin (in /etc/munin/munin-conf or /etc/munin/munin-conf.d), to support a new host.

[example.net;router]
  address 127.0.0.1
  use_node_name no

Author

Olivier Mehani

Copyright (C) 2016–2021 Olivier Mehani <shtrom+munin@ssji.net>

License

SPDX-License-Identifier: GPL-3.0-or-later

Magic Markers

#%# family=auto
#%# capabilities=autoconf suggest
#!/bin/sh -u
# -*- sh -*-

: << =cut

=head1 NAME

upnpc_ - Plugin to monitor routers via UPnP

This plugin uses the upnpc utility (package miniupnpc in Debian), to monitor an
router using UPnP. It can monitor the following aspects, and plot them as
separate graphs, or a single multigraph (if linked at upnpc or upnpc_multi:
* uptime: how long the link has been up;
* bitrate: the up and downlink bitrate (e.g., sync speed for DSL);
* traffic: the actual up and downstream traffic rate;
* pkts: the number of packets coming in and out.

=head1 APPLICABLE SYSTEMS

Linux systems with upnpc installed (miniupnpc package).

=head1 CONFIGURATION

If you do not want to show the link maximum bitrates, add the following
plugin-configuration:

  [upnpc*]
    env.traffic_remove_max true

You can display the graph on another host (e.g., the actual router) than the
one running upnpc. To do so, first configure the plugin to use a different
hostname.

    env.host_name router

Then configure munin (in /etc/munin/munin-conf or /etc/munin/munin-conf.d), to
support a new host.

  [example.net;router]
    address 127.0.0.1
    use_node_name no

=head1 AUTHOR

Olivier Mehani

Copyright (C) 2016--2021 Olivier Mehani <shtrom+munin@ssji.net>

=head1 LICENSE

SPDX-License-Identifier: GPL-3.0-or-later

=head1 MAGIC MARKERS

 #%# family=auto
 #%# capabilities=autoconf suggest

=cut

if [ "${MUNIN_DEBUG:-0}" = 1 ]; then
    set -x
fi

PLUGIN_NAME="$(basename "${0}")"
MODE="$(echo "${PLUGIN_NAME}" | sed 's/.*_//')"
# If called without a mode, default to multigraph
[ "$MODE" = "upnpc" ] && MODE="multi"

get_data() {
	if ! command -v upnpc >/dev/null; then
		echo "upnpc not found (miniupnpc package)" >&2
		exit 1
	fi

	upnpc -s
}

get_supported_modes() {
	DATA=$1
	echo "${DATA}" | sed -n " \
		s/.*Bytes.*/traffic/p; \
		s/.*Packets.*/pkts/p; \
		s/.*uptime=.*/uptime/p; \
		"
}

autoconf() {
	if ! command -v upnpc >/dev/null; then
		echo "no (upnpc not found [miniupnpc package])"
		return
	fi
	upnpc -s 2>/dev/null | grep -q 'List.*devices.*found' && echo yes \
		|| echo "no (No UPnP router detected)"
}


suggest () {
	for mode in ${SUPPORTED_MODES}; do
		echo "${mode}"
	done
	echo "multi"
}

config () {
	case ${1} in
		"uptime")
			cat << EOF
graph_title Uplink connection uptime${HOST_TITLE}
graph_args -l 0
graph_category network
graph_scale no
graph_vlabel uptime in hours
uptime.label uptime
uptime.draw AREA
uptime.cdef uptime,3600,/
${HOST_NAME}
EOF
			;;
		"bitrate")
			cat << EOF
graph_title [DEPRECATED] Uplink bitrate${HOST_TITLE}
graph_args --base 1000 -l 0
graph_category network
graph_vlabel bitrate down (-) / up (+)
down.label bps
up.label bps
down.graph no
up.negative down
${HOST_NAME}
EOF
			;;
		"root")
			cat << EOF
graph_title Uplink traffic${HOST_TITLE}
graph_args --base 1000 -l 0
graph_category network
graph_vlabel bits per second in (-) / out (+)
EOF
			graph_order="down=traffic.down up=traffic.up"
			if [ "${traffic_remove_max:-false}" != 'true' ]; then
				graph_order="${graph_order} maxdown=traffic.maxdown maxup=traffic.maxup"
			fi
			echo "graph_order ${graph_order}"
			if [ "${traffic_remove_max:-false}" != 'true' ]; then
				cat << EOF
maxdown.label bps (max)
maxup.label bps (max)
maxdown.graph no
maxup.negative maxdown
EOF
			fi
			cat << EOF
down.label bps
down.cdef down,8,*
down.graph no
up.label bps
up.cdef up,8,*
up.negative down
${HOST_NAME}
EOF
			;;
		"traffic")
			cat << EOF
graph_title Uplink traffic${HOST_TITLE}
graph_args --base 1000 -l 0
graph_category network
graph_vlabel bits per second in (-) / out (+)
EOF
			if [ "${traffic_remove_max:-false}" != 'true' ]; then
				cat << EOF
maxdown.label bps (max)
maxup.label bps (max)
maxdown.graph no
maxup.negative maxdown
EOF
			fi
			cat << EOF
down.label bps
down.type DERIVE
down.min 0
down.cdef down,8,*
up.label bps
up.type DERIVE
up.min 0
up.cdef up,8,*
down.graph no
up.negative down
${HOST_NAME}
EOF
			;;
		"pkts")
			# ${graph_period} is not a shell variable
			cat << EOF
graph_title Uplink packets${HOST_TITLE}
graph_args --base 1000 -l 0
graph_category network
EOF
			# ${graph_period} is not a shell variable
			# shellcheck disable=SC2016
			echo 'graph_vlabel packets in (-) / out (+) per ${graph_period}'
			cat << EOF
down.label pps
down.type DERIVE
down.min 0
up.label pps
up.type DERIVE
up.min 0
down.graph no
up.negative down
${HOST_NAME}
EOF
			;;
		"multi")
			echo "${HOST_NAME}"
			# Don't repeat HOST_NAME in sub-configs
			HOST_NAME=""
			for mode in ${SUPPORTED_MODES}; do
				echo "multigraph ${PLUGIN_NAME}.${mode}"
				config "${mode}"
			done
			echo "multigraph ${PLUGIN_NAME}"
			config "root"
			;;
		*)
			echo "unknown mode '${1}'" >&2
			exit 1
			;;
	esac
}

fetch () {
	case "${1}" in
		"uptime")
		echo "${DATA}" | sed -n "s/.*uptime=\([0-9]\+\)s.*/uptime.value \1/p"
			;;
		"bitrate")
		echo "${DATA}" | sed -n "s/^MaxBitRateDown : \([0-9]\+\) bps.*MaxBitRateUp \([0-9]\+\) bps.*/down.value \1\nup.value \2/p"
			;;
		"root")
			# Nothing to do: all values loaned from the traffic graph
			;;
		"traffic")
		echo "${DATA}" | sed -n "
		s/^Bytes:\s*Sent:\s*\([0-9]\+\).*Recv:\s*\([0-9]\+\).*/up.value \1\ndown.value \2/p"
		if [ "${traffic_remove_max:-false}" != 'true' ]; then
			echo "${DATA}" | sed -n "
			s/^MaxBitRateDown : \([0-9]\+\) bps.*MaxBitRateUp \([0-9]\+\) bps.*/maxdown.value \1\nmaxup.value \2/p"
		fi
			;;
		"pkts")
		echo "${DATA}" | sed -n "s/^Packets:\s*Sent:\s*\([0-9]\+\).*Recv:\s*\([0-9]\+\).*/up.value \1\ndown.value \2/p"
			;;
		"multi"|"upnpc")
			for mode in ${SUPPORTED_MODES}; do
				echo "multigraph ${PLUGIN_NAME}.${mode}"
				fetch "${mode}"
			done
			echo "multigraph ${PLUGIN_NAME}"
			fetch "root"
			;;
		*)
			echo "unknown mode '${1}'" >&2
			exit 1
			;;
	esac
}

if [ "${1:-}" = "autoconf" ]; then
	autoconf
	exit 0
fi

# do data-based detection here, rather than in
# config() as we don't want to do this multiple times
# when the function calls itself for multigraphs
DATA=$(get_data)
SUPPORTED_MODES=$(get_supported_modes "${DATA}")

HOST=${host_name:-}
HOST_TITLE=""
HOST_NAME="host_name ${HOST}"
if [ -z "${HOST}" ]; then
	HOST=$(echo "${DATA}" | sed -n "s#.*desc: http://\([^/:]\+\).*#\1#p")
	# Only add the host name to the title if autodetected
	HOST_TITLE=" ($HOST)"
	# ...but not as a separate host
	HOST_NAME=""
fi

case ${1:-} in
	"suggest")
		suggest
		;;
	"config")
		config "${MODE}"
		if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = "1" ]; then
			fetch "${MODE}"
		fi
		;;
	*)
		fetch "${MODE}"
		;;
esac