Feat: 支持通过MAC地址进行邻居匹配和拓扑连线
- Neighbor模型添加RemoteMAC字段 - Device模型添加MACAddresses字段 - H3C解析器保存邻居MAC地址和设备所有接口MAC - 拓扑构建支持三层匹配: IP -> 设备名 -> MAC地址 - 即使ARP表获取失败也能通过MAC地址自动连线
This commit is contained in:
+16
-3
@@ -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",
|
fmt.Printf("Warning: parsed 0 interfaces for device %s (output length: %d)\n",
|
||||||
device.IP, len(outputs[1]))
|
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映射(允许失败)
|
// 解析ARP表用于MAC到IP映射(允许失败)
|
||||||
@@ -276,14 +287,16 @@ func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) []
|
|||||||
// 格式: a4bb-6de2-62cd/MAC address
|
// 格式: a4bb-6de2-62cd/MAC address
|
||||||
if macParts := strings.Split(value, "/"); len(macParts) > 0 {
|
if macParts := strings.Split(value, "/"); len(macParts) > 0 {
|
||||||
mac := strings.TrimSpace(strings.ToLower(macParts[0]))
|
mac := strings.TrimSpace(strings.ToLower(macParts[0]))
|
||||||
// 通过ARP表查找IP
|
// 保存MAC地址
|
||||||
|
currentNeighbor.RemoteMAC = mac
|
||||||
|
|
||||||
|
// 通过ARP表查找IP(如果有)
|
||||||
if ip, ok := arpTable[mac]; ok {
|
if ip, ok := arpTable[mac]; ok {
|
||||||
currentNeighbor.RemoteIP = ip
|
currentNeighbor.RemoteIP = ip
|
||||||
currentNeighbor.RemoteDevice = ip
|
currentNeighbor.RemoteDevice = ip
|
||||||
} else {
|
} else {
|
||||||
// 如果ARP表中没有,使用MAC地址作为标识
|
// 如果ARP表中没有,使用MAC地址作为标识(但RemoteIP仍为空)
|
||||||
currentNeighbor.RemoteDevice = mac
|
currentNeighbor.RemoteDevice = mac
|
||||||
// 注意:RemoteIP为空,拓扑可能无法连线
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,24 +56,41 @@ func (b *Builder) Build() models.TopologyGraph {
|
|||||||
edgeMap := make(map[string]bool) // 用于去重
|
edgeMap := make(map[string]bool) // 用于去重
|
||||||
for _, device := range b.devices {
|
for _, device := range b.devices {
|
||||||
for _, neighbor := range device.Neighbors {
|
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 {
|
for _, d := range b.devices {
|
||||||
if d.Hostname == neighbor.RemoteDevice {
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if neighbor.RemoteIP == "" {
|
if targetIP == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建唯一的边ID
|
// 创建唯一的边ID
|
||||||
edgeID := fmt.Sprintf("%s-%s-%s", device.IP, neighbor.LocalInterface, neighbor.RemoteIP)
|
edgeID := fmt.Sprintf("%s-%s-%s", device.IP, neighbor.LocalInterface, targetIP)
|
||||||
reverseEdgeID := fmt.Sprintf("%s-%s-%s", neighbor.RemoteIP, neighbor.RemoteInterface, device.IP)
|
reverseEdgeID := fmt.Sprintf("%s-%s-%s", targetIP, neighbor.RemoteInterface, device.IP)
|
||||||
|
|
||||||
// 避免重复边
|
// 避免重复边
|
||||||
if edgeMap[edgeID] || edgeMap[reverseEdgeID] {
|
if edgeMap[edgeID] || edgeMap[reverseEdgeID] {
|
||||||
@@ -83,7 +100,7 @@ func (b *Builder) Build() models.TopologyGraph {
|
|||||||
edge := models.TopologyEdge{
|
edge := models.TopologyEdge{
|
||||||
ID: edgeID,
|
ID: edgeID,
|
||||||
Source: device.IP,
|
Source: device.IP,
|
||||||
Target: neighbor.RemoteIP,
|
Target: targetIP,
|
||||||
SourceInterface: neighbor.LocalInterface,
|
SourceInterface: neighbor.LocalInterface,
|
||||||
TargetInterface: neighbor.RemoteInterface,
|
TargetInterface: neighbor.RemoteInterface,
|
||||||
Protocol: neighbor.Protocol,
|
Protocol: neighbor.Protocol,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type Device struct {
|
|||||||
Uptime string `json:"uptime"`
|
Uptime string `json:"uptime"`
|
||||||
Interfaces []Interface `json:"interfaces"`
|
Interfaces []Interface `json:"interfaces"`
|
||||||
Neighbors []Neighbor `json:"neighbors"`
|
Neighbors []Neighbor `json:"neighbors"`
|
||||||
|
MACAddresses []string `json:"mac_addresses,omitempty"` // 设备的所有MAC地址(用于邻居匹配)
|
||||||
LastScanned time.Time `json:"last_scanned"`
|
LastScanned time.Time `json:"last_scanned"`
|
||||||
ScanStatus string `json:"scan_status"` // success, failed, pending
|
ScanStatus string `json:"scan_status"` // success, failed, pending
|
||||||
ErrorMessage string `json:"error_message,omitempty"`
|
ErrorMessage string `json:"error_message,omitempty"`
|
||||||
@@ -46,11 +47,13 @@ type Interface struct {
|
|||||||
OutPackets int64 `json:"out_packets"`
|
OutPackets int64 `json:"out_packets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Neighbor 邻居设备信息
|
||||||
// Neighbor 邻居设备信息
|
// Neighbor 邻居设备信息
|
||||||
type Neighbor struct {
|
type Neighbor struct {
|
||||||
LocalInterface string `json:"local_interface"`
|
LocalInterface string `json:"local_interface"`
|
||||||
RemoteDevice string `json:"remote_device"`
|
RemoteDevice string `json:"remote_device"`
|
||||||
RemoteIP string `json:"remote_ip"`
|
RemoteIP string `json:"remote_ip"`
|
||||||
|
RemoteMAC string `json:"remote_mac,omitempty"` // 新增:邻居MAC地址
|
||||||
RemoteInterface string `json:"remote_interface"`
|
RemoteInterface string `json:"remote_interface"`
|
||||||
Protocol string `json:"protocol"` // CDP, LLDP, ARP
|
Protocol string `json:"protocol"` // CDP, LLDP, ARP
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user