master
go 318 lines 8.28 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 // NetworkRouterTopology mirrors Enlinkd NetworkRouterTopologyUpdater graph payload.
12 type NetworkRouterTopology struct {
13 Vertices []NetworkRouterVertex
14 Edges []NetworkRouterEdge
15 DefaultVertex string
16 }
17
18 // NetworkRouterVertex is one node or subnet vertex in the network-router topology.
19 type NetworkRouterVertex struct {
20 ID string
21 Label string
22 Address string
23 IconKey string
24 NodeID int
25 ToolTip string
26 IsSubnet bool
27 }
28
29 // NetworkRouterPort is one endpoint port in the network-router topology.
30 type NetworkRouterPort struct {
31 ID string
32 Vertex string
33 IPID int
34 IfIndex int
35 IfName string
36 Addr string
37 ToolTip string
38 }
39
40 // NetworkRouterEdge is one link in the network-router topology.
41 type NetworkRouterEdge struct {
42 ID string
43 SourcePort NetworkRouterPort
44 TargetPort NetworkRouterPort
45 }
46
47 // BuildNetworkRouterTopology ports NetworkRouterTopologyUpdater.buildTopology().
48 func BuildNetworkRouterTopology(service *NodeTopologyService, ipv4prefix, ipv6prefix int) NetworkRouterTopology {
49 if service == nil {
50 return NetworkRouterTopology{}
51 }
52
53 result := NetworkRouterTopology{}
54 vertexByID := make(map[string]NetworkRouterVertex)
55 edgeByID := make(map[string]NetworkRouterEdge)
56
57 nodeMap := make(map[int]NodeTopologyEntity)
58 for _, node := range service.FindAllNode() {
59 nodeMap[node.ID] = node
60 }
61 ipPrimaryMap := getIPPrimaryMap(service.FindAllIP())
62 ipTable := getIPInterfaceTable(service.FindAllIP())
63 snmpByID := make(map[int]SnmpInterfaceTopologyEntity)
64 for _, snmp := range service.FindAllSnmp() {
65 snmpByID[snmp.ID] = snmp
66 }
67
68 addVertex := func(v NetworkRouterVertex) {
69 if strings.TrimSpace(v.ID) == "" {
70 return
71 }
72 if _, exists := vertexByID[v.ID]; exists {
73 return
74 }
75 vertexByID[v.ID] = v
76 }
77 addEdge := func(e NetworkRouterEdge) {
78 if strings.TrimSpace(e.ID) == "" {
79 return
80 }
81 if _, exists := edgeByID[e.ID]; exists {
82 return
83 }
84 edgeByID[e.ID] = e
85 }
86
87 for _, node := range service.FindAllNode() {
88 primary := ipPrimaryMap[node.ID]
89 addVertex(createNodeVertex(node, primary))
90 }
91
92 for _, subnet := range service.FindAllLegalPointToPointSubNetwork() {
93 if subnet == nil {
94 continue
95 }
96 nodeIDs := subnet.NodeIDs()
97 if len(nodeIDs) < 2 {
98 continue
99 }
100 sourceNodeID := nodeIDs[0]
101 targetNodeID := nodeIDs[1]
102
103 source, sourceOK := nodeMap[sourceNodeID]
104 target, targetOK := nodeMap[targetNodeID]
105 if !sourceOK || !targetOK {
106 continue
107 }
108
109 sourceIP, sourceIPOK := firstIPInSubnet(ipTable[sourceNodeID], subnet)
110 targetIP, targetIPOK := firstIPInSubnet(ipTable[targetNodeID], subnet)
111 if !sourceIPOK || !targetIPOK {
112 continue
113 }
114
115 sourcePort := createNodePort(createNodeVertex(source, ipPrimaryMap[source.ID]), sourceIP, snmpByID[sourceIP.SnmpInterfaceID])
116 targetPort := createNodePort(createNodeVertex(target, ipPrimaryMap[target.ID]), targetIP, snmpByID[targetIP.SnmpInterfaceID])
117 addEdge(NetworkRouterEdge{
118 ID: sourcePort.Vertex + keySep + sourcePort.ID + "->" + targetPort.Vertex + keySep + targetPort.ID,
119 SourcePort: sourcePort,
120 TargetPort: targetPort,
121 })
122 }
123
124 for _, subnet := range service.FindSubNetworkByNetworkPrefixLessThen(ipv4prefix, ipv6prefix) {
125 if subnet == nil {
126 continue
127 }
128 networkVertex := createNetworkVertex(subnet)
129 addVertex(networkVertex)
130 for _, targetNodeID := range subnet.NodeIDs() {
131 targetNode, ok := nodeMap[targetNodeID]
132 if !ok {
133 continue
134 }
135 targetIP, found := firstIPInSubnet(ipTable[targetNodeID], subnet)
136 if !found {
137 continue
138 }
139 targetVertex := createNodeVertex(targetNode, ipPrimaryMap[targetNodeID])
140 sourcePort := createNetworkPort(networkVertex, targetIP)
141 targetPort := createNodePort(targetVertex, targetIP, snmpByID[targetIP.SnmpInterfaceID])
142 addEdge(NetworkRouterEdge{
143 ID: sourcePort.Vertex + keySep + sourcePort.ID + "->" + targetPort.Vertex + keySep + targetPort.ID,
144 SourcePort: sourcePort,
145 TargetPort: targetPort,
146 })
147 }
148 }
149
150 if len(ipPrimaryMap) > 0 {
151 nodeIDs := make([]int, 0, len(ipPrimaryMap))
152 for nodeID := range ipPrimaryMap {
153 nodeIDs = append(nodeIDs, nodeID)
154 }
155 sort.Ints(nodeIDs)
156 for _, nodeID := range nodeIDs {
157 if nodeID <= 0 {
158 continue
159 }
160 result.DefaultVertex = strconv.Itoa(nodeID)
161 break
162 }
163 }
164
165 result.Vertices = sortedNetworkRouterVertices(vertexByID)
166 result.Edges = sortedNetworkRouterEdges(edgeByID)
167 return result
168 }
169
170 func createNodeVertex(node NodeTopologyEntity, primary IPInterfaceTopologyEntity) NetworkRouterVertex {
171 address := ""
172 if primary.IPAddress.IsValid() {
173 address = primary.IPAddress.String()
174 } else if node.Address.IsValid() {
175 address = node.Address.String()
176 }
177 label := strings.TrimSpace(node.Label)
178 if label == "" {
179 label = strconv.Itoa(node.ID)
180 }
181 vertex := NetworkRouterVertex{
182 ID: strconv.Itoa(node.ID),
183 Label: label,
184 Address: address,
185 IconKey: "node",
186 NodeID: node.ID,
187 }
188 vertex.ToolTip = "Node: " + label
189 if address != "" {
190 vertex.ToolTip += " (" + address + ")"
191 }
192 return vertex
193 }
194
195 func createNodePort(vertex NetworkRouterVertex, ip IPInterfaceTopologyEntity, snmp SnmpInterfaceTopologyEntity) NetworkRouterPort {
196 port := NetworkRouterPort{
197 ID: ip.IPAddress.String(),
198 Vertex: vertex.ID,
199 IPID: ip.ID,
200 Addr: ip.IPAddress.String(),
201 }
202 if snmp.ID > 0 {
203 port.IfIndex = snmp.IfIndex
204 port.IfName = snmp.IfName
205 }
206 port.ToolTip = "Port " + port.Addr
207 if port.IfName != "" {
208 port.ToolTip += " (" + port.IfName + ")"
209 }
210 return port
211 }
212
213 func createNetworkPort(vertex NetworkRouterVertex, target IPInterfaceTopologyEntity) NetworkRouterPort {
214 addr := "to: " + target.IPAddress.String()
215 return NetworkRouterPort{
216 ID: vertex.ID + "to:" + target.IPAddress.String(),
217 Vertex: vertex.ID,
218 IPID: target.ID,
219 Addr: addr,
220 ToolTip: "Port " + addr,
221 }
222 }
223
224 func createNetworkVertex(network *SubNetwork) NetworkRouterVertex {
225 cidr := ""
226 nodeIDs := ""
227 if network != nil {
228 cidr = network.CIDR()
229 nodeIDValues := network.NodeIDs()
230 parts := make([]string, 0, len(nodeIDValues))
231 for _, nodeID := range nodeIDValues {
232 parts = append(parts, strconv.Itoa(nodeID))
233 }
234 nodeIDs = strings.Join(parts, ",")
235 }
236 return NetworkRouterVertex{
237 ID: cidr,
238 Label: cidr,
239 Address: cidr,
240 IconKey: "cloud",
241 ToolTip: "SubNetwork: " + cidr + ", Nodeids:[" + nodeIDs + "]",
242 IsSubnet: true,
243 }
244 }
245
246 func getIPPrimaryMap(ips []IPInterfaceTopologyEntity) map[int]IPInterfaceTopologyEntity {
247 primary := make(map[int]IPInterfaceTopologyEntity)
248 for _, ip := range ips {
249 if ip.NodeID <= 0 || !ip.IPAddress.IsValid() {
250 continue
251 }
252 current, exists := primary[ip.NodeID]
253 if !exists {
254 primary[ip.NodeID] = ip
255 continue
256 }
257 if ip.IsSnmpPrimary {
258 primary[ip.NodeID] = ip
259 continue
260 }
261 primary[ip.NodeID] = current
262 }
263 return primary
264 }
265
266 func getIPInterfaceTable(ips []IPInterfaceTopologyEntity) map[int][]IPInterfaceTopologyEntity {
267 table := make(map[int][]IPInterfaceTopologyEntity)
268 for _, ip := range ips {
269 if ip.NodeID <= 0 || !ip.IPAddress.IsValid() {
270 continue
271 }
272 table[ip.NodeID] = append(table[ip.NodeID], ip)
273 }
274 for nodeID := range table {
275 sort.Slice(table[nodeID], func(i, j int) bool {
276 if table[nodeID][i].ID != table[nodeID][j].ID {
277 return table[nodeID][i].ID < table[nodeID][j].ID
278 }
279 return compareAddr(table[nodeID][i].IPAddress, table[nodeID][j].IPAddress) < 0
280 })
281 }
282 return table
283 }
284
285 func firstIPInSubnet(ips []IPInterfaceTopologyEntity, subnet *SubNetwork) (IPInterfaceTopologyEntity, bool) {
286 for _, ip := range ips {
287 if subnet.IsInRange(ip.IPAddress) {
288 return ip, true
289 }
290 }
291 return IPInterfaceTopologyEntity{}, false
292 }
293
294 func sortedNetworkRouterVertices(values map[string]NetworkRouterVertex) []NetworkRouterVertex {
295 keys := make([]string, 0, len(values))
296 for key := range values {
297 keys = append(keys, key)
298 }
299 sort.Strings(keys)
300 result := make([]NetworkRouterVertex, 0, len(keys))
301 for _, key := range keys {
302 result = append(result, values[key])
303 }
304 return result
305 }
306
307 func sortedNetworkRouterEdges(values map[string]NetworkRouterEdge) []NetworkRouterEdge {
308 keys := make([]string, 0, len(values))
309 for key := range values {
310 keys = append(keys, key)
311 }
312 sort.Strings(keys)
313 result := make([]NetworkRouterEdge, 0, len(keys))
314 for _, key := range keys {
315 result = append(result, values[key])
316 }
317 return result
318 }