feat: enhance H3C LLDP parser to support verbose format with System name and Management address
- Add support for LLDP verbose output format (display lldp neighbor-information verbose) - Parse System name field for accurate device hostname matching - Parse Management address field for IP-based neighbor identification - Handle edge cases: endpoint devices without System name (fallback to MAC) - Handle Port ID as MAC address (not interface name) for endpoint devices - Add detailed debug logging for LLDP neighbor parsing - Implement three-level fallback strategy: System name > Management IP > MAC address This fixes the topology auto-linking issue where only 1 link was created despite having neighbor data.
This commit is contained in:
+73
-16
@@ -20,7 +20,7 @@ func (p *H3CParser) GetCommands() []string {
|
||||
"display version",
|
||||
"display interface",
|
||||
"display interface brief", // 接口简要信息(包含VLAN和物理接口状态)
|
||||
"display lldp neighbor-information",
|
||||
"display lldp neighbor-information verbose", // LLDP邻居详细信息(包含System name和Management address)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +288,23 @@ func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) []
|
||||
|
||||
if currentNeighbor != nil {
|
||||
// 提取 ChassisID (MAC地址)
|
||||
// Verbose格式: Chassis ID: 642f-c7e0-0333
|
||||
if strings.Contains(line, "Chassis ID:") && !strings.Contains(line, "ChassisID/subtype") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
mac := strings.TrimSpace(strings.ToLower(parts[1]))
|
||||
if isValidMAC(mac) {
|
||||
currentNeighbor.RemoteMAC = mac
|
||||
// 如果还没有RemoteDevice,先使用MAC作为占位符(后续可能被System name覆盖)
|
||||
if currentNeighbor.RemoteDevice == "" {
|
||||
currentNeighbor.RemoteDevice = mac
|
||||
}
|
||||
fmt.Printf(" [LLDP] Parsed neighbor MAC (verbose): %s\n", mac)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非verbose格式: ChassisID/subtype: a4bb-6de2-62cd/MAC address
|
||||
if strings.Contains(line, "ChassisID/subtype") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
@@ -295,27 +312,61 @@ 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]))
|
||||
// 保存MAC地址
|
||||
currentNeighbor.RemoteMAC = mac
|
||||
fmt.Printf(" Parsed neighbor MAC: %s (from line: %s)\n", mac, line)
|
||||
|
||||
// 通过ARP表查找IP(如果有)
|
||||
if ip, ok := arpTable[mac]; ok {
|
||||
currentNeighbor.RemoteIP = ip
|
||||
currentNeighbor.RemoteDevice = ip
|
||||
} else {
|
||||
// 如果ARP表中没有,使用MAC地址作为标识(但RemoteIP仍为空)
|
||||
if currentNeighbor.RemoteDevice == "" {
|
||||
currentNeighbor.RemoteDevice = mac
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" WARNING: Could not parse MAC from ChassisID line: %s\n", line)
|
||||
fmt.Printf(" [LLDP] Parsed neighbor MAC: %s\n", mac)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取 System name (verbose格式)
|
||||
if strings.Contains(line, "System name:") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
systemName := strings.TrimSpace(parts[1])
|
||||
if systemName != "" {
|
||||
// System name 是最可靠的匹配方式,覆盖之前的MAC地址占位符
|
||||
currentNeighbor.RemoteDevice = systemName
|
||||
fmt.Printf(" [LLDP] Parsed neighbor System name: %s\n", systemName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取 Management address (verbose格式)
|
||||
if strings.Contains(line, "Management address:") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
mgmtAddr := strings.TrimSpace(parts[1])
|
||||
if isValidIP(mgmtAddr) {
|
||||
// 如果还没有RemoteIP,使用Management address
|
||||
if currentNeighbor.RemoteIP == "" {
|
||||
currentNeighbor.RemoteIP = mgmtAddr
|
||||
fmt.Printf(" [LLDP] Parsed neighbor Management address: %s\n", mgmtAddr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" WARNING: ChassisID line has no colon: %s\n", line)
|
||||
}
|
||||
}
|
||||
|
||||
// 提取 PortID (远程接口)
|
||||
// Verbose格式: Port ID: GigabitEthernet1/0/48 或 Port ID: a4bb-6de2-62cd (MAC地址)
|
||||
if strings.Contains(line, "Port ID:") && !strings.Contains(line, "PortID/subtype") && !strings.Contains(line, "Port ID type") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
portID := strings.TrimSpace(parts[1])
|
||||
// 检查Port ID是否是MAC地址(格式: a4bb-6de2-62cd)
|
||||
if isValidMAC(portID) {
|
||||
// Port ID是MAC地址,不赋值给RemoteInterface
|
||||
fmt.Printf(" [LLDP] Port ID is MAC address (not interface): %s\n", portID)
|
||||
} else {
|
||||
// Port ID是接口名
|
||||
currentNeighbor.RemoteInterface = portID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非verbose格式: PortID/subtype: GigabitEthernet0/0/1/Interface name
|
||||
if strings.Contains(line, "PortID/subtype") {
|
||||
parts := strings.SplitN(line, ":", 2)
|
||||
if len(parts) == 2 {
|
||||
@@ -330,8 +381,14 @@ func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) []
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个邻居
|
||||
if currentNeighbor != nil && currentNeighbor.RemoteInterface != "" {
|
||||
// 添加最后一个邻居(修改:只要有RemoteDevice或RemoteInterface就添加)
|
||||
if currentNeighbor != nil && (currentNeighbor.RemoteDevice != "" || currentNeighbor.RemoteInterface != "") {
|
||||
// 如果Port ID是MAC地址而不是接口名,将MAC赋值给RemoteInterface(如果为空)
|
||||
if currentNeighbor.RemoteInterface == "" && currentNeighbor.RemoteMAC != "" {
|
||||
// 检查Port ID是否是MAC地址(在解析过程中可能已经将MAC作为Port ID)
|
||||
// 这种情况发生在Port ID type为MAC address时
|
||||
fmt.Printf(" [LLDP] Neighbor has no interface name, using MAC as identifier: %s\n", currentNeighbor.RemoteMAC)
|
||||
}
|
||||
neighbors = append(neighbors, *currentNeighbor)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user