Conversation
Formality Check: Suggestions AvailableWe checked this pull request against the contribution guidelines. Here is what needs your attention:
|
| #!/bin/sh /etc/rc.common | ||
| # SPDX-License-Identifier: GPL-2.0-or-later | ||
|
|
||
| START=51 |
There was a problem hiding this comment.
snmpd's own init uses START=99, so at boot this starts long before the AgentX master exists and /var/run/agentx.sock is not there to connect to. Recovery then depends on the subagent's reconnect timer plus procd respawn. Order it after snmpd instead.
Generated by Claude Code
| while (err > 0) | ||
| nl_recvmsgs(st.sock, cb); |
There was a problem hiding this comment.
err is only cleared from a callback, so a local nl_recvmsgs() failure (socket error, ENOBUFS) that invokes no callback spins forever and hangs the agent inside an SNMP request.
| while (err > 0) | |
| nl_recvmsgs(st.sock, cb); | |
| while (err > 0) { | |
| if (nl_recvmsgs(st.sock, cb) < 0) | |
| break; | |
| } |
Generated by Claude Code
| if (lt[NL80211_ATTR_MAC]) | ||
| memcpy(l->addr, nla_data(lt[NL80211_ATTR_MAC]), sizeof(l->addr)); |
There was a problem hiding this comment.
nla_parse_nested() is called with a NULL policy, so no attribute length is validated and a short NL80211_ATTR_MAC makes this read past the attribute. Check the length before copying (the nla_get_u32() calls just below have the same exposure).
| if (lt[NL80211_ATTR_MAC]) | |
| memcpy(l->addr, nla_data(lt[NL80211_ATTR_MAC]), sizeof(l->addr)); | |
| if (lt[NL80211_ATTR_MAC] && | |
| nla_len(lt[NL80211_ATTR_MAC]) >= (int)sizeof(l->addr)) | |
| memcpy(l->addr, nla_data(lt[NL80211_ATTR_MAC]), sizeof(l->addr)); |
Generated by Claude Code
| static bool read_u32(const char *path, uint32_t *out) | ||
| { | ||
| char buf[32]; | ||
|
|
||
| if (slurp(path, buf, sizeof(buf)) < 0) | ||
| return false; | ||
| *out = (uint32_t)strtoul(buf, NULL, 10); | ||
| return true; | ||
| } |
There was a problem hiding this comment.
hwmon tempN_input and thermal-zone temp are signed and can be below zero; strtoul("-5000") wraps, so a sub-zero reading is served as ~4294962296 mC. Parse signed and clamp, since lmTempSensorsValue is a Gauge32.
| static bool read_u32(const char *path, uint32_t *out) | |
| { | |
| char buf[32]; | |
| if (slurp(path, buf, sizeof(buf)) < 0) | |
| return false; | |
| *out = (uint32_t)strtoul(buf, NULL, 10); | |
| return true; | |
| } | |
| static bool read_u32(const char *path, uint32_t *out) | |
| { | |
| char buf[32]; | |
| long v; | |
| if (slurp(path, buf, sizeof(buf)) < 0) | |
| return false; | |
| v = strtol(buf, NULL, 10); | |
| *out = (v < 0) ? 0 : (uint32_t)v; | |
| return true; | |
| } |
Generated by Claude Code
| if (seen_n < sizeof(seen) / sizeof(seen[0]) && | ||
| !mac_seen(seen, seen_n, e->mac)) { | ||
| memcpy(seen[seen_n].a, e->mac, 6); | ||
| seen_n++; |
There was a problem hiding this comment.
openwrtWirelessClientCount is documented as excluding STA-mode uplinks ("this device's own uplink is not one of its clients"), but every phy80211 netdev is walked here with no mode check, so a wireless backhaul's upstream AP lands in seen[] and is counted as a client. iw->mode is already available (it is used in collect_dump()); gate the dedup on AP/master mode, or drop the exclusion claim from the MIB.
Generated by Claude Code
| if (iw->noise && !iw->noise(de->d_name, &val)) | ||
| w->noise = val; | ||
| val = 0; | ||
| if (iw->txpower && !iw->txpower(de->d_name, &val)) |
There was a problem hiding this comment.
When noise/txpower fail or are unsupported, the field stays 0 and is still served as a real dBm value — exactly the "misleading zero" the MLD columns go out of their way to avoid. Track them the way has_chanutil is tracked and return noSuchInstance for columns 6 and 17 instead.
Generated by Claude Code
| "Display label for the wireless interface, normally the SSID. If | ||
| multiple interfaces share an SSID, the agent appends a band suffix | ||
| such as 24, 5 or 6 to keep labels unique." |
There was a problem hiding this comment.
nit: no band suffix is ever appended — collect_wireless() uses the raw iwinfo SSID and falls back to the interface name, so two VAPs sharing an SSID get identical labels. Either implement the disambiguation or drop the sentence.
Generated by Claude Code
| -- OPENWRT-MIB | ||
| -- | ||
| -- Base registration module for OpenWrt metrics exported by the | ||
| -- LibreNMS OpenWrt SNMP agent (a single net-snmp pass_persist handler). |
There was a problem hiding this comment.
nit: this ships an AgentX subagent, not a pass_persist handler — the commit message says the pass_persist script is what it replaces. Same wording in OPENWRT-WIRELESS-MIB lines 6 and 43.
| -- LibreNMS OpenWrt SNMP agent (a single net-snmp pass_persist handler). | |
| -- OpenWrt SNMP metrics agent (a net-snmp AgentX subagent). |
Generated by Claude Code
4a8286f to
ea6f205
Compare
|
The build succeeds on every architecture here. The two failing CI jobs (x86_64, arm_cortex-a15_neon-vfpv4) are dying in the post-build Docker runtime smoke test, at |
Stock OpenWrt reports nothing useful about its wireless side or its
sensors over SNMP. The ieee802dot11 MIB module is compiled into net-snmp
but produces no data on mac80211 drivers, and net-snmp's lmSensors module
cannot be enabled because it still targets the libsensors 2 API that
lm-sensors 3 removed.
Add a small AgentX subagent serving two subtrees:
.1.3.6.1.4.1.66510.1.10 OPENWRT-WIRELESS-MIB, under OpenWrt's own IANA
enterprise number, indexed by ifIndex so rows
join IF-MIB: clients, frequency, noise floor,
tx/rx rate range, SNR range, channel
utilisation, tx power, and (for 802.11be
Multi-Link Operation interfaces, which have no
single value for those columns) a separate
per-radio-link table
.1.3.6.1.4.1.2021.13.16 LM-SENSORS-MIB temperature and fan tables
Wireless data comes from libiwinfo, MLO per-link data from a direct
nl80211 query (libiwinfo has no MLO awareness), and sensor data from
hwmon and thermal zones, taking the union of the two so a sensor with no
thermal zone (an MDIO PHY die sensor, for example) is still reported.
snmpd enables the AgentX master by default and listens on a known
socket, so the package needs no snmpd configuration at all: no pass
registration, no uci-defaults, no removal hook. Radios, VAPs and sensors
are discovered at request time, so there is nothing per-interface to
maintain either.
Tested on a GL-BE9300 (qualcommbe/ipq53xx), including its 802.11be
multi-link (5GHz+6GHz) AP, and cross-checked against `iwinfo`/`iw`/sysfs
output and a live AgentX registration against snmpd with `snmpwalk`.
Signed-off-by: Kamil Bienkiewicz <perceivalpercy@gmail.com>
ea6f205 to
7c7fa76
Compare
📦 Package Details
Maintainer: @perceival
Description:
Stock OpenWrt reports nothing useful about its wireless side or its sensors over SNMP: the
ieee802dot11MIB module produces no data on mac80211 drivers, and net-snmp'slmSensorsmodule can't be enabled because it still targets the libsensors 2 API that lm-sensors 3 removed.This adds a small AgentX subagent that serves two subtrees under OpenWrt's own IANA enterprise number (66510) and the standard LM-SENSORS-MIB arc: a per-interface wireless table (clients, frequency, noise floor, tx/rx rate range, SNR range, channel utilisation, tx power, indexed by ifIndex so it joins IF-MIB) plus a per-radio-link table for 802.11be Multi-Link Operation interfaces (which have no single value for those columns), and hwmon/thermal-zone temperature and fan readings. Wireless data comes from libiwinfo, MLO per-link data from a direct nl80211 query (libiwinfo has no MLO awareness), and sensor data from the union of hwmon and thermal zones. No snmpd configuration is required — the AgentX master is on by default.
This is the device-side implementation for LibreNMS PRs librenms/librenms#19347 and librenms/librenms-agent#613, replacing the shell
pass_persistscript those PRs originally described.🧪 Run Testing Details
Verified on all three:
--version/-V/--help, a full SNMP walk of both MIB tables against each device's realsnmpd(viasnmpwalk), and (on the two Flint 3 units) that the multi-link interface's per-link table matchesiw dev <iface> infoexactly while the main interface table correctly reports its radio-scoped columns as absent rather than a misleading single value. On the R7800 (no 802.11be hardware) confirmed the link table is genuinely absent rather than present-but-empty.✅ Formalities
If your PR contains a patch:
N/A — this is a new package, not a patch.