master
go 357 lines 8.88 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package l2topology
4
5 import "sort"
6
7 // NodeTopologyService ports Enlinkd NodeTopologyServiceImpl logic.
8 type NodeTopologyService struct {
9 nodes []NodeTopologyEntity
10 ips []IPInterfaceTopologyEntity
11 snmp []SnmpInterfaceTopologyEntity
12 }
13
14 // NewNodeTopologyService builds a deterministic node topology service snapshot.
15 func NewNodeTopologyService(nodes []NodeTopologyEntity, ips []IPInterfaceTopologyEntity, snmp []SnmpInterfaceTopologyEntity) *NodeTopologyService {
16 out := &NodeTopologyService{
17 nodes: append([]NodeTopologyEntity(nil), nodes...),
18 ips: append([]IPInterfaceTopologyEntity(nil), ips...),
19 snmp: append([]SnmpInterfaceTopologyEntity(nil), snmp...),
20 }
21
22 sort.Slice(out.nodes, func(i, j int) bool {
23 if out.nodes[i].ID != out.nodes[j].ID {
24 return out.nodes[i].ID < out.nodes[j].ID
25 }
26 return out.nodes[i].Label < out.nodes[j].Label
27 })
28 sort.Slice(out.ips, func(i, j int) bool {
29 if out.ips[i].ID != out.ips[j].ID {
30 return out.ips[i].ID < out.ips[j].ID
31 }
32 if out.ips[i].NodeID != out.ips[j].NodeID {
33 return out.ips[i].NodeID < out.ips[j].NodeID
34 }
35 return out.ips[i].IPAddress.String() < out.ips[j].IPAddress.String()
36 })
37 sort.Slice(out.snmp, func(i, j int) bool {
38 if out.snmp[i].ID != out.snmp[j].ID {
39 return out.snmp[i].ID < out.snmp[j].ID
40 }
41 if out.snmp[i].NodeID != out.snmp[j].NodeID {
42 return out.snmp[i].NodeID < out.snmp[j].NodeID
43 }
44 return out.snmp[i].IfIndex < out.snmp[j].IfIndex
45 })
46 return out
47 }
48
49 // FindAllNode returns all node entities.
50 func (s *NodeTopologyService) FindAllNode() []NodeTopologyEntity {
51 if s == nil {
52 return nil
53 }
54 return append([]NodeTopologyEntity(nil), s.nodes...)
55 }
56
57 // FindAllIP returns all IP interface entities.
58 func (s *NodeTopologyService) FindAllIP() []IPInterfaceTopologyEntity {
59 if s == nil {
60 return nil
61 }
62 return append([]IPInterfaceTopologyEntity(nil), s.ips...)
63 }
64
65 // FindAllSnmp returns all SNMP interface entities.
66 func (s *NodeTopologyService) FindAllSnmp() []SnmpInterfaceTopologyEntity {
67 if s == nil {
68 return nil
69 }
70 return append([]SnmpInterfaceTopologyEntity(nil), s.snmp...)
71 }
72
73 // FindAllSubNetwork ports NodeTopologyServiceImpl.findAllSubNetwork().
74 func (s *NodeTopologyService) FindAllSubNetwork() []*SubNetwork {
75 if s == nil {
76 return nil
77 }
78 byKey := make(map[string]*SubNetwork)
79 keys := make([]string, 0)
80
81 for _, ip := range s.ips {
82 if !ip.IsManaged || !ip.IPAddress.IsValid() || !ip.NetMask.IsValid() {
83 continue
84 }
85 network, ok := NetworkAddress(ip.IPAddress, ip.NetMask)
86 if !ok {
87 continue
88 }
89 key := subnetKey(network, ip.NetMask)
90 subnet := byKey[key]
91 if subnet == nil {
92 created, err := NewSubNetwork(ip.NodeID, ip.IPAddress, ip.NetMask)
93 if err != nil {
94 continue
95 }
96 byKey[key] = created
97 keys = append(keys, key)
98 continue
99 }
100 subnet.Add(ip.NodeID, ip.IPAddress)
101 }
102
103 for _, ip := range s.ips {
104 if !ip.IsManaged || !ip.IPAddress.IsValid() || ip.NetMask.IsValid() {
105 continue
106 }
107 for _, key := range keys {
108 subnet := byKey[key]
109 if subnet == nil {
110 continue
111 }
112 subnet.Add(ip.NodeID, ip.IPAddress)
113 }
114 }
115
116 sorted := sortedSubnetworkKeys(byKey)
117 result := make([]*SubNetwork, 0, len(sorted))
118 for _, key := range sorted {
119 subnet := byKey[key]
120 if subnet == nil {
121 continue
122 }
123 result = append(result, subnet.clone())
124 }
125 return result
126 }
127
128 // FindAllLegalSubNetwork ports NodeTopologyServiceImpl.findAllLegalSubNetwork().
129 func (s *NodeTopologyService) FindAllLegalSubNetwork() []*SubNetwork {
130 all := s.FindAllSubNetwork()
131 if len(all) == 0 {
132 return nil
133 }
134 result := make([]*SubNetwork, 0, len(all))
135 for _, subnet := range all {
136 if subnet == nil || subnet.HasDuplicatedAddress() {
137 continue
138 }
139 if InSameNetwork(subnet.Network(), loopbackAddrIPv4, subnet.Netmask()) {
140 continue
141 }
142 result = append(result, subnet)
143 }
144 return result
145 }
146
147 // FindSubNetworkByNetworkPrefixLessThen ports NodeTopologyServiceImpl.findSubNetworkByNetworkPrefixLessThen().
148 func (s *NodeTopologyService) FindSubNetworkByNetworkPrefixLessThen(ipv4prefix, ipv6prefix int) []*SubNetwork {
149 legal := s.FindAllLegalSubNetwork()
150 if len(legal) == 0 {
151 return nil
152 }
153 result := make([]*SubNetwork, 0, len(legal))
154 for _, subnet := range legal {
155 if subnet == nil {
156 continue
157 }
158 prefix := subnet.NetworkPrefix()
159 if subnet.IsIPv4Subnetwork() {
160 if prefix < ipv4prefix {
161 result = append(result, subnet)
162 }
163 continue
164 }
165 if prefix < ipv6prefix {
166 result = append(result, subnet)
167 }
168 }
169 return result
170 }
171
172 // FindAllPointToPointSubNetwork ports NodeTopologyServiceImpl.findAllPointToPointSubNetwork().
173 func (s *NodeTopologyService) FindAllPointToPointSubNetwork() []*SubNetwork {
174 all := s.FindAllSubNetwork()
175 if len(all) == 0 {
176 return nil
177 }
178 result := make([]*SubNetwork, 0, len(all))
179 for _, subnet := range all {
180 if subnet == nil {
181 continue
182 }
183 if IsPointToPointMask(subnet.Netmask()) {
184 result = append(result, subnet)
185 }
186 }
187 return result
188 }
189
190 // FindAllLegalPointToPointSubNetwork ports NodeTopologyServiceImpl.findAllLegalPointToPointSubNetwork().
191 func (s *NodeTopologyService) FindAllLegalPointToPointSubNetwork() []*SubNetwork {
192 legal := s.FindAllLegalSubNetwork()
193 if len(legal) == 0 {
194 return nil
195 }
196 result := make([]*SubNetwork, 0, len(legal))
197 for _, subnet := range legal {
198 if subnet == nil {
199 continue
200 }
201 if IsPointToPointMask(subnet.Netmask()) && len(subnet.NodeIDs()) == 2 {
202 result = append(result, subnet)
203 }
204 }
205 return result
206 }
207
208 // FindAllLoopbacks ports NodeTopologyServiceImpl.findAllLoopbacks().
209 func (s *NodeTopologyService) FindAllLoopbacks() []*SubNetwork {
210 all := s.FindAllSubNetwork()
211 if len(all) == 0 {
212 return nil
213 }
214 result := make([]*SubNetwork, 0, len(all))
215 for _, subnet := range all {
216 if subnet == nil {
217 continue
218 }
219 if IsLoopbackMask(subnet.Netmask()) {
220 result = append(result, subnet)
221 }
222 }
223 return result
224 }
225
226 // FindAllLegalLoopbacks ports NodeTopologyServiceImpl.findAllLegalLoopbacks().
227 func (s *NodeTopologyService) FindAllLegalLoopbacks() []*SubNetwork {
228 all := s.FindAllSubNetwork()
229 if len(all) == 0 {
230 return nil
231 }
232 result := make([]*SubNetwork, 0, len(all))
233 for _, subnet := range all {
234 if subnet == nil {
235 continue
236 }
237 if IsLoopbackMask(subnet.Netmask()) && len(subnet.NodeIDs()) == 1 {
238 result = append(result, subnet)
239 }
240 }
241 return result
242 }
243
244 // GetNodeIDPriorityMap ports NodeTopologyServiceImpl.getNodeidPriorityMap().
245 func (s *NodeTopologyService) GetNodeIDPriorityMap() map[int]int {
246 priorityMap := make(map[int]int)
247 legal := s.FindAllLegalSubNetwork()
248 remaining := make(map[string]*SubNetwork)
249 for _, subnet := range legal {
250 if subnet == nil || len(subnet.NodeIDs()) <= 1 {
251 continue
252 }
253 remaining[subnet.key()] = subnet
254 }
255
256 priority := 0
257 for len(remaining) > 0 {
258 start := getNextSubnetwork(remaining)
259 if start == nil {
260 break
261 }
262 delete(remaining, start.key())
263 for _, nodeID := range start.NodeIDs() {
264 priorityMap[nodeID] = priority
265 }
266 priority = getConnectedSubnets(start, remaining, priorityMap, priority+1)
267 }
268 return priorityMap
269 }
270
271 func getNextSubnetwork(subnets map[string]*SubNetwork) *SubNetwork {
272 var selected *SubNetwork
273 for _, subnet := range subnets {
274 if subnet == nil {
275 continue
276 }
277 if selected == nil {
278 selected = subnet
279 continue
280 }
281 selectedSize := len(selected.NodeIDs())
282 subnetSize := len(subnet.NodeIDs())
283 if selectedSize < subnetSize {
284 selected = subnet
285 continue
286 }
287 if selectedSize != subnetSize {
288 continue
289 }
290 if compareAddr(selected.Network(), subnet.Network()) > 0 {
291 selected = subnet
292 }
293 }
294 return selected
295 }
296
297 func getConnectedSubnets(starting *SubNetwork, subnetworks map[string]*SubNetwork, priorityMap map[int]int, priority int) int {
298 if starting == nil || len(subnetworks) == 0 {
299 return priority
300 }
301
302 downlevels := make([]*SubNetwork, 0)
303 for _, subnet := range subnetworks {
304 if subnet == nil {
305 continue
306 }
307 if hasNodeIntersection(starting, subnet) {
308 downlevels = append(downlevels, subnet)
309 }
310 }
311 for _, subnet := range downlevels {
312 delete(subnetworks, subnet.key())
313 }
314
315 for _, subnet := range downlevels {
316 if subnet == nil {
317 continue
318 }
319 addingNodes := make([]int, 0)
320 for _, nodeID := range subnet.NodeIDs() {
321 if _, exists := priorityMap[nodeID]; exists {
322 continue
323 }
324 addingNodes = append(addingNodes, nodeID)
325 }
326 if len(addingNodes) == 0 {
327 continue
328 }
329 for _, nodeID := range addingNodes {
330 priorityMap[nodeID] = priority
331 }
332 priority++
333 }
334
335 if len(downlevels) > 0 && len(subnetworks) > 0 {
336 for _, level := range downlevels {
337 priority = getConnectedSubnets(level, subnetworks, priorityMap, priority)
338 }
339 }
340 return priority
341 }
342
343 func hasNodeIntersection(left, right *SubNetwork) bool {
344 if left == nil || right == nil {
345 return false
346 }
347 rightIDs := make(map[int]struct{}, len(right.nodeInterfaceMap))
348 for nodeID := range right.nodeInterfaceMap {
349 rightIDs[nodeID] = struct{}{}
350 }
351 for nodeID := range left.nodeInterfaceMap {
352 if _, ok := rightIDs[nodeID]; ok {
353 return true
354 }
355 }
356 return false
357 }