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.
Цей коміт міститься в:
@@ -20,7 +20,7 @@ func (p *H3CParser) GetCommands() []string {
|
|||||||
"display version",
|
"display version",
|
||||||
"display interface",
|
"display interface",
|
||||||
"display interface brief", // 接口简要信息(包含VLAN和物理接口状态)
|
"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 {
|
if currentNeighbor != nil {
|
||||||
// 提取 ChassisID (MAC地址)
|
// 提取 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") {
|
if strings.Contains(line, "ChassisID/subtype") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
@@ -295,27 +312,61 @@ 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]))
|
||||||
// 保存MAC地址
|
|
||||||
currentNeighbor.RemoteMAC = mac
|
currentNeighbor.RemoteMAC = mac
|
||||||
fmt.Printf(" Parsed neighbor MAC: %s (from line: %s)\n", mac, line)
|
if currentNeighbor.RemoteDevice == "" {
|
||||||
|
|
||||||
// 通过ARP表查找IP(如果有)
|
|
||||||
if ip, ok := arpTable[mac]; ok {
|
|
||||||
currentNeighbor.RemoteIP = ip
|
|
||||||
currentNeighbor.RemoteDevice = ip
|
|
||||||
} else {
|
|
||||||
// 如果ARP表中没有,使用MAC地址作为标识(但RemoteIP仍为空)
|
|
||||||
currentNeighbor.RemoteDevice = mac
|
currentNeighbor.RemoteDevice = mac
|
||||||
}
|
}
|
||||||
} else {
|
fmt.Printf(" [LLDP] Parsed neighbor MAC: %s\n", mac)
|
||||||
fmt.Printf(" WARNING: Could not parse MAC from ChassisID line: %s\n", line)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 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 (远程接口)
|
// 提取 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") {
|
if strings.Contains(line, "PortID/subtype") {
|
||||||
parts := strings.SplitN(line, ":", 2)
|
parts := strings.SplitN(line, ":", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
@@ -330,8 +381,14 @@ func (p *H3CParser) parseNeighbors(output string, arpTable map[string]string) []
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加最后一个邻居
|
// 添加最后一个邻居(修改:只要有RemoteDevice或RemoteInterface就添加)
|
||||||
if currentNeighbor != nil && currentNeighbor.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)
|
neighbors = append(neighbors, *currentNeighbor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Посилання в новій задачі
Заблокувати користувача