SNMP LLDP: longer timeout, lower MaxRepetitions, Walk fallback after BulkWalk errors (e.g. Ubiquiti EdgeSwitch).

Made-with: Cursor
This commit is contained in:
Луценко Андрей Анатольевич
2026-04-10 13:22:59 +10:00
parent 6d75de1e2e
commit 16762c14ac
2 changed files with 44 additions and 4 deletions
+40 -4
View File
@@ -184,6 +184,16 @@ func probeSNMPAndLLDP(ip, community string, checkedAt time.Time, timeoutMS int)
out.SysObjectID = snmpValueToString(vb.Value)
}
}
// LLDP — несколько BulkWalk подряд; часть прошивок (в т.ч. Ubiquiti EdgeSwitch) отваливается по таймауту
// или некорректно обрабатывает GET-BULK с большим MaxRepetitions — увеличиваем время и снижаем пакет,
// при ошибке BulkWalk в walkAsMap делаем запасной SNMP Walk (GetNext).
if min := time.Duration(3000) * time.Millisecond; client.Timeout < min {
client.Timeout = min
}
client.MaxRepetitions = 12
client.Retries = 2
return out, probeLLDP(client, ip, checkedAt)
}
@@ -239,16 +249,42 @@ func probeLLDP(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []LLDPResu
return out
}
func snmpOIDTrim(s string) string {
return strings.TrimPrefix(strings.TrimSpace(s), ".")
}
// walkAsMap выполняет поддерево SNMP по base oid. Сначала GET-BULK (быстро); при ошибке — Walk (GetNext),
// что совместимо с большим числом встраиваемых коммутаторов.
func walkAsMap(client *gosnmp.GoSNMP, oid string) map[string]string {
out := map[string]string{}
base := snmpOIDTrim(oid)
prefix := base + "."
out := make(map[string]string)
record := func(pduName string, val any) {
n := snmpOIDTrim(pduName)
if !strings.HasPrefix(n, prefix) {
return
}
key := strings.TrimPrefix(n, prefix)
if key == "" {
return
}
out[key] = snmpValueToString(val)
}
pdus, err := client.BulkWalkAll(oid)
if err != nil {
log.Printf("lldp snmp BulkWalkAll target=%s oid=%s: %v (fallback Walk)", client.Target, base, err)
if werr := client.Walk(oid, func(pdu gosnmp.SnmpPDU) error {
record(pdu.Name, pdu.Value)
return nil
}); werr != nil {
log.Printf("lldp snmp Walk target=%s oid=%s: %v", client.Target, base, werr)
}
return out
}
prefix := oid + "."
for _, p := range pdus {
key := strings.TrimPrefix(p.Name, prefix)
out[key] = snmpValueToString(p.Value)
record(p.Name, p.Value)
}
return out
}