From 3874af44d7f71ae53c1ad066b6f7dea8564a19ba Mon Sep 17 00:00:00 2001 From: Lasse Wackers Date: Fri, 16 Oct 2026 16:44:54 +0200 Subject: [PATCH] Added option to set max interface speed For those who are not interested in traffic fluctuations and only the absolute traffic limits are relevant, we added an option to define the absolut speed limit of an interface. Define --interface-speed with the interface and the speed in bit to set the maximum speed of the interface. You can specify it multiple times. Without an interface definition it will set the global value for all interfaces (except those that are specified). Examples: --interface-speed eth0:1g --interface-speed 100m --- check-plugins/network-io/network-io | 97 +++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/check-plugins/network-io/network-io b/check-plugins/network-io/network-io index 24b937b13..485055868 100755 --- a/check-plugins/network-io/network-io +++ b/check-plugins/network-io/network-io @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/lib64/linuxfabrik-monitoring-plugins/venv/bin/python # -*- coding: utf-8; py-indent-offset: 4 -*- # # Author: Linuxfabrik GmbH, Zurich, Switzerland @@ -12,7 +12,7 @@ import argparse import sys - +import re import lib.args import lib.base import lib.cache @@ -48,6 +48,21 @@ DEFAULT_IGNORE = [ ] DEFAULT_NO_MATCH_SEVERITY = 'ok' +def parse_speed_units(speed): + """Parse the unit and convert speed from bit to byte""" + if speed.endswith("k"): + return int(speed[0:-1]) * 1000 / 8 + elif speed.endswith("m"): + return int(speed[0:-1]) * 1000 ** 2 / 8 + elif speed.endswith("g"): + return int(speed[0:-1]) * 1000 ** 3 / 8 + elif speed.endswith("t"): + return int(speed[0:-1]) * 1000 ** 4 / 8 + else: + if re.search(r"\w$", speed): + lib.base.cu(f"Unsupported speed unit: {speed}") + sys.exit(STATE_UNKNOWN) + return int(speed) / 8 def parse_args(): """Parse command line arguments using argparse.""" @@ -124,6 +139,16 @@ def parse_args(): default=DEFAULT_WARN, ) + parser.add_argument( + '--interface-speed', + help='Set a fixed interface speed (max throughput). Use ":" for per-interface or just "" (or ":") to apply to all interfaces. ' + 'The speed is given in bits. Units can be: k, m, g, t. ' + 'Can be specified multiple times. Examples: --interface-speed eth0:1g --interface-speed 100m', + dest='INTERFACE_SPEED', + action='append', + default=[], + ) + args, _ = parser.parse_known_args() return args @@ -145,6 +170,39 @@ def main(): except SystemExit: sys.exit(STATE_UNKNOWN) + # parse interface speed mappings + iface_speeds = {} + global_iface_speed = None + for entry in args.INTERFACE_SPEED: + if not entry: + lib.base.cu(f'Invalid --interface-speed entry "{entry}", expected format ":" or ""') + sys.exit(STATE_UNKNOWN) + + # split into name:speed if possible. Accept either "name:speed", ":speed", or "speed" + if ':' in entry: + name_part, speed_part = entry.split(':', 1) + name = name_part.strip() or None + speed = speed_part.strip() + else: + name = None + speed = entry.strip() + + if not speed: + lib.base.cu(f'Invalid --interface-speed entry "{entry}", missing speed value') + sys.exit(STATE_UNKNOWN) + + try: + bit_per_second = parse_speed_units(speed) + except ValueError as e: + lib.base.cu(f'Invalid speed value in --interface-speed "{entry}": {e}') + sys.exit(STATE_UNKNOWN) + + if name is None: + # global speed for all interfaces (last one wins) + global_iface_speed = bit_per_second + else: + iface_speeds[name] = bit_per_second + conn = lib.base.coe( lib.db_sqlite.connect(filename='linuxfabrik-monitoring-plugins-network-io.db') ) @@ -257,30 +315,47 @@ def main(): lib.db_sqlite.close(conn) lib.base.oao('Waiting for more data.', state) - # store the max. measured throughput in cache + # store/get the max. measured throughput in cache or use user-provided interface speed throughput_db = lib.cache.get( f'network-io-{interface}-throughput-max', filename='linuxfabrik-monitoring-plugins-network-io.db', ) - if throughput_db is False: - # unknown interface, no value - throughput_max = ( - 10 * 1024 * 1024 - ) # interface should be capable of 10 MB/sec + + # precedence: per-interface CLI > global CLI > cache/discovery + if interface in iface_speeds: + throughput_max = int(iface_speeds[interface]) lib.cache.set( f'network-io-{interface}-throughput-max', throughput_max, filename='linuxfabrik-monitoring-plugins-network-io.db', ) - elif throughput1 > int(throughput_db): - throughput_max = throughput1 + elif global_iface_speed is not None: + throughput_max = int(global_iface_speed) lib.cache.set( f'network-io-{interface}-throughput-max', throughput_max, filename='linuxfabrik-monitoring-plugins-network-io.db', ) else: - throughput_max = int(throughput_db) + if throughput_db is False: + # unknown interface, no value + throughput_max = ( + 10 * 1024 * 1024 + ) # interface should be capable of 10 MB/sec + lib.cache.set( + f'network-io-{interface}-throughput-max', + throughput_max, + filename='linuxfabrik-monitoring-plugins-network-io.db', + ) + elif throughput1 > int(throughput_db): + throughput_max = throughput1 + lib.cache.set( + f'network-io-{interface}-throughput-max', + throughput_max, + filename='linuxfabrik-monitoring-plugins-network-io.db', + ) + else: + throughput_max = int(throughput_db) # per-second rates for the remaining cumulative counters (packets, # errors, drops), computed like the byte rates above instead of