| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- package device
- import (
- "bufio"
- "fmt"
- "network-topology-discovery/pkg/models"
- "regexp"
- "strings"
- )
- // HuaweiParser 华为设备解析器
- type HuaweiParser struct {
- BaseParser
- }
- // GetCommands 获取华为设备命令列表
- func (p *HuaweiParser) GetCommands() []string {
- return []string{
- "display version",
- "display interface",
- "display interface brief",
- "display lldp neighbor",
- }
- }
- // Parse 解析华为设备输出
- func (p *HuaweiParser) 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 *HuaweiParser) 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, "VRP") {
- lines := strings.Split(output, "\n")
- for _, line := range lines {
- if strings.Contains(line, "VRP") {
- 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 *HuaweiParser) 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.Speed == "" {
- currentInterface.Speed = brief.Speed
- }
- if currentInterface.Duplex == "" {
- currentInterface.Duplex = brief.Duplex
- }
- if currentInterface.VLAN == "" {
- currentInterface.VLAN = brief.VLAN
- }
- }
- }
- if currentInterface != nil {
- // 描述
- if descRegex := regexp.MustCompile(`Description:\s+(.+)`); descRegex.MatchString(line) {
- currentInterface.Description = descRegex.FindStringSubmatch(line)[1]
- }
- // MAC地址
- if macRegex := regexp.MustCompile(`Hardware address is\s+(\S+)`); macRegex.MatchString(line) {
- currentInterface.MAC = macRegex.FindStringSubmatch(line)[1]
- }
- // IP地址
- if ipRegex := regexp.MustCompile(`Internet Address is\s+(\d+\.\d+\.\d+\.\d+),\s+Subnet mask is\s+(\d+\.\d+\.\d+\.\d+)`); ipRegex.MatchString(line) {
- matches := ipRegex.FindStringSubmatch(line)
- currentInterface.IP = matches[1]
- currentInterface.Mask = matches[2]
- }
- // 带宽格式1: Speed : 1000Mbps
- if speedRegex := regexp.MustCompile(`Speed\s*:\s*(\d+)\s*(Kbps|Mbps|Gbps)`); speedRegex.MatchString(line) {
- matches := speedRegex.FindStringSubmatch(line)
- currentInterface.Speed = matches[1] + matches[2]
- }
- // 带宽格式2: BW 1000000 Kbit
- if speedRegex2 := regexp.MustCompile(`BW\s+(\d+)\s+(Kbit|Mbit|Gbit)`); speedRegex2.MatchString(line) && currentInterface.Speed == "" {
- matches := speedRegex2.FindStringSubmatch(line)
- currentInterface.Speed = matches[1] + " " + matches[2]
- }
- // VLAN信息: Port link-type
- if linkTypeRegex := regexp.MustCompile(`Port link-type\s*:\s*(\S+)`); linkTypeRegex.MatchString(line) {
- currentInterface.VLAN = linkTypeRegex.FindStringSubmatch(line)[1]
- }
- if untaggedRegex := regexp.MustCompile(`Untagged VLAN ID\s*:\s*(\S+)`); untaggedRegex.MatchString(line) {
- untagged := untaggedRegex.FindStringSubmatch(line)[1]
- if untagged != "none" && untagged != "--" {
- if currentInterface.VLAN != "" {
- currentInterface.VLAN = currentInterface.VLAN + " " + untagged
- } else {
- currentInterface.VLAN = untagged
- }
- }
- }
- if taggedRegex := regexp.MustCompile(`Tagged VLAN ID\s*:\s*(\S+)`); taggedRegex.MatchString(line) {
- tagged := taggedRegex.FindStringSubmatch(line)[1]
- if tagged != "none" && tagged != "--" {
- if currentInterface.VLAN != "" {
- currentInterface.VLAN = currentInterface.VLAN + " (T:" + tagged + ")"
- } else {
- currentInterface.VLAN = "T:" + tagged
- }
- }
- }
- }
- }
- if currentInterface != nil {
- interfaces = append(interfaces, *currentInterface)
- }
- return interfaces
- }
- func (p *HuaweiParser) parseInterfaceBrief(output string) map[string]models.Interface {
- interfaces := make(map[string]models.Interface)
- lines := strings.Split(output, "\n")
- mode := 0 // 0=未开始, 1=route mode, 2=bridge mode
- for _, line := range lines {
- trimmed := strings.TrimSpace(line)
- if trimmed == "" || strings.HasPrefix(trimmed, "---") {
- continue
- }
- if strings.Contains(trimmed, "route mode") {
- mode = 1
- continue
- }
- if strings.Contains(trimmed, "bridge mode") {
- mode = 2
- continue
- }
- fields := strings.Fields(trimmed)
- if len(fields) > 0 && (fields[0] == "Interface" || fields[0] == "interface") {
- continue
- }
- // Route mode: Interface Link Protocol Primary IP Description
- if mode == 1 && len(fields) >= 3 {
- fullName := expandH3CInterfaceName(fields[0])
- ip := ""
- if len(fields) >= 4 && fields[3] != "--" {
- ip = fields[3]
- }
- iface := models.Interface{
- Name: fullName,
- Status: strings.ToLower(fields[1]),
- IP: ip,
- }
- interfaces[fullName] = iface
- }
- // Bridge mode: Interface Link Speed Duplex Type PVID Description
- if mode == 2 && len(fields) >= 5 {
- fullName := expandH3CInterfaceName(fields[0])
- speed := fields[2]
- duplex := fields[3]
- switch duplex {
- case "A":
- duplex = "auto"
- case "F(a)", "F":
- duplex = "full"
- case "H":
- duplex = "half"
- }
- vlan := ""
- if len(fields) >= 5 {
- switch fields[4] {
- case "A":
- vlan = "Access"
- case "T":
- vlan = "Trunk"
- case "H":
- vlan = "Hybrid"
- }
- }
- if len(fields) >= 6 {
- vlan = vlan + " " + fields[5]
- }
- iface := models.Interface{
- Name: fullName,
- Status: strings.ToLower(fields[1]),
- Speed: speed,
- Duplex: duplex,
- VLAN: strings.TrimSpace(vlan),
- }
- if existing, ok := interfaces[fullName]; ok {
- if existing.IP != "" {
- iface.IP = existing.IP
- }
- }
- interfaces[fullName] = iface
- }
- }
- return interfaces
- }
- func (p *HuaweiParser) 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.Contains(line, "Local Interface") || strings.Contains(line, "-----") {
- continue
- }
- fields := strings.Fields(line)
- if len(fields) >= 5 {
- currentNeighbor = &models.Neighbor{
- LocalInterface: fields[0],
- RemoteDevice: fields[2],
- RemoteInterface: fields[4],
- Protocol: "LLDP",
- }
- neighbors = append(neighbors, *currentNeighbor)
- }
- }
- return neighbors
- }
|