master
go 216 lines 5.5 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package l2topology
4
5 import (
6 "sort"
7 "strconv"
8 "strings"
9 )
10
11 func selectProbableEndpointReporterHint(
12 endpointLabels map[string]string,
13 reporterHints map[string][]bridgePortRef,
14 owner fdbEndpointOwner,
15 aliasOwnerIDs map[string]map[string]struct{},
16 managedDeviceIDs map[string]struct{},
17 ) probableEndpointReporterHint {
18 ownerDeviceID := strings.TrimSpace(owner.port.deviceID)
19 if ownerDeviceID != "" {
20 if len(managedDeviceIDs) == 0 {
21 return probableEndpointReporterHint{
22 deviceID: ownerDeviceID,
23 ifIndex: owner.port.ifIndex,
24 ifName: strings.TrimSpace(owner.port.ifName),
25 }
26 }
27 if _, ok := managedDeviceIDs[ownerDeviceID]; ok {
28 return probableEndpointReporterHint{
29 deviceID: ownerDeviceID,
30 ifIndex: owner.port.ifIndex,
31 ifName: strings.TrimSpace(owner.port.ifName),
32 }
33 }
34 }
35
36 deviceIDs := resolveTopologyEndpointDeviceHints(
37 topologyEndpointLabelDeviceIDs(endpointLabels),
38 aliasOwnerIDs,
39 )
40 if len(deviceIDs) == 0 {
41 for reporterID := range reporterHints {
42 reporterID = strings.TrimSpace(reporterID)
43 if reporterID == "" {
44 continue
45 }
46 deviceIDs = append(deviceIDs, reporterID)
47 }
48 deviceIDs = resolveTopologyEndpointDeviceHints(deviceIDs, aliasOwnerIDs)
49 }
50 deviceIDs = filterManagedDeviceHints(deviceIDs, managedDeviceIDs)
51 if len(deviceIDs) == 0 {
52 return probableEndpointReporterHint{}
53 }
54
55 ifIndexes := labelsCSVToSlice(endpointLabels, "learned_if_indexes")
56 ifNames := labelsCSVToSlice(endpointLabels, "learned_if_names")
57 parsedIfIndex := 0
58 for _, value := range ifIndexes {
59 value = strings.TrimSpace(value)
60 if value == "" {
61 continue
62 }
63 if n, err := strconv.Atoi(value); err == nil && n > 0 {
64 parsedIfIndex = n
65 break
66 }
67 }
68 parsedIfName := ""
69 for _, value := range ifNames {
70 value = strings.TrimSpace(value)
71 if value != "" {
72 parsedIfName = value
73 break
74 }
75 }
76
77 selectedDeviceID := deviceIDs[0]
78 for _, deviceID := range deviceIDs {
79 if len(reporterHints[deviceID]) > 0 {
80 selectedDeviceID = deviceID
81 break
82 }
83 }
84 hint := probableEndpointReporterHint{
85 deviceID: selectedDeviceID,
86 ifIndex: parsedIfIndex,
87 ifName: parsedIfName,
88 }
89 if ports := reporterHints[selectedDeviceID]; len(ports) > 0 {
90 sort.SliceStable(ports, func(i, j int) bool {
91 return bridgePortRefSortKey(ports[i]) < bridgePortRefSortKey(ports[j])
92 })
93 port := ports[0]
94 if hint.ifIndex == 0 && port.ifIndex > 0 {
95 hint.ifIndex = port.ifIndex
96 }
97 if strings.TrimSpace(hint.ifName) == "" && strings.TrimSpace(port.ifName) != "" {
98 hint.ifName = strings.TrimSpace(port.ifName)
99 }
100 }
101
102 if hint.ifIndex == 0 && strings.TrimSpace(hint.ifName) == "" {
103 hint.ifName = "0"
104 }
105 return hint
106 }
107
108 func ensureManagedProbableReporterHint(
109 hint probableEndpointReporterHint,
110 endpointLabels map[string]string,
111 reporterHints map[string][]bridgePortRef,
112 aliasOwnerIDs map[string]map[string]struct{},
113 managedDeviceIDs map[string]struct{},
114 managedDeviceIDList []string,
115 ) probableEndpointReporterHint {
116 if len(managedDeviceIDs) == 0 {
117 return hint
118 }
119 deviceID := strings.TrimSpace(hint.deviceID)
120 if deviceID != "" {
121 if _, ok := managedDeviceIDs[deviceID]; ok {
122 return hint
123 }
124 }
125
126 deviceIDs := resolveTopologyEndpointDeviceHints(
127 topologyEndpointLabelDeviceIDs(endpointLabels),
128 aliasOwnerIDs,
129 )
130 if len(deviceIDs) == 0 {
131 for reporterID := range reporterHints {
132 reporterID = strings.TrimSpace(reporterID)
133 if reporterID == "" {
134 continue
135 }
136 deviceIDs = append(deviceIDs, reporterID)
137 }
138 deviceIDs = resolveTopologyEndpointDeviceHints(deviceIDs, aliasOwnerIDs)
139 }
140 deviceIDs = filterManagedDeviceHints(deviceIDs, managedDeviceIDs)
141 if len(deviceIDs) == 0 {
142 deviceIDs = managedDeviceIDList
143 }
144 if len(deviceIDs) == 0 {
145 return probableEndpointReporterHint{}
146 }
147
148 hint.deviceID = strings.TrimSpace(deviceIDs[0])
149
150 ports := reporterHints[hint.deviceID]
151 if len(ports) > 0 {
152 sort.SliceStable(ports, func(i, j int) bool {
153 return bridgePortRefSortKey(ports[i]) < bridgePortRefSortKey(ports[j])
154 })
155 port := ports[0]
156 if hint.ifIndex == 0 && port.ifIndex > 0 {
157 hint.ifIndex = port.ifIndex
158 }
159 if strings.TrimSpace(hint.ifName) == "" && strings.TrimSpace(port.ifName) != "" {
160 hint.ifName = strings.TrimSpace(port.ifName)
161 }
162 }
163 if hint.ifIndex == 0 {
164 for _, value := range labelsCSVToSlice(endpointLabels, "learned_if_indexes") {
165 value = strings.TrimSpace(value)
166 if value == "" {
167 continue
168 }
169 if n, err := strconv.Atoi(value); err == nil && n > 0 {
170 hint.ifIndex = n
171 break
172 }
173 }
174 }
175 if strings.TrimSpace(hint.ifName) == "" {
176 for _, value := range labelsCSVToSlice(endpointLabels, "learned_if_names") {
177 value = strings.TrimSpace(value)
178 if value == "" {
179 continue
180 }
181 hint.ifName = value
182 break
183 }
184 }
185 if hint.ifIndex == 0 && strings.TrimSpace(hint.ifName) == "" {
186 hint.ifName = "0"
187 }
188 return hint
189 }
190
191 func ensureProbablePortlessSegment(
192 segmentByID map[string]*bridgeDomainSegment,
193 hint probableEndpointReporterHint,
194 ) (string, bool) {
195 deviceID := strings.TrimSpace(hint.deviceID)
196 if deviceID == "" {
197 return "", false
198 }
199 port := bridgePortRef{
200 deviceID: deviceID,
201 ifIndex: hint.ifIndex,
202 ifName: strings.TrimSpace(hint.ifName),
203 }
204 if port.ifIndex == 0 && strings.TrimSpace(port.ifName) == "" {
205 port.ifName = "0"
206 }
207
208 segmentID := "bridge-domain:probable:" + bridgePortRefSortKey(port)
209 if _, ok := segmentByID[segmentID]; ok {
210 return segmentID, false
211 }
212 segment := newBridgeDomainSegment(port)
213 segment.methods["probable"] = struct{}{}
214 segmentByID[segmentID] = segment
215 return segmentID, true
216 }