Ver código fonte

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

Your Name 4 semanas atrás
pai
commit
a7e51c5bea
1 arquivos alterados com 63 adições e 35 exclusões
  1. 63 35
      internal/topology/builder.go

+ 63 - 35
internal/topology/builder.go

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