Bug description
snmp_topology picks 127.0.0.1 as the management IP of every SNMP device that exposes a loopback row in ipAddrTable. Because it picks the same address for every device, the map's default nodes_identity: ip then collapses the entire managed estate into a single actor.
On a 7-device UniFi estate (1 gateway, 3 switches, 3 APs, all polled fine, all with correct sysName), the topology:snmp function returns:
nodes_identity: ip -> managed SNMP devices: 1
sys_name = LivingRoomAP, management_ip = 127.0.0.1, type = access_point,
display_name = coreswitch.int.intergrem.com
nodes_identity: mac -> managed SNMP devices: 7
...every one of them with management_ip = 127.0.0.1
One node, wearing one device's hostname, another's sysName, and a third's device type. Endpoint actors render correctly throughout, so nothing else about the map looks broken.
Two defects compound. Either one alone would be harmless; together they produce the collapse.
1. No loopback exclusion when harvesting management addresses.
topology_cache_interfaces.go:81-95 — updateIfIndexByIP() appends every address from the ip_if_index walk (IP-MIB ipAddrTable) to localDevice.ManagementAddresses, with no filter for loopback, link-local or unspecified addresses:
c.ifIndexByIP[ip] = ifIndex
c.localDevice.ManagementAddresses = appendManagementAddress(c.localDevice.ManagementAddresses, topologymodel.ManagementAddress{
Address: ip,
AddressType: managementAddressTypeFromIP(ip),
Source: "ip_mib",
})
Most agents list 127.0.0.1 in ipAddrTable. Every UniFi device here does:
$ snmpwalk ... 192.168.1.240 1.3.6.1.2.1.4.20.1.2
iso.3.6.1.2.1.4.20.1.2.127.0.0.1 = INTEGER: 1
iso.3.6.1.2.1.4.20.1.2.192.168.1.240 = INTEGER: 3
2. Management IP is chosen by lexicographic string sort.
topology_management_address.go:92-128 — pickManagementIP() sorts the candidates as strings and returns the first:
if len(ipValues) > 0 {
sort.Strings(ipValues)
return ipValues[0]
}
"127.0.0.1" sorts below "192.168.1.240", so the loopback wins — on every device, identically, which is what merges them via normalizeTopologyDevice() (topology_device.go:27).
This defect bites independently of loopback. A device with several real addresses gets an arbitrary one. Our gateway's ipAddrTable is:
97.165.236.22, 127.0.0.1, 192.161.76.43, 192.168.0.0, 192.168.1.1, 192.168.2.1
Even with loopback filtered, lexicographic order returns 192.161.76.43 — the public WAN address — in preference to the actual management address 192.168.1.1. String order also puts "9x.x.x.x" last, so any 9x/8x-prefixed address loses to any 1x one regardless of what it is.
Expected behavior
snmp_topology should select a real management address per device, and distinct devices should stay distinct actors under the default nodes_identity: ip.
Concretely:
- Exclude loopback, link-local (169.254/16, fe80::/10) and unspecified addresses when building
ManagementAddresses from IP-MIB — or at minimum skip them in pickManagementIP().
- Replace the lexicographic sort with a preference order, then compare numerically as IPs rather than as strings. A reasonable order: the target the collector actually polls the device on (already available as
DeviceConnectionInfo.Hostname, and already passed into refreshDeviceTopology, though it may be a DNS name rather than a literal IP) > LLDP/CDP-advertised management address > private/RFC1918 > other global > link-local > loopback.
Point 2 alone would fix both symptoms and is the more valuable half — preferring the polled address is both obviously correct and information the collector already has.
Steps to reproduce
- Configure
go.d/snmp.conf with two or more SNMP devices whose ipAddrTable includes 127.0.0.1 (any stock net-snmp agent, and all UniFi switches/APs/gateways).
- Ensure the matched profile supplies the
ip_if_index topology kind — e.g. one extending _std-topology-fdb-arp-mib.yaml.
- Let
snmp_topology complete a refresh, then call the topology:snmp function with the defaults (map_type: high_confidence_inferred, nodes_identity: ip).
- Every device reports
management_ip: 127.0.0.1, and the devices are merged into one actor. Switching nodes_identity: mac separates them again but the management IP is still 127.0.0.1 on each.
Installation method
kickstart.sh
System info
Linux 7.0.14-6-pve x86_64 GNU/Linux
Debian GNU/Linux 13 (trixie) (Proxmox VE 9.2.5)
SNMP devices: UniFi UCG Fiber gateway, 2x USW Lite 16 PoE, 1x USW Pro Max 24 PoE, 2x UAP-AC-LR, 1x U6 Mesh — SNMPv3 authPriv.
Netdata build info
Netdata Version _____ : v2.11.0
Package Architecture : x86_64
Package Distro _______ : debian 13
Kernel Version _______ : 7.0.14-6-pve
Both functions are byte-identical on master as of filing, so this is not fixed there.
Additional info
Workaround, for anyone hitting this before it is fixed. updateIfIndexByIP() returns early when a row yields no topo_ip_addr tag, and the tag processor emits no tag at all when a match_pattern fails to match (tag_processor.go — a non-match is not a passthrough). So re-declaring the ip_if_index kind with a pattern constrained to the real management subnet drops the loopback row before it reaches either defect:
topology:
- kind: ip_if_index
MIB: IP-MIB
table:
OID: 1.3.6.1.2.1.4.20
name: ipAddrTable
symbols:
- OID: 1.3.6.1.2.1.4.20.1.2
name: ip_if_index
metric_tags:
- tag: topo_ip_addr
symbol:
OID: 1.3.6.1.2.1.4.20.1.1
name: ipAdEntAddr
match_pattern: '^(192\.168\.[0-9]{1,3}\.[1-9][0-9]{0,2})$'
match_value: "$1"
- tag: topo_if_index
symbol:
OID: 1.3.6.1.2.1.4.20.1.2
name: ipAdEntIfIndex
- tag: topo_ip_netmask
symbol:
OID: 1.3.6.1.2.1.4.20.1.3
name: ipAdEntNetMask
With that in place, same devices, same defaults: 1 managed device becomes 7, each with its real address, and actors/links go from 108/110 to 118/123. It obviously only works if you can hardcode your management subnet, which is why it is a workaround and not a fix.
Unrelated observation from the same estate, mentioned in case it is useful rather than as part of this report: none of the shipped ubiquiti-* profiles declare a topology: section or extend any _std-topology-* profile, so a UniFi estate produces a device-only map with zero links out of the box. UniFi also does not implement LLDP-MIB over SNMP (lldpLocSysName/lldpRemTable return No Such Object on the gateway, the switches and the APs), while BRIDGE-MIB/Q-BRIDGE/STP/ARP are all present — so FDB-based inference works well for these devices once a profile asks for it. Happy to open that separately or send a PR adding the topology extends to the Ubiquiti profiles if that would be welcome.
Bug description
snmp_topologypicks127.0.0.1as the management IP of every SNMP device that exposes a loopback row inipAddrTable. Because it picks the same address for every device, the map's defaultnodes_identity: ipthen collapses the entire managed estate into a single actor.On a 7-device UniFi estate (1 gateway, 3 switches, 3 APs, all polled fine, all with correct
sysName), thetopology:snmpfunction returns:One node, wearing one device's hostname, another's sysName, and a third's device type. Endpoint actors render correctly throughout, so nothing else about the map looks broken.
Two defects compound. Either one alone would be harmless; together they produce the collapse.
1. No loopback exclusion when harvesting management addresses.
topology_cache_interfaces.go:81-95—updateIfIndexByIP()appends every address from theip_if_indexwalk (IP-MIBipAddrTable) tolocalDevice.ManagementAddresses, with no filter for loopback, link-local or unspecified addresses:Most agents list
127.0.0.1inipAddrTable. Every UniFi device here does:2. Management IP is chosen by lexicographic string sort.
topology_management_address.go:92-128—pickManagementIP()sorts the candidates as strings and returns the first:"127.0.0.1"sorts below"192.168.1.240", so the loopback wins — on every device, identically, which is what merges them vianormalizeTopologyDevice()(topology_device.go:27).This defect bites independently of loopback. A device with several real addresses gets an arbitrary one. Our gateway's
ipAddrTableis:Even with loopback filtered, lexicographic order returns
192.161.76.43— the public WAN address — in preference to the actual management address192.168.1.1. String order also puts"9x.x.x.x"last, so any 9x/8x-prefixed address loses to any 1x one regardless of what it is.Expected behavior
snmp_topologyshould select a real management address per device, and distinct devices should stay distinct actors under the defaultnodes_identity: ip.Concretely:
ManagementAddressesfrom IP-MIB — or at minimum skip them inpickManagementIP().DeviceConnectionInfo.Hostname, and already passed intorefreshDeviceTopology, though it may be a DNS name rather than a literal IP) > LLDP/CDP-advertised management address > private/RFC1918 > other global > link-local > loopback.Point 2 alone would fix both symptoms and is the more valuable half — preferring the polled address is both obviously correct and information the collector already has.
Steps to reproduce
go.d/snmp.confwith two or more SNMP devices whoseipAddrTableincludes127.0.0.1(any stock net-snmp agent, and all UniFi switches/APs/gateways).ip_if_indextopology kind — e.g. one extending_std-topology-fdb-arp-mib.yaml.snmp_topologycomplete a refresh, then call thetopology:snmpfunction with the defaults (map_type: high_confidence_inferred,nodes_identity: ip).management_ip: 127.0.0.1, and the devices are merged into one actor. Switchingnodes_identity: macseparates them again but the management IP is still127.0.0.1on each.Installation method
kickstart.sh
System info
SNMP devices: UniFi UCG Fiber gateway, 2x USW Lite 16 PoE, 1x USW Pro Max 24 PoE, 2x UAP-AC-LR, 1x U6 Mesh — SNMPv3 authPriv.
Netdata build info
Both functions are byte-identical on
masteras of filing, so this is not fixed there.Additional info
Workaround, for anyone hitting this before it is fixed.
updateIfIndexByIP()returns early when a row yields notopo_ip_addrtag, and the tag processor emits no tag at all when amatch_patternfails to match (tag_processor.go— a non-match is not a passthrough). So re-declaring theip_if_indexkind with a pattern constrained to the real management subnet drops the loopback row before it reaches either defect:With that in place, same devices, same defaults: 1 managed device becomes 7, each with its real address, and actors/links go from 108/110 to 118/123. It obviously only works if you can hardcode your management subnet, which is why it is a workaround and not a fix.
Unrelated observation from the same estate, mentioned in case it is useful rather than as part of this report: none of the shipped
ubiquiti-*profiles declare atopology:section or extend any_std-topology-*profile, so a UniFi estate produces a device-only map with zero links out of the box. UniFi also does not implement LLDP-MIB over SNMP (lldpLocSysName/lldpRemTablereturnNo Such Objecton the gateway, the switches and the APs), while BRIDGE-MIB/Q-BRIDGE/STP/ARP are all present — so FDB-based inference works well for these devices once a profile asks for it. Happy to open that separately or send a PR adding the topology extends to the Ubiquiti profiles if that would be welcome.