master
go 129 lines 3.49 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package l2topology
4
5 import (
6 "strings"
7 )
8
9 type topologySegmentPortRef struct {
10 deviceID string
11 ifName string
12 ifIndex string
13 bridgePort string
14 }
15
16 func topologySegmentDisplayName(actor Actor, deviceDisplayByID map[string]string) string {
17 attrs := actor.Attributes
18 if len(attrs) == 0 {
19 return ""
20 }
21
22 ref := parseTopologySegmentPortRef(topologyAttrString(attrs, "designated_port"))
23 parent := topologySegmentParentDisplayName(ref.deviceID, deviceDisplayByID)
24 port := topologySegmentPortDisplay(ref)
25 if parent != "" && port != "" {
26 return parent + "." + port + ".segment"
27 }
28
29 parentCandidates := make(map[string]struct{})
30 for _, candidate := range topologyAttrStringSlice(attrs, "parent_devices") {
31 if value := topologySegmentParentDisplayName(candidate, deviceDisplayByID); value != "" {
32 parentCandidates[value] = struct{}{}
33 }
34 }
35 portCandidates := make(map[string]struct{})
36 for _, candidate := range topologyAttrStringSlice(attrs, "if_names") {
37 if candidate = strings.TrimSpace(candidate); candidate != "" {
38 portCandidates[candidate] = struct{}{}
39 }
40 }
41 if len(portCandidates) == 0 {
42 for _, candidate := range topologyAttrStringSlice(attrs, "bridge_ports") {
43 if candidate = strings.TrimSpace(candidate); candidate != "" {
44 portCandidates[candidate] = struct{}{}
45 }
46 }
47 }
48 parents := sortedTopologySet(parentCandidates)
49 ports := sortedTopologySet(portCandidates)
50 if len(parents) > 0 && len(ports) > 0 {
51 return parents[0] + "." + ports[0] + ".segment"
52 }
53
54 return topologyCompactSegmentID(topologyAttrString(attrs, "segment_id"))
55 }
56
57 func parseTopologySegmentPortRef(raw string) topologySegmentPortRef {
58 raw = strings.TrimSpace(raw)
59 if raw == "" {
60 return topologySegmentPortRef{}
61 }
62 parts := strings.Split(raw, keySep)
63 if len(parts) == 0 {
64 return topologySegmentPortRef{}
65 }
66 ref := topologySegmentPortRef{
67 deviceID: strings.TrimSpace(parts[0]),
68 }
69 for _, part := range parts[1:] {
70 switch {
71 case strings.HasPrefix(part, "name:"):
72 ref.ifName = strings.TrimSpace(strings.TrimPrefix(part, "name:"))
73 case strings.HasPrefix(part, "if:"):
74 ref.ifIndex = strings.TrimSpace(strings.TrimPrefix(part, "if:"))
75 case strings.HasPrefix(part, "bp:"):
76 ref.bridgePort = strings.TrimSpace(strings.TrimPrefix(part, "bp:"))
77 }
78 }
79 return ref
80 }
81
82 func topologySegmentPortDisplay(ref topologySegmentPortRef) string {
83 if name := strings.TrimSpace(ref.ifName); name != "" {
84 return name
85 }
86 if name := strings.TrimSpace(ref.bridgePort); name != "" {
87 return name
88 }
89 if index := strings.TrimSpace(ref.ifIndex); index != "" && index != "0" {
90 return index
91 }
92 return ""
93 }
94
95 func topologySegmentParentDisplayName(raw string, deviceDisplayByID map[string]string) string {
96 raw = strings.TrimSpace(raw)
97 if raw == "" {
98 return ""
99 }
100 if deviceDisplayByID != nil {
101 if display := strings.TrimSpace(deviceDisplayByID[raw]); display != "" {
102 return display
103 }
104 }
105 lower := strings.ToLower(raw)
106 switch {
107 case strings.HasPrefix(lower, "management_ip:"):
108 return strings.TrimSpace(raw[len("management_ip:"):])
109 case strings.HasPrefix(lower, "macaddress:"):
110 if mac := normalizeMAC(raw[len("macAddress:"):]); mac != "" {
111 return mac
112 }
113 return strings.TrimSpace(raw[len("macAddress:"):])
114 }
115 return raw
116 }
117
118 func topologyCompactSegmentID(segmentID string) string {
119 segmentID = strings.TrimSpace(segmentID)
120 if segmentID == "" {
121 return ""
122 }
123 const max = 48
124 runes := []rune(segmentID)
125 if len(runes) <= max {
126 return segmentID
127 }
128 return string(runes[:max]) + "..."
129 }