From dbc8e511a2c118b768e517a7e25c089a55bdc1af Mon Sep 17 00:00:00 2001 From: Sandro Date: Tue, 7 Jun 2022 16:34:08 +0200 Subject: [PATCH] Add nft_counters plugin Plugin monitors nftables counters and can be configured to show a subset of counters. Limiting output by type of counter (bytes or packets) is also possible. Plugin requires python3-nftables, which makes use of libnftables and is part of Netfilter's nftables, but may need to be installed separately. Plugin will bail out if the nftables module cannot be loaded. Plugin is built upon PyMunin, adapted for Python3. The version listed in PIP is still using Python 2 syntax. Release of a Python 3 compatible version is pending. --- .../example-graphs/nft_counters-day.png | Bin 0 -> 33216 bytes plugins/network/nft_counters | 277 ++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 plugins/network/example-graphs/nft_counters-day.png create mode 100755 plugins/network/nft_counters diff --git a/plugins/network/example-graphs/nft_counters-day.png b/plugins/network/example-graphs/nft_counters-day.png new file mode 100644 index 0000000000000000000000000000000000000000..c4fafe35f275696ea777bd669b626bb597166eb5 GIT binary patch literal 33216 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ͫG8psM;vA3J(coUl9S?ih`jIe^$V^q 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 F{{{M*6n+2z literal 0 HcmV?d00001 diff --git a/plugins/network/nft_counters b/plugins/network/nft_counters new file mode 100755 index 00000000..3f674b57 --- /dev/null +++ b/plugins/network/nft_counters @@ -0,0 +1,277 @@ +#!/usr/bin/python + +""" +Munin plugin for monitoring counters in nftables. For more information on +nftables see https://wiki.nftables.org/wiki-nftables/index.php/Counters + +=head1 NAME + +nft_counters - Munin Plugin for monitoring counters in nftables + +=head1 DESCRIPTION + +Plugin reads counters [1] from nftables and shows the associated values in bytes +and packets. Which counters and/or values are to be shown can be configured +(see below). + +=head1 REQUIREMENTS + +Plugin runs on systems with nftables installed. It makes use of the excellent +PyMunin module, so that needs to be installed as well. + +=head1 CONFIGURATION + +Since reading nftables needs root permissions, so does this plugin. That makes +the 'user root' setting in the configuration file mandatory. + +To further tune what should be graphed or not, you can adjust the configuration +usually found in /etc/munin/plugin-conf.d/nft_counters: + + [nft_counters] + user root + + env.counters_exclude counter_one,counter_two + env.counters_include counter_this,counter_that + env.count_only [bytes | packets] + +=head2 env.counters_exclude + +Exclude counters from graph. Comma separated list of counters, as known to +nftables (see 'nft list counters'), to exclude from graphing. + +=head2 env.counters_include + +Include counters in graph, I. Comma separated list of counters, +as known to nftables (see 'nft list counters'), to include in graphing. +B + +=head2 env.count_only + +Show values only in bytes or packets. Default both counters are shown. + +=head1 BUGS + +=head2 {fieldname}.info + +The {fieldname}.info should show the comment associated with the counter. +However, the JSON output of 'nft' does not contain the comment attribute. So, +for now, the plugin uses the counter name for {fieldname}.info. There is an +open L upstream. + +=head1 AUTHOR + +Written and Blessed by (Holy) Penguinpee > + +=head1 LICENSE + +GPLv3 + +=head1 ACKNOWLEDGEMENT + +This plugin makes use of the excellent PyMunin [2] module by Ali Onur Uyar, +adapted to Python3 [3] with the help of 2to3. + +The implementation of nftables interaction is based on the very helpful +examples [4] provided by Arturo Borrero Gonzalez. + +=head1 SEE ALSO + +=over + +=item [1] L + +=item [2] L + +=item [3] L + +=item [4] L + +=back + +=head1 MAGIC MARKERS + + #%# family=auto + #%# capabilities=autoconf + +=cut +""" + +import sys +try: + from nftables import Nftables + from nftables import json +except: + raise RuntimeError("Unable to load nftables module.") + sys.exit() +try: + from pymunin import MuninPlugin, MuninGraph, muninMain +except: + raise RuntimeError("Unable to load PyMunin module.") + sys.exit() + + +def _find_objects(ruleset, type): + # isn't this pure python? + return [o[type] for o in ruleset if type in o] + + +def nft_cmd(nftlib, cmd): + rc, output, error = nftlib.cmd(cmd) + if rc != 0: + # do proper error handling here, exceptions etc + raise RuntimeError("ERROR: running cmd nft {}".format(cmd)) + + if len(output) == 0: + # more error control + raise RuntimeError("ERROR: no output from libnftables") + + # transform the libnftables JSON output into generic python data structures + ruleset = json.loads(output)["nftables"] + + # validate we understand the libnftables JSON schema version. + # if the schema bumps version, this program might require updates + for metainfo in _find_objects(ruleset, "metainfo"): + if metainfo["json_schema_version"] > 1: + print("WARNING: we might not understand the JSON produced by libnftables") + + return ruleset + +def getCounters(): + + nft = Nftables() + nft.set_json_output(True) + nft.set_handle_output(True) + + ruleset = nft_cmd(nft, "list counters") + + return _find_objects(ruleset, "counter") + + +class MuninNftCountersPlugin(MuninPlugin): + + """ + Munin Plugin for nftables counters + """ + + plugin_name = "nft_counters" + isMultigraph = True + + + def __init__(self, argv=(), env=None, debug=True): + + """ + + Initialize Munin Plugin + + Parameters + ---------- + argv : TYPE, optional + List of commandline arguments. The default is (). + env : TYPE, optional + Dictionary of environment variables. The default is None. + debug : TYPE, optional + Print debugging messages. The default is False. + + Returns + ------- + None. + + """ + + MuninPlugin.__init__(self, argv, env, debug=True) + + # Munin graph parameters + graph_category = "network" + + try: + counters = getCounters() + if len(counters) <= 0: + print(""" + # No counters in nftables. Try adding some first. + # See 'munin-doc %s' for more information. + """ % self.plugin_name) + sys.exit() + except: + print(""" + # Plugin needs to be run as root since nftables can only be + # run as root. + # + # Use the following setting in the configuration file + # to enable root privileges: + # + # [%s] + # user root + """ % self.plugin_name) + sys.exit() + + count_only = self.envGet("count_only") + + # Create the graphs + if not (count_only == "bytes"): + graph_packets = MuninGraph("nftables packets per second", graph_category, + vlabel="packets / second", args="--base 1000") + if not (count_only == "packets"): + graph_bytes = MuninGraph("nftables bytes per second", graph_category, + vlabel="bytes / second", args="--base 1024") + + # Define filter to allow for tuning of counters graphed + self.envRegisterFilter("counters") + + # add counters as field to each graph (packets and bytes) + for counter in counters: + # JSON output does not contain "comment" attribute. + # Until it does, use counter name as info + try: + field_info = counter["comment"] + except: + field_info = counter["name"] + + if self.envCheckFilter("counters", counter["name"]): + if not (count_only == "bytes"): + graph_packets.addField(counter["name"], counter["name"], max=0, + type="DERIVE", info=field_info) + if not (count_only == "packets"): + graph_bytes.addField(counter["name"], counter["name"], max=0, + type="DERIVE", info=field_info) + + if not (count_only == "bytes"): + self.appendGraph("nft_counters_packets", graph_packets) + if not (count_only == "packets"): + self.appendGraph("nft_counters_bytes", graph_bytes) + + # add values for each field + for counter in counters: + if self.envCheckFilter("counters", counter["name"]): + if not (count_only == "bytes"): + self.setGraphVal("nft_counters_packets", counter["name"], + counter["packets"]) + if not (count_only == "packets"): + self.setGraphVal("nft_counters_bytes", counter["name"], + counter["bytes"]) + + + def autoconf(self): + + """ + + Checks if nft command can be run (needs root) and if so, + if there any counters present in nftables + + """ + + try: + counters = getCounters() + if len(counters) > 0: + return True + else: + return False + except: + return False + + +def main(): + sys.exit(muninMain(MuninNftCountersPlugin)) + + +if __name__ == "__main__": + main()