24263a7439
- 打印所有设备的MAC地址数据库 - 详细输出每个邻居的匹配过程 - 添加normalizeMAC函数标准化MAC地址格式 - 解决MAC地址格式不一致导致匹配失败的问题
200 lines
5.3 KiB
Go
200 lines
5.3 KiB
Go
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)
|
||
}
|