key interfaces by name when available and normalize port names

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ian Gulliver
2026-01-18 14:00:51 -08:00
parent 37b30fe788
commit 92299f5efc
2 changed files with 77 additions and 30 deletions

View File

@@ -91,12 +91,18 @@ func (n *Nodes) Update(mac net.HardwareAddr, ips []net.IP, ifaceName, nodeName,
}
macKey := mac.String()
var targetID int
targetID := -1
isNew := false
if id, exists := n.macIndex[macKey]; exists {
targetID = id
} else {
if _, nodeExists := n.nodes[id]; nodeExists {
targetID = id
} else {
delete(n.macIndex, macKey)
}
}
if targetID == -1 {
targetID = n.nextID
n.nextID++
n.nodes[targetID] = &Node{
@@ -108,15 +114,24 @@ func (n *Nodes) Update(mac net.HardwareAddr, ips []net.IP, ifaceName, nodeName,
node := n.nodes[targetID]
var added []string
iface, exists := node.Interfaces[macKey]
ifaceKey := macKey
if ifaceName != "" {
ifaceKey = ifaceName
}
iface, exists := node.Interfaces[ifaceKey]
if !exists {
iface = &Interface{
MAC: mac,
IPs: map[string]net.IP{},
Name: ifaceName,
MAC: mac,
IPs: map[string]net.IP{},
}
node.Interfaces[macKey] = iface
node.Interfaces[ifaceKey] = iface
added = append(added, "iface="+ifaceKey)
}
if _, exists := n.macIndex[macKey]; !exists {
n.macIndex[macKey] = targetID
added = append(added, "mac="+macKey)
}
for _, ip := range ips {
@@ -128,10 +143,6 @@ func (n *Nodes) Update(mac net.HardwareAddr, ips []net.IP, ifaceName, nodeName,
n.ipIndex[ipKey] = targetID
}
if ifaceName != "" && iface.Name == "" {
iface.Name = ifaceName
}
if nodeName != "" && node.Name == "" {
node.Name = nodeName
}

72
snmp.go
View File

@@ -5,12 +5,29 @@ import (
"fmt"
"log"
"net"
"regexp"
"strings"
"time"
"github.com/gosnmp/gosnmp"
)
var portNameRewrites = []struct {
re *regexp.Regexp
repl string
}{
{regexp.MustCompile(`.*Slot: (\d+) Port: (\d+).*`), "$1/$2"},
}
func rewritePortName(name string) string {
for _, rw := range portNameRewrites {
if rw.re.MatchString(name) {
return rw.re.ReplaceAllString(name, rw.repl)
}
}
return name
}
type snmpConfig struct {
username string
authKey string
@@ -105,10 +122,6 @@ func (t *Tendrils) querySNMPDevice(ip net.IP) {
}
defer snmp.Conn.Close()
if t.DebugSNMP {
log.Printf("[snmp] %s: connected", ip)
}
t.querySysName(snmp, ip)
t.queryInterfaceMACs(snmp, ip)
t.queryBridgeMIB(snmp, ip)
@@ -152,24 +165,47 @@ func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, deviceIP net.IP) {
return
}
var macs []net.HardwareAddr
ifNames := t.getInterfaceNames(snmp)
type ifaceEntry struct {
mac net.HardwareAddr
name string
}
var ifaces []ifaceEntry
for _, result := range results {
if result.Type == gosnmp.OctetString {
macBytes := result.Value.([]byte)
if len(macBytes) == 6 {
mac := net.HardwareAddr(macBytes)
if !isBroadcastOrZero(mac) {
macs = append(macs, mac)
if t.DebugSNMP {
log.Printf("[snmp] %s: interface mac=%s", deviceIP, mac)
}
}
}
if result.Type != gosnmp.OctetString {
continue
}
macBytes := result.Value.([]byte)
if len(macBytes) != 6 {
continue
}
mac := net.HardwareAddr(macBytes)
if isBroadcastOrZero(mac) {
continue
}
oidSuffix := strings.TrimPrefix(strings.TrimPrefix(result.Name, "."+oid), ".")
var ifIndex int
if _, err := fmt.Sscanf(oidSuffix, "%d", &ifIndex); err != nil {
continue
}
name := rewritePortName(ifNames[ifIndex])
if t.DebugSNMP {
log.Printf("[snmp] %s: interface %d mac=%s name=%s", deviceIP, ifIndex, mac, name)
}
ifaces = append(ifaces, ifaceEntry{mac: mac, name: name})
}
for _, mac := range macs {
t.nodes.Update(mac, nil, "", "", "snmp-ifmac")
var macs []net.HardwareAddr
for _, iface := range ifaces {
t.nodes.Update(iface.mac, nil, iface.name, "", "snmp-ifmac")
macs = append(macs, iface.mac)
}
if len(macs) > 1 {
t.nodes.Merge(macs, "snmp-ifmac")