95ab5e0fdb
- 将 'display lldp neighbor-list' 改为 'display lldp neighbor-information' - 重写解析函数以适配新命令的输出格式 - 正确提取邻居设备名称、IP、接口信息
209 righe
5.5 KiB
Go
209 righe
5.5 KiB
Go
package device
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"network-topology-discovery/pkg/models"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// H3CParser H3C设备解析器
|
|
type H3CParser struct {
|
|
BaseParser
|
|
}
|
|
|
|
// GetCommands 获取H3C设备命令列表
|
|
func (p *H3CParser) GetCommands() []string {
|
|
return []string{
|
|
"display version",
|
|
"display interface",
|
|
"display ip interface brief",
|
|
"display lldp neighbor-information",
|
|
}
|
|
}
|
|
|
|
// Parse 解析H3C设备输出
|
|
func (p *H3CParser) Parse(device *models.Device, outputs []string) error {
|
|
if len(outputs) < 4 {
|
|
return fmt.Errorf("insufficient command outputs")
|
|
}
|
|
|
|
p.parseVersion(device, outputs[0])
|
|
device.Interfaces = p.parseInterfaces(outputs[1], outputs[2])
|
|
device.Neighbors = p.parseNeighbors(outputs[3])
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *H3CParser) parseVersion(device *models.Device, output string) {
|
|
hostnameRegex := regexp.MustCompile(`<(\S+)>`)
|
|
if matches := hostnameRegex.FindStringSubmatch(output); len(matches) > 1 {
|
|
device.Hostname = matches[1]
|
|
}
|
|
|
|
if strings.Contains(output, "Comware") {
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
if strings.Contains(line, "Comware") {
|
|
device.OSVersion = strings.TrimSpace(line)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
uptimeRegex := regexp.MustCompile(`uptime is\s+(\d+\s+\S+)`)
|
|
if matches := uptimeRegex.FindStringSubmatch(output); len(matches) > 1 {
|
|
device.Uptime = matches[1]
|
|
}
|
|
}
|
|
|
|
func (p *H3CParser) parseInterfaces(interfaceOutput, briefOutput string) []models.Interface {
|
|
var interfaces []models.Interface
|
|
briefMap := p.parseInterfaceBrief(briefOutput)
|
|
|
|
scanner := bufio.NewScanner(strings.NewReader(interfaceOutput))
|
|
var currentInterface *models.Interface
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
|
|
if nameRegex := regexp.MustCompile(`^(\S+)\s+current state:\s+(UP|DOWN)`); nameRegex.MatchString(line) {
|
|
if currentInterface != nil {
|
|
interfaces = append(interfaces, *currentInterface)
|
|
}
|
|
matches := nameRegex.FindStringSubmatch(line)
|
|
currentInterface = &models.Interface{
|
|
Name: matches[1],
|
|
Status: strings.ToLower(matches[2]),
|
|
}
|
|
|
|
if brief, ok := briefMap[currentInterface.Name]; ok {
|
|
currentInterface.IP = brief.IP
|
|
}
|
|
}
|
|
|
|
if currentInterface != nil {
|
|
if descRegex := regexp.MustCompile(`Description:\s+(.+)`); descRegex.MatchString(line) {
|
|
currentInterface.Description = descRegex.FindStringSubmatch(line)[1]
|
|
}
|
|
|
|
if macRegex := regexp.MustCompile(`Hardware address is\s+(\S+)`); macRegex.MatchString(line) {
|
|
currentInterface.MAC = macRegex.FindStringSubmatch(line)[1]
|
|
}
|
|
|
|
if ipRegex := regexp.MustCompile(`IP Address:\s+(\d+\.\d+\.\d+\.\d+)\s+Subnet Mask:\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
|
|
matches := ipRegex.FindStringSubmatch(line)
|
|
currentInterface.IP = matches[1]
|
|
currentInterface.Mask = matches[2]
|
|
}
|
|
|
|
if speedRegex := regexp.MustCompile(`(\d+)\s+(Kbps|Mbps|Gbps)`); speedRegex.MatchString(line) {
|
|
matches := speedRegex.FindStringSubmatch(line)
|
|
currentInterface.Speed = matches[1] + " " + matches[2]
|
|
}
|
|
}
|
|
}
|
|
|
|
if currentInterface != nil {
|
|
interfaces = append(interfaces, *currentInterface)
|
|
}
|
|
|
|
return interfaces
|
|
}
|
|
|
|
func (p *H3CParser) parseInterfaceBrief(output string) map[string]models.Interface {
|
|
interfaces := make(map[string]models.Interface)
|
|
lines := strings.Split(output, "\n")
|
|
|
|
for _, line := range lines {
|
|
fields := strings.Fields(line)
|
|
if len(fields) >= 4 {
|
|
iface := models.Interface{
|
|
Name: fields[0],
|
|
IP: fields[1],
|
|
Status: strings.ToLower(fields[3]),
|
|
}
|
|
interfaces[iface.Name] = iface
|
|
}
|
|
}
|
|
|
|
return interfaces
|
|
}
|
|
|
|
func (p *H3CParser) parseNeighbors(output string) []models.Neighbor {
|
|
var neighbors []models.Neighbor
|
|
scanner := bufio.NewScanner(strings.NewReader(output))
|
|
|
|
var currentNeighbor *models.Neighbor
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
|
|
// 跳过空行和标题行
|
|
if strings.TrimSpace(line) == "" ||
|
|
strings.Contains(line, "LLDP neighbor information") ||
|
|
strings.Contains(line, "------") {
|
|
continue
|
|
}
|
|
|
|
// 匹配邻居设备信息 - display lldp neighbor-information 输出格式:
|
|
// NeighborIndex : 1
|
|
// ChassisID : 00e0-fc12-3456
|
|
// PortID : GigabitEthernet1/0/1
|
|
// SystemName : Switch-02
|
|
// ManagementAddress : 172.16.12.2
|
|
// LocalInterface : GigabitEthernet1/0/1
|
|
|
|
if strings.Contains(line, "NeighborIndex") {
|
|
if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
|
|
neighbors = append(neighbors, *currentNeighbor)
|
|
}
|
|
currentNeighbor = &models.Neighbor{
|
|
Protocol: "LLDP",
|
|
}
|
|
}
|
|
|
|
if currentNeighbor != nil {
|
|
// 提取设备名称
|
|
if strings.Contains(line, "SystemName") {
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if len(parts) == 2 {
|
|
currentNeighbor.RemoteDevice = strings.TrimSpace(parts[1])
|
|
}
|
|
}
|
|
|
|
// 提取管理IP地址
|
|
if strings.Contains(line, "ManagementAddress") {
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if len(parts) == 2 {
|
|
currentNeighbor.RemoteIP = strings.TrimSpace(parts[1])
|
|
}
|
|
}
|
|
|
|
// 提取远程接口
|
|
if strings.Contains(line, "PortID") {
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if len(parts) == 2 {
|
|
currentNeighbor.RemoteInterface = strings.TrimSpace(parts[1])
|
|
}
|
|
}
|
|
|
|
// 提取本地接口
|
|
if strings.Contains(line, "LocalInterface") {
|
|
parts := strings.SplitN(line, ":", 2)
|
|
if len(parts) == 2 {
|
|
currentNeighbor.LocalInterface = strings.TrimSpace(parts[1])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 添加最后一个邻居
|
|
if currentNeighbor != nil && currentNeighbor.RemoteDevice != "" {
|
|
neighbors = append(neighbors, *currentNeighbor)
|
|
}
|
|
|
|
return neighbors
|
|
}
|