From 050b107e078b71b3bcde8492e6f13a315fce3d53 Mon Sep 17 00:00:00 2001 From: cppla Date: Thu, 20 Aug 2026 14:09:26 +0800 Subject: [PATCH] fix: correct client interface traffic filtering --- clients/client-linux.py | 21 ++++++++++++--------- clients/client-psutil.py | 20 ++++++++++++-------- clients/test_client_metrics.py | 30 ++++++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/clients/client-linux.py b/clients/client-linux.py index 85273c4..601c67f 100755 --- a/clients/client-linux.py +++ b/clients/client-linux.py @@ -236,6 +236,16 @@ def get_os_name(): except Exception: return 'unknown' +def is_ignored_network_interface(name): + name = str(name or '').strip().lower() + is_loopback = ( + name == 'lo' + or (name.startswith('lo') and name[2:].isdigit()) + or name.startswith('loopback') + ) + virtual_prefixes = ('tun', 'docker', 'veth', 'br-', 'vmbr', 'vnet', 'kube') + return not name or is_loopback or name.startswith(virtual_prefixes) + def liuliang(): NET_IN = 0 NET_OUT = 0 @@ -243,11 +253,7 @@ def liuliang(): for line in f.readlines(): netinfo = re.findall(r'([^\s]+):[\s]{0,}(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)', line) if netinfo: - if netinfo[0][0] == 'lo' or 'tun' in netinfo[0][0] \ - or 'docker' in netinfo[0][0] or 'veth' in netinfo[0][0] \ - or 'br-' in netinfo[0][0] or 'vmbr' in netinfo[0][0] \ - or 'vnet' in netinfo[0][0] or 'kube' in netinfo[0][0] \ - or netinfo[0][1]=='0' or netinfo[0][9]=='0': + if is_ignored_network_interface(netinfo[0][0]): continue else: NET_IN += int(netinfo[0][1]) @@ -366,10 +372,7 @@ def _net_speed(): avgtx = 0 for dev in net_dev[2:]: dev = dev.split(':') - if "lo" in dev[0] or "tun" in dev[0] \ - or "docker" in dev[0] or "veth" in dev[0] \ - or "br-" in dev[0] or "vmbr" in dev[0] \ - or "vnet" in dev[0] or "kube" in dev[0]: + if is_ignored_network_interface(dev[0]): continue dev = dev[1].split() avgrx += int(dev[0]) diff --git a/clients/client-psutil.py b/clients/client-psutil.py index d07b1d7..4a8021e 100755 --- a/clients/client-psutil.py +++ b/clients/client-psutil.py @@ -178,15 +178,22 @@ def _get_net_io_counters(): with _net_io_counters_lock: return psutil.net_io_counters(pernic=True) +def is_ignored_network_interface(name): + name = str(name or '').strip().lower() + is_loopback = ( + name == 'lo' + or (name.startswith('lo') and name[2:].isdigit()) + or name.startswith('loopback') + ) + virtual_prefixes = ('tun', 'docker', 'veth', 'br-', 'vmbr', 'vnet', 'kube') + return not name or is_loopback or name.startswith(virtual_prefixes) + def liuliang(): NET_IN = 0 NET_OUT = 0 net = _get_net_io_counters() for k, v in net.items(): - if 'lo' in k or 'tun' in k \ - or 'docker' in k or 'veth' in k \ - or 'br-' in k or 'vmbr' in k \ - or 'vnet' in k or 'kube' in k: + if is_ignored_network_interface(k): continue else: NET_IN += v[1] @@ -321,10 +328,7 @@ def _net_speed(): avgrx = 0 avgtx = 0 for name, stats in _get_net_io_counters().items(): - if "lo" in name or "tun" in name \ - or "docker" in name or "veth" in name \ - or "br-" in name or "vmbr" in name \ - or "vnet" in name or "kube" in name: + if is_ignored_network_interface(name): continue avgrx += stats.bytes_recv avgtx += stats.bytes_sent diff --git a/clients/test_client_metrics.py b/clients/test_client_metrics.py index 4aaf470..7c62520 100644 --- a/clients/test_client_metrics.py +++ b/clients/test_client_metrics.py @@ -55,12 +55,13 @@ class ClientMetricTests(unittest.TestCase): values = { "eth0": counters(500, 1000), "ens5": counters(300, 700), + "wlo1": counters(200, 400), "lo": counters(9000, 9000), "docker0": counters(8000, 8000), "veth123": counters(7000, 7000), } with mock.patch.object(client["psutil"], "net_io_counters", return_value=values, create=True): - self.assertEqual(client["liuliang"](), (1700, 800)) + self.assertEqual(client["liuliang"](), (2100, 1000)) def test_linux_totals_read_proc_and_exclude_virtual_interfaces(self): client = load_client("client-linux.py") @@ -68,11 +69,36 @@ class ClientMetricTests(unittest.TestCase): face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed eth0: 1000 10 0 0 0 0 0 0 500 5 0 0 0 0 0 0 ens5: 700 7 0 0 0 0 0 0 300 3 0 0 0 0 0 0 + wlo1: 400 4 0 0 0 0 0 0 200 2 0 0 0 0 0 0 lo: 9000 9 0 0 0 0 0 0 9000 9 0 0 0 0 0 0 veth123: 8000 8 0 0 0 0 0 0 8000 8 0 0 0 0 0 0 """ with mock.patch("builtins.open", mock.mock_open(read_data=proc_net_dev)): - self.assertEqual(client["liuliang"](), (1700, 800)) + self.assertEqual(client["liuliang"](), (2100, 1000)) + + def test_interface_filter_keeps_wlo_and_excludes_virtual_interfaces(self): + ignored = ( + "lo", "lo0", "Loopback Pseudo-Interface 1", "tun0", "docker0", + "veth123", "br-test", "vmbr0", "vnet0", "kube-ipvs0", + ) + included = ("wlo1", "eth0", "enp3s0", "bond0") + + for filename in ("client-linux.py", "client-psutil.py"): + with self.subTest(client=filename): + client = load_client(filename) + predicate = client["is_ignored_network_interface"] + self.assertTrue(all(predicate(name) for name in ignored)) + self.assertTrue(all(not predicate(name) for name in included)) + + def test_linux_totals_keep_one_way_interfaces(self): + client = load_client("client-linux.py") + proc_net_dev = """Inter-| Receive | Transmit + face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed + eth0: 1000 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + ens5: 0 0 0 0 0 0 0 0 300 3 0 0 0 0 0 0 +""" + with mock.patch("builtins.open", mock.mock_open(read_data=proc_net_dev)): + self.assertEqual(client["liuliang"](), (1000, 300)) def test_network_speed_starts_and_resets_at_zero(self): for filename in ("client-linux.py", "client-psutil.py"):