Files
network-topology-discovery/internal/topology/builder.go
T
Your Name c28c6ad128 Feat: 添加详细调试日志输出拓扑构建过程
- 输出每个设备的邻居数量和MAC地址数量
- 输出邻居匹配过程(IP/主机名/MAC)
- 输出匹配失败的详细信息
- 输出创建的连线详情
2026-04-26 01:16:17 +08:00

163 line
4.2 KiB
Go

package topology
import (
"fmt"
"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) // 用于去重
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 {
// 尝试匹配邻居设备
targetIP := neighbor.RemoteIP
matchMethod := "IP"
// 如果没有IP,尝试通过设备名匹配
if targetIP == "" && neighbor.RemoteDevice != "" {
fmt.Printf(" Neighbor %s has no IP, trying hostname match: %s\n",
neighbor.LocalInterface, 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(" Neighbor %s has no IP/hostname, trying MAC match: %s\n",
neighbor.LocalInterface, neighbor.RemoteMAC)
for _, d := range b.devices {
for _, mac := range d.MACAddresses {
if mac == neighbor.RemoteMAC {
targetIP = d.IP
matchMethod = "MAC"
fmt.Printf(" Matched by MAC: %s -> %s\n", mac, d.IP)
break
}
}
if targetIP != "" {
break
}
}
}
if targetIP == "" {
fmt.Printf(" Neighbor %s could not be matched (RemoteIP=%s, RemoteMAC=%s, RemoteDevice=%s)\n",
neighbor.LocalInterface, neighbor.RemoteIP, neighbor.RemoteMAC, neighbor.RemoteDevice)
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
}
// 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)
}