Files
network-topology-discovery/internal/topology/builder.go
T
Your Name 24263a7439 Debug: 增强拓扑构建调试日志和MAC地址标准化
- 打印所有设备的MAC地址数据库
- 详细输出每个邻居的匹配过程
- 添加normalizeMAC函数标准化MAC地址格式
- 解决MAC地址格式不一致导致匹配失败的问题
2026-04-26 03:39:01 +08:00

200 строки
5.3 KiB
Go
Исходник Ответственный История

Этот файл содержит неоднозначные символы Юникода
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package topology
import (
"fmt"
"strings"
"network-topology-discovery/pkg/models"
)
// Builder 拓扑构建器
type Builder struct {
devices []models.Device
}
// NewBuilder 创建拓扑构建器
func NewBuilder() *Builder {
return &Builder{}
}
// AddDevice 添加设备
func (b *Builder) AddDevice(device models.Device) {
b.devices = append(b.devices, device)
}
// AddDevices 批量添加设备
func (b *Builder) AddDevices(devices []models.Device) {
b.devices = append(b.devices, devices...)
}
// Build 构建拓扑图
func (b *Builder) Build() models.TopologyGraph {
graph := models.TopologyGraph{
Nodes: make([]models.TopologyNode, 0),
Edges: make([]models.TopologyEdge, 0),
}
// 构建节点
nodeMap := make(map[string]models.TopologyNode)
for _, device := range b.devices {
// 优先使用主机名,如果没有则使用IP作为显示名
hostname := device.Hostname
if hostname == "" {
hostname = device.IP
}
node := models.TopologyNode{
ID: device.IP,
IP: device.IP,
Hostname: hostname,
Type: string(device.Type),
Icon: getDeviceIcon(device.Type),
}
nodeMap[device.IP] = node
graph.Nodes = append(graph.Nodes, node)
}
// 构建边(基于邻居信息)
edgeMap := make(map[string]bool) // 用于去重
// 打印所有设备的MAC地址,用于调试
fmt.Println("\n========== MAC Address Database ==========")
for _, d := range b.devices {
if len(d.MACAddresses) > 0 {
fmt.Printf("Device %s (%s): %d MAC addresses\n", d.Hostname, d.IP, len(d.MACAddresses))
for i, mac := range d.MACAddresses {
if i < 5 { // 只打印前5个
fmt.Printf(" MAC[%d]: %s\n", i, mac)
}
}
if len(d.MACAddresses) > 5 {
fmt.Printf(" ... and %d more\n", len(d.MACAddresses)-5)
}
}
}
fmt.Println("==========================================\n")
for _, device := range b.devices {
fmt.Printf("Building edges for device %s: %d neighbors, %d MAC addresses\n",
device.IP, len(device.Neighbors), len(device.MACAddresses))
for _, neighbor := range device.Neighbors {
fmt.Printf(" Processing neighbor on %s: RemoteMAC=%s, RemoteDevice=%s, RemoteIP=%s\n",
neighbor.LocalInterface, neighbor.RemoteMAC, neighbor.RemoteDevice, neighbor.RemoteIP)
// 尝试匹配邻居设备
targetIP := neighbor.RemoteIP
matchMethod := "IP"
// 如果没有IP,尝试通过设备名匹配
if targetIP == "" && neighbor.RemoteDevice != "" {
fmt.Printf(" Trying hostname match: %s\n", neighbor.RemoteDevice)
for _, d := range b.devices {
if d.Hostname == neighbor.RemoteDevice {
targetIP = d.IP
matchMethod = "hostname"
fmt.Printf(" ✓ Matched by hostname: %s -> %s\n", d.Hostname, d.IP)
break
}
}
}
// 如果还是没有,尝试通过MAC地址匹配(新增)
if targetIP == "" && neighbor.RemoteMAC != "" {
fmt.Printf(" Trying MAC match: %s\n", neighbor.RemoteMAC)
for _, d := range b.devices {
for _, mac := range d.MACAddresses {
// 标准化MAC地址进行比较(去除分隔符,转小写)
normalizedNeighborMAC := normalizeMAC(neighbor.RemoteMAC)
normalizedDeviceMAC := normalizeMAC(mac)
if normalizedNeighborMAC == normalizedDeviceMAC {
targetIP = d.IP
matchMethod = "MAC"
fmt.Printf(" ✓ Matched by MAC: %s (device) == %s (neighbor) -> %s\n",
mac, neighbor.RemoteMAC, d.IP)
break
}
}
if targetIP != "" {
break
}
}
}
if targetIP == "" {
fmt.Printf(" ✗ Could not match neighbor on %s\n", neighbor.LocalInterface)
continue
}
fmt.Printf(" ✓ Creating edge: %s (%s) -> %s via %s, matched by %s\n",
device.IP, neighbor.LocalInterface, targetIP, neighbor.RemoteInterface, matchMethod)
// 创建唯一的边ID
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] {
continue
}
edge := models.TopologyEdge{
ID: edgeID,
Source: device.IP,
Target: targetIP,
SourceInterface: neighbor.LocalInterface,
TargetInterface: neighbor.RemoteInterface,
Protocol: neighbor.Protocol,
}
graph.Edges = append(graph.Edges, edge)
edgeMap[edgeID] = true
}
}
return graph
}
// normalizeMAC 标准化MAC地址(去除分隔符,转小写)
func normalizeMAC(mac string) string {
// 去除所有分隔符(-、:、.
result := ""
for _, c := range mac {
if c != '-' && c != ':' && c != '.' {
result += string(c)
}
}
// 转小写
return strings.ToLower(result)
}
// getDeviceIcon 获取设备图标
func getDeviceIcon(deviceType models.DeviceType) string {
switch deviceType {
case models.DeviceTypeCisco:
return "router"
case models.DeviceTypeHuawei:
return "router"
case models.DeviceTypeH3C:
return "switch"
case models.DeviceTypeASA:
return "firewall"
case models.DeviceTypeLinux:
return "server"
case models.DeviceTypeWindows:
return "server"
default:
return "device"
}
}
// GetDevices 获取所有设备
func (b *Builder) GetDevices() []models.Device {
return b.devices
}
// Clear 清空拓扑
func (b *Builder) Clear() {
b.devices = make([]models.Device, 0)
}