diff --git a/internal/device/h3c.go b/internal/device/h3c.go index 9948778..c2695ac 100644 --- a/internal/device/h3c.go +++ b/internal/device/h3c.go @@ -41,6 +41,17 @@ func (p *H3CParser) Parse(device *models.Device, outputs []string) error { fmt.Printf("Warning: parsed 0 interfaces for device %s (output length: %d)\n", device.IP, len(outputs[1])) } + + // 收集所有接口的MAC地址(用于邻居匹配) + macSet := make(map[string]bool) + for _, iface := range device.Interfaces { + if iface.MAC != "" { + macSet[iface.MAC] = true + } + } + for mac := range macSet { + device.MACAddresses = append(device.MACAddresses, mac) + } } // 解析ARP表用于MAC到IP映射(允许失败) @@ -276,14 +287,16 @@ func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) [] // 格式: a4bb-6de2-62cd/MAC address if macParts := strings.Split(value, "/"); len(macParts) > 0 { mac := strings.TrimSpace(strings.ToLower(macParts[0])) - // 通过ARP表查找IP + // 保存MAC地址 + currentNeighbor.RemoteMAC = mac + + // 通过ARP表查找IP(如果有) if ip, ok := arpTable[mac]; ok { currentNeighbor.RemoteIP = ip currentNeighbor.RemoteDevice = ip } else { - // 如果ARP表中没有,使用MAC地址作为标识 + // 如果ARP表中没有,使用MAC地址作为标识(但RemoteIP仍为空) currentNeighbor.RemoteDevice = mac - // 注意:RemoteIP为空,拓扑可能无法连线 } } } diff --git a/internal/topology/builder.go b/internal/topology/builder.go index 7b0114b..2dabf09 100644 --- a/internal/topology/builder.go +++ b/internal/topology/builder.go @@ -56,24 +56,41 @@ func (b *Builder) Build() models.TopologyGraph { edgeMap := make(map[string]bool) // 用于去重 for _, device := range b.devices { for _, neighbor := range device.Neighbors { - // 检查邻居是否在设备列表中 - if _, exists := nodeMap[neighbor.RemoteIP]; !exists && neighbor.RemoteDevice != "" { - // 尝试通过设备名匹配 + // 尝试匹配邻居设备 + targetIP := neighbor.RemoteIP + + // 如果没有IP,尝试通过设备名匹配 + if targetIP == "" && neighbor.RemoteDevice != "" { for _, d := range b.devices { if d.Hostname == neighbor.RemoteDevice { - neighbor.RemoteIP = d.IP + targetIP = d.IP + break + } + } + } + + // 如果还是没有,尝试通过MAC地址匹配(新增) + if targetIP == "" && neighbor.RemoteMAC != "" { + for _, d := range b.devices { + for _, mac := range d.MACAddresses { + if mac == neighbor.RemoteMAC { + targetIP = d.IP + break + } + } + if targetIP != "" { break } } } - if neighbor.RemoteIP == "" { + if targetIP == "" { continue } // 创建唯一的边ID - edgeID := fmt.Sprintf("%s-%s-%s", device.IP, neighbor.LocalInterface, neighbor.RemoteIP) - reverseEdgeID := fmt.Sprintf("%s-%s-%s", neighbor.RemoteIP, neighbor.RemoteInterface, device.IP) + edgeID := fmt.Sprintf("%s-%s-%s", device.IP, neighbor.LocalInterface, targetIP) + reverseEdgeID := fmt.Sprintf("%s-%s-%s", targetIP, neighbor.RemoteInterface, device.IP) // 避免重复边 if edgeMap[edgeID] || edgeMap[reverseEdgeID] { @@ -83,7 +100,7 @@ func (b *Builder) Build() models.TopologyGraph { edge := models.TopologyEdge{ ID: edgeID, Source: device.IP, - Target: neighbor.RemoteIP, + Target: targetIP, SourceInterface: neighbor.LocalInterface, TargetInterface: neighbor.RemoteInterface, Protocol: neighbor.Protocol, diff --git a/pkg/models/models.go b/pkg/models/models.go index 55ffec6..ce5a1f9 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -24,6 +24,7 @@ type Device struct { Uptime string `json:"uptime"` Interfaces []Interface `json:"interfaces"` Neighbors []Neighbor `json:"neighbors"` + MACAddresses []string `json:"mac_addresses,omitempty"` // 设备的所有MAC地址(用于邻居匹配) LastScanned time.Time `json:"last_scanned"` ScanStatus string `json:"scan_status"` // success, failed, pending ErrorMessage string `json:"error_message,omitempty"` @@ -46,11 +47,13 @@ type Interface struct { OutPackets int64 `json:"out_packets"` } +// Neighbor 邻居设备信息 // Neighbor 邻居设备信息 type Neighbor struct { LocalInterface string `json:"local_interface"` RemoteDevice string `json:"remote_device"` RemoteIP string `json:"remote_ip"` + RemoteMAC string `json:"remote_mac,omitempty"` // 新增:邻居MAC地址 RemoteInterface string `json:"remote_interface"` Protocol string `json:"protocol"` // CDP, LLDP, ARP }