master
go 291 lines 6.86 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package l2topology
4
5 import (
6 "sort"
7 "strings"
8 )
9
10 func sortedLLDPRemotes(in []LLDPRemoteObservation) []LLDPRemoteObservation {
11 out := make([]LLDPRemoteObservation, 0, len(in))
12 for _, remote := range in {
13 if strings.TrimSpace(remote.ChassisID) == "" && strings.TrimSpace(remote.SysName) == "" {
14 continue
15 }
16 out = append(out, remote)
17 }
18 sort.Slice(out, func(i, j int) bool {
19 a, b := out[i], out[j]
20 if a.LocalPortNum != b.LocalPortNum {
21 return a.LocalPortNum < b.LocalPortNum
22 }
23 if a.RemoteIndex != b.RemoteIndex {
24 return a.RemoteIndex < b.RemoteIndex
25 }
26 if a.SysName != b.SysName {
27 return a.SysName < b.SysName
28 }
29 if a.ChassisID != b.ChassisID {
30 return a.ChassisID < b.ChassisID
31 }
32 if a.PortID != b.PortID {
33 return a.PortID < b.PortID
34 }
35 if a.PortIDSubtype != b.PortIDSubtype {
36 return a.PortIDSubtype < b.PortIDSubtype
37 }
38 if a.LocalPortIDSubtype != b.LocalPortIDSubtype {
39 return a.LocalPortIDSubtype < b.LocalPortIDSubtype
40 }
41 if a.PortDesc != b.PortDesc {
42 return a.PortDesc < b.PortDesc
43 }
44 if a.LocalPortDesc != b.LocalPortDesc {
45 return a.LocalPortDesc < b.LocalPortDesc
46 }
47 return a.ManagementIP < b.ManagementIP
48 })
49 return out
50 }
51
52 func sortedCDPRemotes(in []CDPRemoteObservation) []CDPRemoteObservation {
53 out := make([]CDPRemoteObservation, 0, len(in))
54 for _, remote := range in {
55 if strings.TrimSpace(remote.DeviceID) == "" && strings.TrimSpace(remote.Address) == "" {
56 continue
57 }
58 out = append(out, remote)
59 }
60 sort.Slice(out, func(i, j int) bool {
61 a, b := out[i], out[j]
62 if a.LocalIfIndex != b.LocalIfIndex {
63 return a.LocalIfIndex < b.LocalIfIndex
64 }
65 if a.DeviceIndex != b.DeviceIndex {
66 return a.DeviceIndex < b.DeviceIndex
67 }
68 if a.SysName != b.SysName {
69 return a.SysName < b.SysName
70 }
71 if a.DeviceID != b.DeviceID {
72 return a.DeviceID < b.DeviceID
73 }
74 return a.Address < b.Address
75 })
76 return out
77 }
78
79 func sortedBridgePorts(in []BridgePortObservation) []BridgePortObservation {
80 out := make([]BridgePortObservation, 0, len(in))
81 for _, bridgePort := range in {
82 if strings.TrimSpace(bridgePort.BasePort) == "" || bridgePort.IfIndex <= 0 {
83 continue
84 }
85 out = append(out, bridgePort)
86 }
87 sort.Slice(out, func(i, j int) bool {
88 a, b := out[i], out[j]
89 if a.BasePort != b.BasePort {
90 return a.BasePort < b.BasePort
91 }
92 return a.IfIndex < b.IfIndex
93 })
94 return out
95 }
96
97 func sortedSTPPortEntries(in []STPPortObservation) []STPPortObservation {
98 out := make([]STPPortObservation, 0, len(in))
99 for _, entry := range in {
100 if strings.TrimSpace(entry.Port) == "" {
101 continue
102 }
103 out = append(out, entry)
104 }
105 sort.Slice(out, func(i, j int) bool {
106 a, b := out[i], out[j]
107 if a.Port != b.Port {
108 return a.Port < b.Port
109 }
110 if a.VLANID != b.VLANID {
111 return a.VLANID < b.VLANID
112 }
113 if a.IfIndex != b.IfIndex {
114 return a.IfIndex < b.IfIndex
115 }
116 if a.IfName != b.IfName {
117 return a.IfName < b.IfName
118 }
119 return a.DesignatedBridge < b.DesignatedBridge
120 })
121 return out
122 }
123
124 func sortedFDBEntries(in []FDBObservation) []FDBObservation {
125 out := make([]FDBObservation, 0, len(in))
126 for _, entry := range in {
127 if strings.TrimSpace(entry.MAC) == "" {
128 continue
129 }
130 out = append(out, entry)
131 }
132 sort.Slice(out, func(i, j int) bool {
133 a, b := out[i], out[j]
134 if a.BridgePort != b.BridgePort {
135 return a.BridgePort < b.BridgePort
136 }
137 if a.VLANID != b.VLANID {
138 return a.VLANID < b.VLANID
139 }
140 if a.IfIndex != b.IfIndex {
141 return a.IfIndex < b.IfIndex
142 }
143 if a.MAC != b.MAC {
144 return a.MAC < b.MAC
145 }
146 return a.Status < b.Status
147 })
148 return out
149 }
150
151 func sortedARPNDEntries(in []ARPNDObservation) []ARPNDObservation {
152 out := make([]ARPNDObservation, 0, len(in))
153 for _, entry := range in {
154 if strings.TrimSpace(entry.MAC) == "" && strings.TrimSpace(entry.IP) == "" {
155 continue
156 }
157 out = append(out, entry)
158 }
159 sort.Slice(out, func(i, j int) bool {
160 a, b := out[i], out[j]
161 if a.Protocol != b.Protocol {
162 return a.Protocol < b.Protocol
163 }
164 if a.IfIndex != b.IfIndex {
165 return a.IfIndex < b.IfIndex
166 }
167 if a.IP != b.IP {
168 return a.IP < b.IP
169 }
170 if a.MAC != b.MAC {
171 return a.MAC < b.MAC
172 }
173 if a.State != b.State {
174 return a.State < b.State
175 }
176 return a.AddrType < b.AddrType
177 })
178 return out
179 }
180
181 func sortedDevices(in map[string]Device) []Device {
182 out := make([]Device, 0, len(in))
183 for _, dev := range in {
184 out = append(out, dev)
185 }
186 sort.Slice(out, func(i, j int) bool {
187 if out[i].ID != out[j].ID {
188 return out[i].ID < out[j].ID
189 }
190 return out[i].Hostname < out[j].Hostname
191 })
192 return out
193 }
194
195 func sortedInterfaces(in map[string]Interface) []Interface {
196 out := make([]Interface, 0, len(in))
197 for _, iface := range in {
198 out = append(out, iface)
199 }
200 sort.Slice(out, func(i, j int) bool {
201 a, b := out[i], out[j]
202 if a.DeviceID != b.DeviceID {
203 return a.DeviceID < b.DeviceID
204 }
205 if a.IfIndex != b.IfIndex {
206 return a.IfIndex < b.IfIndex
207 }
208 return a.IfName < b.IfName
209 })
210 return out
211 }
212
213 func sortedAdjacencies(in map[string]Adjacency) []Adjacency {
214 out := make([]Adjacency, 0, len(in))
215 for _, adj := range in {
216 out = append(out, adj)
217 }
218 sort.Slice(out, func(i, j int) bool {
219 a, b := out[i], out[j]
220 if a.Protocol != b.Protocol {
221 return a.Protocol < b.Protocol
222 }
223 if a.SourceID != b.SourceID {
224 return a.SourceID < b.SourceID
225 }
226 if a.SourcePort != b.SourcePort {
227 return a.SourcePort < b.SourcePort
228 }
229 if a.TargetID != b.TargetID {
230 return a.TargetID < b.TargetID
231 }
232 return a.TargetPort < b.TargetPort
233 })
234 return out
235 }
236
237 func sortedAttachments(in map[string]Attachment) []Attachment {
238 out := make([]Attachment, 0, len(in))
239 for _, attachment := range in {
240 out = append(out, attachment)
241 }
242 sort.Slice(out, func(i, j int) bool {
243 a, b := out[i], out[j]
244 if a.DeviceID != b.DeviceID {
245 return a.DeviceID < b.DeviceID
246 }
247 if a.IfIndex != b.IfIndex {
248 return a.IfIndex < b.IfIndex
249 }
250 if a.EndpointID != b.EndpointID {
251 return a.EndpointID < b.EndpointID
252 }
253 return a.Method < b.Method
254 })
255 return out
256 }
257
258 func sortedEnrichments(in map[string]*enrichmentAccumulator) []Enrichment {
259 out := make([]Enrichment, 0, len(in))
260 for _, acc := range in {
261 if acc == nil || strings.TrimSpace(acc.EndpointID) == "" {
262 continue
263 }
264 enrichment := Enrichment{
265 EndpointID: acc.EndpointID,
266 MAC: acc.MAC,
267 IPs: sortedAddrValues(acc.IPs),
268 Labels: map[string]string{
269 "sources": setToCSV(acc.Protocols),
270 "device_ids": setToCSV(acc.DeviceIDs),
271 "if_indexes": setToCSV(acc.IfIndexes),
272 "if_names": setToCSV(acc.IfNames),
273 "states": setToCSV(acc.States),
274 "addr_types": setToCSV(acc.AddrTypes),
275 },
276 }
277 pruneEmptyLabels(enrichment.Labels)
278 out = append(out, enrichment)
279 }
280 sort.Slice(out, func(i, j int) bool {
281 a, b := out[i], out[j]
282 if a.EndpointID != b.EndpointID {
283 return a.EndpointID < b.EndpointID
284 }
285 if a.MAC != b.MAC {
286 return a.MAC < b.MAC
287 }
288 return len(a.IPs) < len(b.IPs)
289 })
290 return out
291 }