feat: VLAN in FDB, persist vlan, enrich port-devices with hostname, UI columns

Made-with: Cursor
This commit is contained in:
PTah
2026-04-13 12:38:05 +10:00
parent 927110167c
commit 886300b6c0
8 changed files with 91 additions and 26 deletions
+22 -3
View File
@@ -266,7 +266,8 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
seen := make(map[string]struct{})
out := make([]PortDeviceResult, 0, len(combinedFdb))
for macTail, bridgePortRaw := range combinedFdb {
mac := normalizeMACKey(dottedDecimalToMACTail(macTail))
vlan, macSix := parseFdbKeyVlanAndMacTail(macTail)
mac := normalizeMACKey(dottedDecimalToMACTail(macSix))
if mac == "" {
continue
}
@@ -285,7 +286,7 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
ipsSet := macToIPs[mac]
if len(ipsSet) == 0 {
key := fmt.Sprintf("%d|%s|", ifIndex, mac)
key := fmt.Sprintf("%d|%d|%s|", vlan, ifIndex, mac)
if _, ok := seen[key]; ok {
continue
}
@@ -294,6 +295,7 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
IP: ip,
IfIndex: ifIndex,
BridgePort: bridgePort,
Vlan: vlan,
MAC: mac,
LearnedIP: "",
CheckedAt: checkedAt,
@@ -301,7 +303,7 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
continue
}
for learnedIP := range ipsSet {
key := fmt.Sprintf("%d|%s|%s", ifIndex, mac, learnedIP)
key := fmt.Sprintf("%d|%d|%s|%s", vlan, ifIndex, mac, learnedIP)
if _, ok := seen[key]; ok {
continue
}
@@ -310,6 +312,7 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
IP: ip,
IfIndex: ifIndex,
BridgePort: bridgePort,
Vlan: vlan,
MAC: mac,
LearnedIP: learnedIP,
CheckedAt: checkedAt,
@@ -321,6 +324,9 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
if out[i].IfIndex != out[j].IfIndex {
return out[i].IfIndex < out[j].IfIndex
}
if out[i].Vlan != out[j].Vlan {
return out[i].Vlan < out[j].Vlan
}
if out[i].MAC != out[j].MAC {
return out[i].MAC < out[j].MAC
}
@@ -333,6 +339,19 @@ func probePortDevices(client *gosnmp.GoSNMP, ip string, checkedAt time.Time) []P
return out
}
// parseFdbKeyVlanAndMacTail — суффикс OID FDB: dot1q — {vlan}.{6 октетов MAC}; dot1d — только 6 октетов (vlan=0).
func parseFdbKeyVlanAndMacTail(macTail string) (vlan int, macSixTail string) {
p := strings.Split(strings.TrimSpace(macTail), ".")
if len(p) >= 7 {
vlan, _ = strconv.Atoi(p[0])
return vlan, strings.Join(p[1:7], ".")
}
if len(p) >= 6 {
return 0, strings.Join(p[len(p)-6:], ".")
}
return 0, ""
}
// snmpNumericString — значение SNMP как строка (int/float/[]byte) для Atoi.
func snmpNumericString(v any) string {
switch x := v.(type) {