diff --git a/plugins/network/olsrd b/plugins/network/olsrd new file mode 100755 index 00000000..5fcfedba --- /dev/null +++ b/plugins/network/olsrd @@ -0,0 +1,348 @@ +#!/bin/sh +# weird shebang? See below: "interpreter selection" +# +# Collect basic information about the neighbours of an OLSR node: +# * link quality +# * neighbour link quality +# * number of nodes reachable behind each neighbour +# * ping times of direct neighbours +# +# This plugin works with the following python interpreters: +# * Python 2 +# * Python 3 +# * micropython +# +# Environment variables: +# * OLSRD_HOST: name or IP of the host running the txtinfo plugin (default: localhost) +# * OLSRD_TXTINFO_PORT: the port that the txtinfo plugin is listening to (default: 2006) +# * OLSRD_BIN_PATH: name of the olsrd binary (only used for 'autoconf', defaults to /usr/sbin/olsrd) +# * MICROPYTHON_HEAP: adjust this parameter for micropython if your olsr network contains +# more than a few thousand nodes (default: 512k) +# +# +# Copyright (C) 2015 Lars Kruse +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Magic markers +#%# capabilities=autoconf +#%# family=auto + +"""true" +# ****************** Interpreter Selection *************** +# This unbelievable dirty hack allows to find a suitable python interpreter. +# This is specifically useful for OpenWRT where typically only micropython is available. +# +# Additionally we need to run micropython with additional startup options. +# This is necessary due to our demand for more than 128k heap (this default is sufficient for only 400 olsr nodes). +# +# This "execution hack" works as follows: +# * the script is executed by busybox ash or another shell +# * the above line (three quotes before and one quote after 'true') evaluates differently for shell and python: +# * shell: run "true" (i.e. nothing happens) +# * python: ignore everything up to the next three consecutive quotes +# Thus we may place shell code here that will take care for selecting an interpreter. + +# prefer micropython if it is available - otherwise fall back to any python (2 or 3) +if which micropython >/dev/null; then + /usr/bin/micropython -X "heapsize=${MICROPYTHON_HEAP:-512k}" "$0" "$@" +else + python "$0" "$@" +fi +exit $? + +# For shell: ignore everything starting from here until the last line of this file. +# This is necessary for syntax checkers that try to complain about invalid shell syntax below. +true < 1: + host = tokens[0] + avg_ping = tokens[-2].split("/")[1] + result[host] = float(avg_ping) + return result + + +if __name__ == "__main__": + # parse arguments + if len(sys.argv) > 1: + if sys.argv[1]=="config": + links = list(get_olsr_links()) + + # link quality with regard to neighbours + print("multigraph olsr_link_quality") + print(LQ_GRAPH_CONFIG.format(title="OLSR Link Quality")) + is_first = True + for link in links: + print(LQ_VALUES_CONFIG.format(label=link["remote"], + suffix="_{host}".format(host=get_clean_fieldname(link["remote"])), + draw_type=("AREA" if is_first else "STACK"))) + is_first = False + is_first = True + for link in links: + print("multigraph olsr_link_quality.host_{remote}".format(remote=get_clean_fieldname(link["remote"]))) + print(LQ_GRAPH_CONFIG.format(title="Link Quality towards {host}".format(host=link["remote"]))) + print(LQ_VALUES_CONFIG.format(label="Link Quality", suffix="", draw_type="AREA")) + is_first = False + + # link count ("number of nodes behind each neighbour") + print("multigraph olsr_neighbour_link_count") + print(NEIGHBOUR_COUNT_CONFIG) + is_first = True + for link in links: + print(NEIGHBOUR_COUNT_VALUE + .format(host=link["remote"], + host_fieldname=get_clean_fieldname(link["remote"]), + draw_type=("AREA" if is_first else "STACK"))) + is_first = False + + # neighbour ping + print("multigraph olsr_neighbour_ping") + print(NEIGHBOUR_PING_CONFIG.format(title="Ping time of neighbours")) + for link in links: + print(NEIGHBOUR_PING_VALUE + .format(host=link["remote"], + host_fieldname=get_clean_fieldname(link["remote"]))) + # neighbour pings - single subgraphs + for link in links: + remote = get_clean_fieldname(link["remote"]) + print("multigraph olsr_neighbour_ping.host_{remote}".format(remote=remote)) + print(NEIGHBOUR_PING_CONFIG.format(title="Ping time of {remote}".format(remote=remote))) + print(NEIGHBOUR_PING_VALUE.format(host=link["remote"], host_fieldname=remote)) + + sys.exit(0) + elif sys.argv[1] == "autoconf": + if os.path.exists(os.getenv('OLSRD_BIN_PATH', '/usr/sbin/olsrd')): + print('yes') + else: + print('no') + sys.exit(0) + elif sys.argv[1] == "version": + print('olsrd Munin plugin, version %s' % plugin_version) + sys.exit(0) + elif sys.argv[1] == "": + # ignore + pass + else: + # unknown argument + sys.stderr.write("Unknown argument{eol}".format(eol=LINESEP)) + sys.exit(1) + + # output values + links = list(get_olsr_links()) + + # overview graph for the link quality (ETX) of all neighbours + print("multigraph olsr_link_quality") + for link in links: + print("lq_{remote}.value {lq:f}".format(lq=link["lq"], + remote=get_clean_fieldname(link["remote"]))) + print("nlq_{remote}.value {nlq:f}".format(nlq=link["nlq"], + remote=get_clean_fieldname(link["remote"]))) + # detailed ETX graph for each single neighbour link + for link in links: + print("multigraph olsr_link_quality.host_{remote}" + .format(remote=get_clean_fieldname(link["remote"]))) + print("lq.value {lq:f}".format(lq=link["lq"])) + print("nlq.value {nlq:f}".format(nlq=link["nlq"])) + + # count the links/nodes behind each neighbour node + print("multigraph olsr_neighbour_link_count") + for link in links: + print("neighbour_{host_fieldname}.value {value}" + .format(value=link["route_count"], + host_fieldname=get_clean_fieldname(link["remote"]))) + + # overview of ping roundtrip times + print("multigraph olsr_neighbour_ping") + ping_times = get_ping_times([link["remote"] for link in links]) + for link in links: + ping_time = ping_times.get(link["remote"], None) + if ping_time is not None: + print("neighbour_{remote}.value {value:.4f}" + .format(value=ping_time, + remote=get_clean_fieldname(link["remote"]))) + # single detailed graphs for the ping time of each link + for link in links: + ping_time = ping_times.get(link["remote"], None) + if ping_time is not None: + remote = get_clean_fieldname(link["remote"]) + print("multigraph olsr_neighbour_ping.host_{remote}".format(remote=remote)) + print("neighbour_{remote}.value {value:.4f}".format(remote=remote, value=ping_time)) + +# final marker for shell / python hybrid script (see "Interpreter Selection") +EOF = True +EOF