master
go 120 lines 3.34 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package l2topology
4
5 import (
6 "strconv"
7 "strings"
8 )
9
10 func (s *l2BuildState) applyBridge(observations []L2Observation) {
11 for _, obs := range observations {
12 sourceID := strings.TrimSpace(obs.DeviceID)
13 if sourceID == "" {
14 continue
15 }
16
17 bridgePortToIfIndex := make(map[string]int, len(obs.BridgePorts))
18 for _, bridgePort := range sortedBridgePorts(obs.BridgePorts) {
19 basePort := strings.TrimSpace(bridgePort.BasePort)
20 if basePort == "" || bridgePort.IfIndex <= 0 {
21 continue
22 }
23 bridgePortToIfIndex[basePort] = bridgePort.IfIndex
24 }
25
26 for _, candidate := range buildFDBCandidates(obs.FDBEntries, bridgePortToIfIndex) {
27 endpointID := "mac:" + candidate.mac
28 attachment := Attachment{
29 DeviceID: sourceID,
30 IfIndex: candidate.ifIndex,
31 EndpointID: endpointID,
32 Method: "fdb",
33 }
34
35 labels := make(map[string]string)
36 if candidate.bridgePort != "" {
37 labels["bridge_port"] = candidate.bridgePort
38 }
39 if status := strings.TrimSpace(candidate.statusRaw); status != "" {
40 labels["fdb_status"] = status
41 }
42 if candidate.ifIndex > 0 {
43 ifName := strings.TrimSpace(s.ifNameByDeviceIfIndex[deviceIfIndexKey(sourceID, candidate.ifIndex)])
44 if ifName != "" {
45 labels["if_name"] = ifName
46 }
47 labels["bridge_domain"] = deriveBridgeDomainFromIfIndex(sourceID, candidate.ifIndex)
48 } else if candidate.bridgePort != "" {
49 labels["bridge_domain"] = deriveBridgeDomainFromBridgePort(sourceID, candidate.bridgePort)
50 }
51 if candidate.vlanID != "" {
52 labels["vlan_id"] = candidate.vlanID
53 labels["vlan"] = candidate.vlanID
54 }
55 if candidate.vlanName != "" {
56 labels["vlan_name"] = candidate.vlanName
57 }
58 if len(labels) > 0 {
59 attachment.Labels = labels
60 }
61
62 if addAttachment(s.attachments, attachment) {
63 s.attachmentsFDB++
64 s.endpointIDs[endpointID] = struct{}{}
65 if domain := attachmentDomain(attachment); domain != "" {
66 s.bridgeDomains[domain] = struct{}{}
67 }
68 }
69 }
70 }
71 }
72
73 func (s *l2BuildState) applyARP(observations []L2Observation) {
74 for _, obs := range observations {
75 sourceID := strings.TrimSpace(obs.DeviceID)
76 if sourceID == "" {
77 continue
78 }
79 for _, entry := range sortedARPNDEntries(obs.ARPNDEntries) {
80 mac := normalizeMAC(entry.MAC)
81 ip := canonicalIP(entry.IP)
82 if mac == "" {
83 continue
84 }
85
86 endpointID := "mac:" + mac
87 acc := ensureEnrichmentAccumulator(s.enrichments, endpointID)
88 acc.EndpointID = endpointID
89 acc.MAC = mac
90 if ip != "" {
91 addr := parseAddr(ip)
92 if addr.IsValid() {
93 acc.IPs[addr.String()] = addr
94 }
95 }
96
97 protocol := canonicalARPProtocol(entry.Protocol)
98 acc.Protocols[protocol] = struct{}{}
99 acc.DeviceIDs[sourceID] = struct{}{}
100 if entry.IfIndex > 0 {
101 acc.IfIndexes[strconv.Itoa(entry.IfIndex)] = struct{}{}
102 }
103 ifName := strings.TrimSpace(entry.IfName)
104 if ifName == "" && entry.IfIndex > 0 {
105 ifName = strings.TrimSpace(s.ifNameByDeviceIfIndex[deviceIfIndexKey(sourceID, entry.IfIndex)])
106 }
107 if ifName != "" {
108 acc.IfNames[ifName] = struct{}{}
109 }
110 if state := strings.TrimSpace(entry.State); state != "" {
111 acc.States[state] = struct{}{}
112 }
113 if addrType := canonicalAddrType(entry.AddrType, ip); addrType != "" {
114 acc.AddrTypes[addrType] = struct{}{}
115 }
116 }
117 }
118 s.refreshEndpointIndex()
119 s.enrichmentsARPND = len(s.enrichments)
120 }