feat: 优化拓扑匹配策略,使用12字符MAC前缀提高匹配精度

This commit is contained in:
Your Name
2026-04-27 18:32:29 +08:00
parent 07adc3ac5c
commit a7e51c5bea
+63 -35
View File
@@ -157,18 +157,59 @@ func (b *Builder) Build() models.TopologyGraph {
} }
} }
// 策略3b: MAC前缀匹配已禁用 - 同品牌设备MAC前缀相同,极易产生误匹配 // 策略3b: MAC前缀匹配(使用12字符前缀 - 更精确)
// 如果需要连接,请使用精确MAC匹配或确保邻居设备在设备列表中 // 同品牌设备虽然4字符前缀相同,但12字符前缀通常不同
if false && targetIP == "" && neighbor.RemoteMAC != "" { if targetIP == "" && neighbor.RemoteMAC != "" {
neighborMACPrefix := getMACPrefix(neighbor.RemoteMAC) // 使用12字符前缀(例如:642f-c7e0-03
fmt.Printf(" ⚠ MAC prefix match disabled (too unreliable): %s (prefix: %s)\n", neighbor.RemoteMAC, neighborMACPrefix) macPrefix := ""
if len(neighbor.RemoteMAC) >= 12 {
macPrefix = neighbor.RemoteMAC[:12]
} else {
macPrefix = neighbor.RemoteMAC
}
fmt.Printf(" Trying MAC prefix match (12 chars): %s (prefix: %s)\n", neighbor.RemoteMAC, macPrefix)
var matchedDevices []string
for _, d := range b.devices {
if d.IP == device.IP {
continue // 跳过自己
}
// 检查设备d的MAC地址是否有匹配的前缀
matchingMACs := 0
for _, mac := range d.MACAddresses {
if len(mac) >= 12 && mac[:12] == macPrefix {
matchingMACs++
}
}
if matchingMACs >= 3 {
matchedDevices = append(matchedDevices, d.IP)
}
}
// 只有唯一匹配时才建立连接
if len(matchedDevices) == 1 {
targetIP = matchedDevices[0]
matchMethod = fmt.Sprintf("MAC-prefix-12(%s)", macPrefix)
fmt.Printf(" ✓ Matched by MAC prefix-12 (unique): %s -> %s\n", neighbor.RemoteMAC, targetIP)
} else if len(matchedDevices) > 1 {
fmt.Printf(" ✗ Ambiguous MAC prefix-12 match: %s matched %v\n", macPrefix, matchedDevices)
} else {
fmt.Printf(" ✗ No device matches MAC prefix-12 %s\n", macPrefix)
}
} }
// 策略3c: LLDP对称性匹配(改进 - 需要双向验证 // 策略3c: LLDP接口匹配(改进 - 单向但要求唯一性
// 设备A的接口X连接到设备B的接口Y // 如果设备A的LLDP信息显示它连接到接口Y
// 同时设备B接口Y也应该连接到设备A的接口X // 设备B接口Y,则A连接到B
// 但如果有多个设备都有接口Y,则不匹配(避免歧义)
if targetIP == "" && neighbor.RemoteMAC != "" && neighbor.RemoteInterface != "" { if targetIP == "" && neighbor.RemoteMAC != "" && neighbor.RemoteInterface != "" {
fmt.Printf(" Trying LLDP symmetric match: looking for device with interface %s\n", neighbor.RemoteInterface) fmt.Printf(" Trying LLDP interface match: looking for device with interface %s\n", neighbor.RemoteInterface)
var matchedDevices []string
for _, d := range b.devices { for _, d := range b.devices {
if d.IP == device.IP { if d.IP == device.IP {
@@ -176,38 +217,25 @@ func (b *Builder) Build() models.TopologyGraph {
} }
// 检查设备d是否有这个接口 // 检查设备d是否有这个接口
hasInterface := false
for _, iface := range d.Interfaces { for _, iface := range d.Interfaces {
if iface.Name == neighbor.RemoteInterface { if iface.Name == neighbor.RemoteInterface {
hasInterface = true matchedDevices = append(matchedDevices, d.IP)
break break
} }
} }
}
if !hasInterface { // 只有唯一匹配时才建立连接
continue if len(matchedDevices) == 1 {
} targetIP = matchedDevices[0]
matchMethod = fmt.Sprintf("LLDP-interface(%s->%s)", neighbor.LocalInterface, neighbor.RemoteInterface)
// 双向验证:检查设备d的邻居信息中,这个接口是否连接回当前设备 fmt.Printf(" ✓ Matched by LLDP interface (unique): %s %s -> %s %s\n",
hasReverseLink := false device.IP, neighbor.LocalInterface, targetIP, neighbor.RemoteInterface)
for _, dNeighbor := range d.Neighbors { } else if len(matchedDevices) > 1 {
if dNeighbor.RemoteInterface == neighbor.LocalInterface && dNeighbor.LocalInterface == neighbor.RemoteInterface { fmt.Printf(" ✗ Ambiguous: multiple devices have interface %s: %v\n",
hasReverseLink = true neighbor.RemoteInterface, matchedDevices)
break } else {
} fmt.Printf(" ✗ No device found with interface %s\n", neighbor.RemoteInterface)
}
if hasReverseLink {
// 双向验证通过!
targetIP = d.IP
matchMethod = fmt.Sprintf("LLDP-symmetric(%s<->%s)", neighbor.LocalInterface, neighbor.RemoteInterface)
fmt.Printf(" ✓ Matched by LLDP symmetric (bidirectional): %s %s <-> %s %s -> %s\n",
device.IP, neighbor.LocalInterface, d.IP, neighbor.RemoteInterface, targetIP)
break
} else {
fmt.Printf(" ✗ Device %s has interface %s but no reverse link to %s %s\n",
d.IP, neighbor.RemoteInterface, device.IP, neighbor.LocalInterface)
}
} }
} }