| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package l2topology |
| 4 | |
| 5 | import ( |
| 6 | "net/netip" |
| 7 | "sort" |
| 8 | "strings" |
| 9 | ) |
| 10 | |
| 11 | func sortedAddrValues(in map[string]netip.Addr) []netip.Addr { |
| 12 | if len(in) == 0 { |
| 13 | return nil |
| 14 | } |
| 15 | keys := make([]string, 0, len(in)) |
| 16 | for key := range in { |
| 17 | keys = append(keys, key) |
| 18 | } |
| 19 | sort.Strings(keys) |
| 20 | out := make([]netip.Addr, 0, len(keys)) |
| 21 | for _, key := range keys { |
| 22 | if addr, ok := in[key]; ok && addr.IsValid() { |
| 23 | out = append(out, addr) |
| 24 | } |
| 25 | } |
| 26 | return out |
| 27 | } |
| 28 | |
| 29 | func setToCSV(in map[string]struct{}) string { |
| 30 | if len(in) == 0 { |
| 31 | return "" |
| 32 | } |
| 33 | out := make([]string, 0, len(in)) |
| 34 | for value := range in { |
| 35 | value = strings.TrimSpace(value) |
| 36 | if value == "" { |
| 37 | continue |
| 38 | } |
| 39 | out = append(out, value) |
| 40 | } |
| 41 | if len(out) == 0 { |
| 42 | return "" |
| 43 | } |
| 44 | sort.Strings(out) |
| 45 | return strings.Join(out, ",") |
| 46 | } |
| 47 | |
| 48 | func csvToTopologySet(value string) map[string]struct{} { |
| 49 | out := make(map[string]struct{}) |
| 50 | for token := range strings.SplitSeq(strings.TrimSpace(value), ",") { |
| 51 | token = strings.TrimSpace(strings.ToLower(token)) |
| 52 | if token == "" { |
| 53 | continue |
| 54 | } |
| 55 | out[token] = struct{}{} |
| 56 | } |
| 57 | return out |
| 58 | } |
| 59 | |
| 60 | func observationProtocolsUsed(obs L2Observation) map[string]struct{} { |
| 61 | out := make(map[string]struct{}, 6) |
| 62 | if len(obs.LLDPRemotes) > 0 { |
| 63 | out["lldp"] = struct{}{} |
| 64 | } |
| 65 | if len(obs.CDPRemotes) > 0 { |
| 66 | out["cdp"] = struct{}{} |
| 67 | } |
| 68 | if len(obs.BridgePorts) > 0 { |
| 69 | out["bridge"] = struct{}{} |
| 70 | } |
| 71 | if len(obs.FDBEntries) > 0 { |
| 72 | out["fdb"] = struct{}{} |
| 73 | } |
| 74 | if len(obs.STPPorts) > 0 { |
| 75 | out["stp"] = struct{}{} |
| 76 | } |
| 77 | if len(obs.ARPNDEntries) > 0 { |
| 78 | out["arp"] = struct{}{} |
| 79 | } |
| 80 | return out |
| 81 | } |
| 82 | |
| 83 | func pruneEmptyLabels(labels map[string]string) { |
| 84 | for key, value := range labels { |
| 85 | if strings.TrimSpace(value) == "" { |
| 86 | delete(labels, key) |
| 87 | } |
| 88 | } |
| 89 | } |