diff --git a/go.mod b/go.mod index a5c3bfcb..fe48d562 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/unpoller/unpoller -go 1.24.0 - -toolchain go1.24.2 +go 1.25.5 require ( github.com/DataDog/datadog-go/v5 v5.8.1 @@ -13,9 +11,9 @@ require ( github.com/prometheus/common v0.67.4 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 - github.com/unpoller/unifi/v5 v5.2.0 - golang.org/x/crypto v0.45.0 - golang.org/x/term v0.37.0 + github.com/unpoller/unifi/v5 v5.2.1 + golang.org/x/crypto v0.46.0 + golang.org/x/term v0.38.0 golift.io/cnfg v0.2.3 golift.io/cnfgfile v0.0.0-20240713024420-a5436d84eb48 golift.io/version v0.0.2 @@ -24,7 +22,7 @@ require ( require ( go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/net v0.47.0 // indirect + golang.org/x/net v0.48.0 // indirect ) require ( @@ -44,7 +42,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/procfs v0.16.1 // indirect - golang.org/x/sys v0.38.0 // indirect + golang.org/x/sys v0.39.0 // indirect google.golang.org/protobuf v1.36.10 // indirect ) diff --git a/go.sum b/go.sum index 62c88d6a..6f859e98 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/unpoller/unifi/v5 v5.2.0 h1:qw0fWRHjzabfYSXxV1ViJeRL+L6oILSBMqPcZyLzmO4= -github.com/unpoller/unifi/v5 v5.2.0/go.mod h1:zQwa4J4qM0ybv9EO51jHt78GsJdS2ySLzy8b5IHUQaY= +github.com/unpoller/unifi/v5 v5.2.1 h1:clcF0/UKYQm4ycWlM0Pe6f+NbmGGpky3KkfuGBBmsR0= +github.com/unpoller/unifi/v5 v5.2.1/go.mod h1:a9Hl1hBnDuaJDIvHswpW8/QUQgk3gQ5U9c5EnpZXMUg= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -84,14 +84,14 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -101,11 +101,11 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/datadogunifi/integration_test_expectations.yaml b/pkg/datadogunifi/integration_test_expectations.yaml index 2adb4a3b..343b1a53 100644 --- a/pkg/datadogunifi/integration_test_expectations.yaml +++ b/pkg/datadogunifi/integration_test_expectations.yaml @@ -370,6 +370,98 @@ gauges: - unifi.ubb.uplink_latency - unifi.ubb.uplink_max_speed - unifi.ubb.uplink_uptime + - unifi.ubb.upgradeable + - unifi.ubb.link_capacity + - unifi.ubb.link_quality + - unifi.ubb.link_quality_current + - unifi.ubb.p2p_rx_rate + - unifi.ubb.p2p_throughput + - unifi.ubb.p2p_tx_rate + - unifi.ubb.stat_duration + - unifi.ubb.stat_mac_filter_rejections + - unifi.ubb.stat_terra2_mac_filter_rejections + - unifi.ubb.stat_terra2_rx_bytes + - unifi.ubb.stat_terra2_rx_crypts + - unifi.ubb.stat_terra2_rx_dropped + - unifi.ubb.stat_terra2_rx_errors + - unifi.ubb.stat_terra2_rx_frags + - unifi.ubb.stat_terra2_rx_packets + - unifi.ubb.stat_terra2_tx_bytes + - unifi.ubb.stat_terra2_tx_dropped + - unifi.ubb.stat_terra2_tx_errors + - unifi.ubb.stat_terra2_tx_packets + - unifi.ubb.stat_terra2_tx_retries + - unifi.ubb.stat_terra2_wifi_tx_attempts + - unifi.ubb.stat_terra2_wifi_tx_dropped + - unifi.ubb.stat_user_mac_filter_rejections + - unifi.ubb.stat_user_rx_bytes + - unifi.ubb.stat_user_rx_crypts + - unifi.ubb.stat_user_rx_dropped + - unifi.ubb.stat_user_rx_errors + - unifi.ubb.stat_user_rx_frags + - unifi.ubb.stat_user_rx_packets + - unifi.ubb.stat_user_terra2_mac_filter_rejections + - unifi.ubb.stat_user_terra2_rx_bytes + - unifi.ubb.stat_user_terra2_rx_crypts + - unifi.ubb.stat_user_terra2_rx_dropped + - unifi.ubb.stat_user_terra2_rx_errors + - unifi.ubb.stat_user_terra2_rx_frags + - unifi.ubb.stat_user_terra2_rx_packets + - unifi.ubb.stat_user_terra2_tx_bytes + - unifi.ubb.stat_user_terra2_tx_dropped + - unifi.ubb.stat_user_terra2_tx_errors + - unifi.ubb.stat_user_terra2_tx_packets + - unifi.ubb.stat_user_terra2_tx_retries + - unifi.ubb.stat_user_terra2_wifi_tx_attempts + - unifi.ubb.stat_user_terra2_wifi_tx_dropped + - unifi.ubb.stat_user_terra2_wlan0_rx_bytes + - unifi.ubb.stat_user_terra2_wlan0_rx_errors + - unifi.ubb.stat_user_terra2_wlan0_rx_packets + - unifi.ubb.stat_user_terra2_wlan0_tx_bytes + - unifi.ubb.stat_user_terra2_wlan0_tx_dropped + - unifi.ubb.stat_user_terra2_wlan0_tx_errors + - unifi.ubb.stat_user_terra2_wlan0_tx_packets + - unifi.ubb.stat_user_tx_bytes + - unifi.ubb.stat_user_tx_dropped + - unifi.ubb.stat_user_tx_errors + - unifi.ubb.stat_user_tx_packets + - unifi.ubb.stat_user_tx_retries + - unifi.ubb.stat_user_wifi0_ath0_rx_bytes + - unifi.ubb.stat_user_wifi0_ath0_rx_packets + - unifi.ubb.stat_user_wifi0_ath0_tx_bytes + - unifi.ubb.stat_user_wifi0_ath0_tx_packets + - unifi.ubb.stat_user_wifi0_mac_filter_rejections + - unifi.ubb.stat_user_wifi0_rx_bytes + - unifi.ubb.stat_user_wifi0_rx_crypts + - unifi.ubb.stat_user_wifi0_rx_dropped + - unifi.ubb.stat_user_wifi0_rx_errors + - unifi.ubb.stat_user_wifi0_rx_frags + - unifi.ubb.stat_user_wifi0_rx_packets + - unifi.ubb.stat_user_wifi0_tx_bytes + - unifi.ubb.stat_user_wifi0_tx_dropped + - unifi.ubb.stat_user_wifi0_tx_errors + - unifi.ubb.stat_user_wifi0_tx_packets + - unifi.ubb.stat_user_wifi0_tx_retries + - unifi.ubb.stat_user_wifi0_wifi_tx_attempts + - unifi.ubb.stat_user_wifi0_wifi_tx_dropped + - unifi.ubb.stat_user_wifi_tx_attempts + - unifi.ubb.stat_user_wifi_tx_dropped + - unifi.ubb.stat_wifi0_mac_filter_rejections + - unifi.ubb.stat_wifi0_rx_bytes + - unifi.ubb.stat_wifi0_rx_crypts + - unifi.ubb.stat_wifi0_rx_dropped + - unifi.ubb.stat_wifi0_rx_errors + - unifi.ubb.stat_wifi0_rx_frags + - unifi.ubb.stat_wifi0_rx_packets + - unifi.ubb.stat_wifi0_tx_bytes + - unifi.ubb.stat_wifi0_tx_dropped + - unifi.ubb.stat_wifi0_tx_errors + - unifi.ubb.stat_wifi0_tx_packets + - unifi.ubb.stat_wifi0_tx_retries + - unifi.ubb.stat_wifi0_wifi_tx_attempts + - unifi.ubb.stat_wifi0_wifi_tx_dropped + - unifi.ubb.stat_wifi_tx_attempts + - unifi.ubb.stat_wifi_tx_dropped - unifi.usg.uplink_max_speed - unifi.usg.uplink_uptime - unifi.ubb.stat_rx_frags diff --git a/pkg/datadogunifi/ubb.go b/pkg/datadogunifi/ubb.go index e1e5ab7e..119e3cd3 100644 --- a/pkg/datadogunifi/ubb.go +++ b/pkg/datadogunifi/ubb.go @@ -7,8 +7,10 @@ import ( // ubbT is used as a name for printed/logged counters. const ubbT = item("UBB") -// batchUBB generates UBB datapoints for Datadog. -// These points can be passed directly to datadog. +// batchUBB generates UBB (UniFi Building Bridge) datapoints for Datadog. +// UBB devices are point-to-point wireless bridges with dual radios: +// - wifi0: 5GHz radio (802.11ac) +// - terra2/wlan0/ad: 60GHz radio (802.11ad - Terragraph/WiGig) func (u *DatadogUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen if !s.Adopted.Val || s.Locating.Val { return @@ -27,11 +29,6 @@ func (u *DatadogUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen "license_state": s.LicenseState, }) - var sw *unifi.Bb - if s.Stat != nil { - sw = s.Stat.Bb - } - sysStats := unifi.SysStats{} if s.SysStats != nil { sysStats = *s.SysStats @@ -44,6 +41,7 @@ func (u *DatadogUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen data := CombineFloat64( u.batchSysStats(sysStats, systemStats), + u.batchUBBstats(s.Stat), map[string]float64{ "bytes": s.Bytes.Val, "last_seen": s.LastSeen.Val, @@ -59,53 +57,148 @@ func (u *DatadogUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen }, ) + // Add upgradeable as a float64 (0 or 1) + if s.Upgradable.Val { + data["upgradeable"] = 1.0 + } else { + data["upgradeable"] = 0.0 + } + + // Add UBB-specific P2P and link quality metrics + if s.P2PStats != nil { + data["p2p_rx_rate"] = s.P2PStats.RXRate.Val + data["p2p_tx_rate"] = s.P2PStats.TXRate.Val + data["p2p_throughput"] = s.P2PStats.Throughput.Val + } + data["link_quality"] = s.LinkQuality.Val + data["link_quality_current"] = s.LinkQualityCurrent.Val + data["link_capacity"] = s.LinkCapacity.Val + r.addCount(ubbT) metricName := metricNamespace("ubb") reportGaugeForFloat64Map(r, metricName, data, tags) - tags = cleanTags(map[string]string{ - "mac": s.Mac, - "site_name": s.SiteName, - "source": s.SourceName, - "name": s.Name, - "version": s.Version, - "model": s.Model, - "serial": s.Serial, - "type": s.Type, - "ip": s.IP, - }) - data = CombineFloat64( - u.batchUBBstat(sw), - map[string]float64{ - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - }) + // Export VAP table (Virtual Access Point table - wireless interface stats) + u.processVAPTable(r, tags, s.VapTable) - metricName = metricNamespace("ubb") - reportGaugeForFloat64Map(r, metricName, data, tags) + // Export Radio tables (includes 5GHz wifi0 and 60GHz terra2/ad radios) + u.processRadTable(r, tags, s.RadioTable, s.RadioTableStats) } -func (u *DatadogUnifi) batchUBBstat(sw *unifi.Bb) map[string]float64 { - if sw == nil { +// batchUBBstats generates UBB-specific statistics separated by radio. +// This includes metrics for total, wifi0 (5GHz), terra2 (60GHz), and user-specific stats. +func (u *DatadogUnifi) batchUBBstats(stat *unifi.UBBStat) map[string]float64 { + if stat == nil || stat.Bb == nil { return map[string]float64{} } + bb := stat.Bb + + // Total aggregated stats across both radios return map[string]float64{ - "stat_bytes": sw.Bytes.Val, - "stat_rx_bytes": sw.RxBytes.Val, - "stat_rx_crypts": sw.RxCrypts.Val, - "stat_rx_dropped": sw.RxDropped.Val, - "stat_rx_errors": sw.RxErrors.Val, - "stat_rx_frags": sw.RxFrags.Val, - "stat_rx_packets": sw.TxPackets.Val, - "stat_tx_bytes": sw.TxBytes.Val, - "stat_tx_dropped": sw.TxDropped.Val, - "stat_tx_errors": sw.TxErrors.Val, - "stat_tx_packets": sw.TxPackets.Val, - "stat_tx_retries": sw.TxRetries.Val, + "stat_bytes": bb.Bytes.Val, + "stat_duration": bb.Duration.Val, + "stat_rx_packets": bb.RxPackets.Val, + "stat_rx_bytes": bb.RxBytes.Val, + "stat_rx_errors": bb.RxErrors.Val, + "stat_rx_dropped": bb.RxDropped.Val, + "stat_rx_crypts": bb.RxCrypts.Val, + "stat_rx_frags": bb.RxFrags.Val, + "stat_tx_packets": bb.TxPackets.Val, + "stat_tx_bytes": bb.TxBytes.Val, + "stat_tx_errors": bb.TxErrors.Val, + "stat_tx_dropped": bb.TxDropped.Val, + "stat_tx_retries": bb.TxRetries.Val, + "stat_mac_filter_rejections": bb.MacFilterRejections.Val, + "stat_wifi_tx_attempts": bb.WifiTxAttempts.Val, + "stat_wifi_tx_dropped": bb.WifiTxDropped.Val, + // User aggregated stats + "stat_user_rx_packets": bb.UserRxPackets.Val, + "stat_user_rx_bytes": bb.UserRxBytes.Val, + "stat_user_rx_errors": bb.UserRxErrors.Val, + "stat_user_rx_dropped": bb.UserRxDropped.Val, + "stat_user_rx_crypts": bb.UserRxCrypts.Val, + "stat_user_rx_frags": bb.UserRxFrags.Val, + "stat_user_tx_packets": bb.UserTxPackets.Val, + "stat_user_tx_bytes": bb.UserTxBytes.Val, + "stat_user_tx_errors": bb.UserTxErrors.Val, + "stat_user_tx_dropped": bb.UserTxDropped.Val, + "stat_user_tx_retries": bb.UserTxRetries.Val, + "stat_user_mac_filter_rejections": bb.UserMacFilterRejections.Val, + "stat_user_wifi_tx_attempts": bb.UserWifiTxAttempts.Val, + "stat_user_wifi_tx_dropped": bb.UserWifiTxDropped.Val, + // wifi0 radio stats (5GHz) + "stat_wifi0_rx_packets": bb.Wifi0RxPackets.Val, + "stat_wifi0_rx_bytes": bb.Wifi0RxBytes.Val, + "stat_wifi0_rx_errors": bb.Wifi0RxErrors.Val, + "stat_wifi0_rx_dropped": bb.Wifi0RxDropped.Val, + "stat_wifi0_rx_crypts": bb.Wifi0RxCrypts.Val, + "stat_wifi0_rx_frags": bb.Wifi0RxFrags.Val, + "stat_wifi0_tx_packets": bb.Wifi0TxPackets.Val, + "stat_wifi0_tx_bytes": bb.Wifi0TxBytes.Val, + "stat_wifi0_tx_errors": bb.Wifi0TxErrors.Val, + "stat_wifi0_tx_dropped": bb.Wifi0TxDropped.Val, + "stat_wifi0_tx_retries": bb.Wifi0TxRetries.Val, + "stat_wifi0_mac_filter_rejections": bb.Wifi0MacFilterRejections.Val, + "stat_wifi0_wifi_tx_attempts": bb.Wifi0WifiTxAttempts.Val, + "stat_wifi0_wifi_tx_dropped": bb.Wifi0WifiTxDropped.Val, + // terra2 radio stats (60GHz - 802.11ad) + "stat_terra2_rx_packets": bb.Terra2RxPackets.Val, + "stat_terra2_rx_bytes": bb.Terra2RxBytes.Val, + "stat_terra2_rx_errors": bb.Terra2RxErrors.Val, + "stat_terra2_rx_dropped": bb.Terra2RxDropped.Val, + "stat_terra2_rx_crypts": bb.Terra2RxCrypts.Val, + "stat_terra2_rx_frags": bb.Terra2RxFrags.Val, + "stat_terra2_tx_packets": bb.Terra2TxPackets.Val, + "stat_terra2_tx_bytes": bb.Terra2TxBytes.Val, + "stat_terra2_tx_errors": bb.Terra2TxErrors.Val, + "stat_terra2_tx_dropped": bb.Terra2TxDropped.Val, + "stat_terra2_tx_retries": bb.Terra2TxRetries.Val, + "stat_terra2_mac_filter_rejections": bb.Terra2MacFilterRejections.Val, + "stat_terra2_wifi_tx_attempts": bb.Terra2WifiTxAttempts.Val, + "stat_terra2_wifi_tx_dropped": bb.Terra2WifiTxDropped.Val, + // User wifi0 stats + "stat_user_wifi0_rx_packets": bb.UserWifi0RxPackets.Val, + "stat_user_wifi0_rx_bytes": bb.UserWifi0RxBytes.Val, + "stat_user_wifi0_rx_errors": bb.UserWifi0RxErrors.Val, + "stat_user_wifi0_rx_dropped": bb.UserWifi0RxDropped.Val, + "stat_user_wifi0_rx_crypts": bb.UserWifi0RxCrypts.Val, + "stat_user_wifi0_rx_frags": bb.UserWifi0RxFrags.Val, + "stat_user_wifi0_tx_packets": bb.UserWifi0TxPackets.Val, + "stat_user_wifi0_tx_bytes": bb.UserWifi0TxBytes.Val, + "stat_user_wifi0_tx_errors": bb.UserWifi0TxErrors.Val, + "stat_user_wifi0_tx_dropped": bb.UserWifi0TxDropped.Val, + "stat_user_wifi0_tx_retries": bb.UserWifi0TxRetries.Val, + "stat_user_wifi0_mac_filter_rejections": bb.UserWifi0MacFilterRejections.Val, + "stat_user_wifi0_wifi_tx_attempts": bb.UserWifi0WifiTxAttempts.Val, + "stat_user_wifi0_wifi_tx_dropped": bb.UserWifi0WifiTxDropped.Val, + // User terra2 stats (60GHz) + "stat_user_terra2_rx_packets": bb.UserTerra2RxPackets.Val, + "stat_user_terra2_rx_bytes": bb.UserTerra2RxBytes.Val, + "stat_user_terra2_rx_errors": bb.UserTerra2RxErrors.Val, + "stat_user_terra2_rx_dropped": bb.UserTerra2RxDropped.Val, + "stat_user_terra2_rx_crypts": bb.UserTerra2RxCrypts.Val, + "stat_user_terra2_rx_frags": bb.UserTerra2RxFrags.Val, + "stat_user_terra2_tx_packets": bb.UserTerra2TxPackets.Val, + "stat_user_terra2_tx_bytes": bb.UserTerra2TxBytes.Val, + "stat_user_terra2_tx_errors": bb.UserTerra2TxErrors.Val, + "stat_user_terra2_tx_dropped": bb.UserTerra2TxDropped.Val, + "stat_user_terra2_tx_retries": bb.UserTerra2TxRetries.Val, + "stat_user_terra2_mac_filter_rejections": bb.UserTerra2MacFilterRejections.Val, + "stat_user_terra2_wifi_tx_attempts": bb.UserTerra2WifiTxAttempts.Val, + "stat_user_terra2_wifi_tx_dropped": bb.UserTerra2WifiTxDropped.Val, + // Interface-specific stats + "stat_user_wifi0_ath0_rx_packets": bb.UserWifi0Ath0RxPackets.Val, + "stat_user_wifi0_ath0_rx_bytes": bb.UserWifi0Ath0RxBytes.Val, + "stat_user_wifi0_ath0_tx_packets": bb.UserWifi0Ath0TxPackets.Val, + "stat_user_wifi0_ath0_tx_bytes": bb.UserWifi0Ath0TxBytes.Val, + "stat_user_terra2_wlan0_rx_packets": bb.UserTerra2Wlan0RxPackets.Val, + "stat_user_terra2_wlan0_rx_bytes": bb.UserTerra2Wlan0RxBytes.Val, + "stat_user_terra2_wlan0_tx_packets": bb.UserTerra2Wlan0TxPackets.Val, + "stat_user_terra2_wlan0_tx_bytes": bb.UserTerra2Wlan0TxBytes.Val, + "stat_user_terra2_wlan0_tx_dropped": bb.UserTerra2Wlan0TxDropped.Val, + "stat_user_terra2_wlan0_rx_errors": bb.UserTerra2Wlan0RxErrors.Val, + "stat_user_terra2_wlan0_tx_errors": bb.UserTerra2Wlan0TxErrors.Val, } } diff --git a/pkg/influxunifi/integration_test_expectations.yaml b/pkg/influxunifi/integration_test_expectations.yaml index 7f63aad1..4e840773 100644 --- a/pkg/influxunifi/integration_test_expectations.yaml +++ b/pkg/influxunifi/integration_test_expectations.yaml @@ -406,6 +406,9 @@ points: ip: string last_seen: float license_state: string + link_capacity: float + link_quality: float + link_quality_current: float loadavg_1: float loadavg_5: float loadavg_15: float @@ -413,20 +416,108 @@ points: mem_buffer: float mem_total: float mem_used: float + p2p_rx_rate: float + p2p_throughput: float + p2p_tx_rate: float rx_bytes: float source: string stat_bytes: float + stat_duration: float + stat_mac_filter_rejections: float stat_rx_bytes: float stat_rx_crypts: float stat_rx_dropped: float stat_rx_errors: float stat_rx_frags: float stat_rx_packets: float + stat_terra2-mac_filter_rejections: float + stat_terra2-rx_bytes: float + stat_terra2-rx_crypts: float + stat_terra2-rx_dropped: float + stat_terra2-rx_errors: float + stat_terra2-rx_frags: float + stat_terra2-rx_packets: float + stat_terra2-tx_bytes: float + stat_terra2-tx_dropped: float + stat_terra2-tx_errors: float + stat_terra2-tx_packets: float + stat_terra2-tx_retries: float + stat_terra2-wifi_tx_attempts: float + stat_terra2-wifi_tx_dropped: float stat_tx_bytes: float stat_tx_dropped: float stat_tx_errors: float stat_tx_packets: float stat_tx_retries: float + stat_user-mac_filter_rejections: float + stat_user-rx_bytes: float + stat_user-rx_crypts: float + stat_user-rx_dropped: float + stat_user-rx_errors: float + stat_user-rx_frags: float + stat_user-rx_packets: float + stat_user-terra2-mac_filter_rejections: float + stat_user-terra2-rx_bytes: float + stat_user-terra2-rx_crypts: float + stat_user-terra2-rx_dropped: float + stat_user-terra2-rx_errors: float + stat_user-terra2-rx_frags: float + stat_user-terra2-rx_packets: float + stat_user-terra2-tx_bytes: float + stat_user-terra2-tx_dropped: float + stat_user-terra2-tx_errors: float + stat_user-terra2-tx_packets: float + stat_user-terra2-tx_retries: float + stat_user-terra2-wifi_tx_attempts: float + stat_user-terra2-wifi_tx_dropped: float + stat_user-terra2-wlan0-rx_bytes: float + stat_user-terra2-wlan0-rx_errors: float + stat_user-terra2-wlan0-rx_packets: float + stat_user-terra2-wlan0-tx_bytes: float + stat_user-terra2-wlan0-tx_dropped: float + stat_user-terra2-wlan0-tx_errors: float + stat_user-terra2-wlan0-tx_packets: float + stat_user-tx_bytes: float + stat_user-tx_dropped: float + stat_user-tx_errors: float + stat_user-tx_packets: float + stat_user-tx_retries: float + stat_user-wifi0-ath0-rx_bytes: float + stat_user-wifi0-ath0-rx_packets: float + stat_user-wifi0-ath0-tx_bytes: float + stat_user-wifi0-ath0-tx_packets: float + stat_user-wifi0-mac_filter_rejections: float + stat_user-wifi0-rx_bytes: float + stat_user-wifi0-rx_crypts: float + stat_user-wifi0-rx_dropped: float + stat_user-wifi0-rx_errors: float + stat_user-wifi0-rx_frags: float + stat_user-wifi0-rx_packets: float + stat_user-wifi0-tx_bytes: float + stat_user-wifi0-tx_dropped: float + stat_user-wifi0-tx_errors: float + stat_user-wifi0-tx_packets: float + stat_user-wifi0-tx_retries: float + stat_user-wifi0-wifi_tx_attempts: float + stat_user-wifi0-wifi_tx_dropped: float + stat_user-wifi_tx_attempts: float + stat_user-wifi_tx_dropped: float + stat_wifi0-mac_filter_rejections: float + stat_wifi0-rx_bytes: float + stat_wifi0-rx_crypts: float + stat_wifi0-rx_dropped: float + stat_wifi0-rx_errors: float + stat_wifi0-rx_frags: float + stat_wifi0-rx_packets: float + stat_wifi0-tx_bytes: float + stat_wifi0-tx_dropped: float + stat_wifi0-tx_errors: float + stat_wifi0-tx_packets: float + stat_wifi0-tx_retries: float + stat_wifi0-wifi_tx_attempts: float + stat_wifi0-wifi_tx_dropped: float + stat_wifi_tx_attempts: float + stat_wifi_tx_dropped: float state: float system_uptime: float temp_cpu: int @@ -439,6 +530,7 @@ points: uplink_max_speed: float uplink_speed: float uplink_uptime: float + upgradeable: bool uptime: float user-num_sta: float version: string diff --git a/pkg/influxunifi/ubb.go b/pkg/influxunifi/ubb.go index 2a63d893..4c379bbc 100644 --- a/pkg/influxunifi/ubb.go +++ b/pkg/influxunifi/ubb.go @@ -7,8 +7,10 @@ import ( // ubbT is used as a name for printed/logged counters. const ubbT = item("UBB") -// batchUXG generates UBB datapoints for InfluxDB. -// These points can be passed directly to influx. +// batchUBB generates UBB (UniFi Building Bridge) datapoints for InfluxDB. +// UBB devices are point-to-point wireless bridges with dual radios: +// - wifi0: 5GHz radio (802.11ac) +// - terra2/wlan0/ad: 60GHz radio (802.11ad - Terragraph/WiGig) func (u *InfluxUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen if !s.Adopted.Val || s.Locating.Val { return @@ -25,11 +27,6 @@ func (u *InfluxUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen "type": s.Type, } - var sw *unifi.Bb - if s.Stat != nil { - sw = s.Stat.Bb - } - sysStats := unifi.SysStats{} if s.SysStats != nil { sysStats = *s.SysStats @@ -42,6 +39,7 @@ func (u *InfluxUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen fields := Combine( u.batchSysStats(sysStats, systemStats), + u.batchUBBstats(s.Stat), map[string]any{ "source": s.SourceName, "ip": s.IP, @@ -58,53 +56,143 @@ func (u *InfluxUnifi) batchUBB(r report, s *unifi.UBB) { // nolint: funlen "uplink_max_speed": s.Uplink.MaxSpeed.Val, "uplink_latency": s.Uplink.Latency.Val, "uplink_uptime": s.Uplink.Uptime.Val, + "upgradeable": s.Upgradable.Val, }, ) + // Add UBB-specific P2P and link quality metrics + if s.P2PStats != nil { + fields["p2p_rx_rate"] = s.P2PStats.RXRate.Val + fields["p2p_tx_rate"] = s.P2PStats.TXRate.Val + fields["p2p_throughput"] = s.P2PStats.Throughput.Val + } + fields["link_quality"] = s.LinkQuality.Val + fields["link_quality_current"] = s.LinkQualityCurrent.Val + fields["link_capacity"] = s.LinkCapacity.Val + r.addCount(ubbT) r.send(&metric{Table: "ubb", Tags: tags, Fields: fields}) - tags = map[string]string{ - "mac": s.Mac, - "site_name": s.SiteName, - "source": s.SourceName, - "name": s.Name, - "version": s.Version, - "model": s.Model, - "serial": s.Serial, - "type": s.Type, - } - fields = Combine( - u.batchUBBstat(sw), - map[string]any{ - "ip": s.IP, - "bytes": s.Bytes.Val, - "last_seen": s.LastSeen.Val, - "rx_bytes": s.RxBytes.Val, - "tx_bytes": s.TxBytes.Val, - "uptime": s.Uptime.Val, - }) + // Export VAP table (Virtual Access Point table - wireless interface stats) + u.processVAPTable(r, tags, s.VapTable) - r.send(&metric{Table: "ubb", Tags: tags, Fields: fields}) + // Export Radio tables (includes 5GHz wifi0 and 60GHz terra2/ad radios) + u.processRadTable(r, tags, s.RadioTable, s.RadioTableStats) } -func (u *InfluxUnifi) batchUBBstat(sw *unifi.Bb) map[string]any { - if sw == nil { +// batchUBBstats generates UBB-specific statistics separated by radio. +// This includes metrics for total, wifi0 (5GHz), terra2 (60GHz), and user-specific stats. +func (u *InfluxUnifi) batchUBBstats(stat *unifi.UBBStat) map[string]any { + if stat == nil || stat.Bb == nil { return map[string]any{} } + bb := stat.Bb + + // Total aggregated stats across both radios return map[string]any{ - "stat_bytes": sw.Bytes.Val, - "stat_rx_bytes": sw.RxBytes.Val, - "stat_rx_crypts": sw.RxCrypts.Val, - "stat_rx_dropped": sw.RxDropped.Val, - "stat_rx_errors": sw.RxErrors.Val, - "stat_rx_frags": sw.RxFrags.Val, - "stat_rx_packets": sw.TxPackets.Val, - "stat_tx_bytes": sw.TxBytes.Val, - "stat_tx_dropped": sw.TxDropped.Val, - "stat_tx_errors": sw.TxErrors.Val, - "stat_tx_packets": sw.TxPackets.Val, - "stat_tx_retries": sw.TxRetries.Val, + "stat_bytes": bb.Bytes.Val, + "stat_duration": bb.Duration.Val, + "stat_rx_packets": bb.RxPackets.Val, + "stat_rx_bytes": bb.RxBytes.Val, + "stat_rx_errors": bb.RxErrors.Val, + "stat_rx_dropped": bb.RxDropped.Val, + "stat_rx_crypts": bb.RxCrypts.Val, + "stat_rx_frags": bb.RxFrags.Val, + "stat_tx_packets": bb.TxPackets.Val, + "stat_tx_bytes": bb.TxBytes.Val, + "stat_tx_errors": bb.TxErrors.Val, + "stat_tx_dropped": bb.TxDropped.Val, + "stat_tx_retries": bb.TxRetries.Val, + "stat_mac_filter_rejections": bb.MacFilterRejections.Val, + "stat_wifi_tx_attempts": bb.WifiTxAttempts.Val, + "stat_wifi_tx_dropped": bb.WifiTxDropped.Val, + // User aggregated stats + "stat_user-rx_packets": bb.UserRxPackets.Val, + "stat_user-rx_bytes": bb.UserRxBytes.Val, + "stat_user-rx_errors": bb.UserRxErrors.Val, + "stat_user-rx_dropped": bb.UserRxDropped.Val, + "stat_user-rx_crypts": bb.UserRxCrypts.Val, + "stat_user-rx_frags": bb.UserRxFrags.Val, + "stat_user-tx_packets": bb.UserTxPackets.Val, + "stat_user-tx_bytes": bb.UserTxBytes.Val, + "stat_user-tx_errors": bb.UserTxErrors.Val, + "stat_user-tx_dropped": bb.UserTxDropped.Val, + "stat_user-tx_retries": bb.UserTxRetries.Val, + "stat_user-mac_filter_rejections": bb.UserMacFilterRejections.Val, + "stat_user-wifi_tx_attempts": bb.UserWifiTxAttempts.Val, + "stat_user-wifi_tx_dropped": bb.UserWifiTxDropped.Val, + // wifi0 radio stats (5GHz) + "stat_wifi0-rx_packets": bb.Wifi0RxPackets.Val, + "stat_wifi0-rx_bytes": bb.Wifi0RxBytes.Val, + "stat_wifi0-rx_errors": bb.Wifi0RxErrors.Val, + "stat_wifi0-rx_dropped": bb.Wifi0RxDropped.Val, + "stat_wifi0-rx_crypts": bb.Wifi0RxCrypts.Val, + "stat_wifi0-rx_frags": bb.Wifi0RxFrags.Val, + "stat_wifi0-tx_packets": bb.Wifi0TxPackets.Val, + "stat_wifi0-tx_bytes": bb.Wifi0TxBytes.Val, + "stat_wifi0-tx_errors": bb.Wifi0TxErrors.Val, + "stat_wifi0-tx_dropped": bb.Wifi0TxDropped.Val, + "stat_wifi0-tx_retries": bb.Wifi0TxRetries.Val, + "stat_wifi0-mac_filter_rejections": bb.Wifi0MacFilterRejections.Val, + "stat_wifi0-wifi_tx_attempts": bb.Wifi0WifiTxAttempts.Val, + "stat_wifi0-wifi_tx_dropped": bb.Wifi0WifiTxDropped.Val, + // terra2 radio stats (60GHz - 802.11ad) + "stat_terra2-rx_packets": bb.Terra2RxPackets.Val, + "stat_terra2-rx_bytes": bb.Terra2RxBytes.Val, + "stat_terra2-rx_errors": bb.Terra2RxErrors.Val, + "stat_terra2-rx_dropped": bb.Terra2RxDropped.Val, + "stat_terra2-rx_crypts": bb.Terra2RxCrypts.Val, + "stat_terra2-rx_frags": bb.Terra2RxFrags.Val, + "stat_terra2-tx_packets": bb.Terra2TxPackets.Val, + "stat_terra2-tx_bytes": bb.Terra2TxBytes.Val, + "stat_terra2-tx_errors": bb.Terra2TxErrors.Val, + "stat_terra2-tx_dropped": bb.Terra2TxDropped.Val, + "stat_terra2-tx_retries": bb.Terra2TxRetries.Val, + "stat_terra2-mac_filter_rejections": bb.Terra2MacFilterRejections.Val, + "stat_terra2-wifi_tx_attempts": bb.Terra2WifiTxAttempts.Val, + "stat_terra2-wifi_tx_dropped": bb.Terra2WifiTxDropped.Val, + // User wifi0 stats + "stat_user-wifi0-rx_packets": bb.UserWifi0RxPackets.Val, + "stat_user-wifi0-rx_bytes": bb.UserWifi0RxBytes.Val, + "stat_user-wifi0-rx_errors": bb.UserWifi0RxErrors.Val, + "stat_user-wifi0-rx_dropped": bb.UserWifi0RxDropped.Val, + "stat_user-wifi0-rx_crypts": bb.UserWifi0RxCrypts.Val, + "stat_user-wifi0-rx_frags": bb.UserWifi0RxFrags.Val, + "stat_user-wifi0-tx_packets": bb.UserWifi0TxPackets.Val, + "stat_user-wifi0-tx_bytes": bb.UserWifi0TxBytes.Val, + "stat_user-wifi0-tx_errors": bb.UserWifi0TxErrors.Val, + "stat_user-wifi0-tx_dropped": bb.UserWifi0TxDropped.Val, + "stat_user-wifi0-tx_retries": bb.UserWifi0TxRetries.Val, + "stat_user-wifi0-mac_filter_rejections": bb.UserWifi0MacFilterRejections.Val, + "stat_user-wifi0-wifi_tx_attempts": bb.UserWifi0WifiTxAttempts.Val, + "stat_user-wifi0-wifi_tx_dropped": bb.UserWifi0WifiTxDropped.Val, + // User terra2 stats (60GHz) + "stat_user-terra2-rx_packets": bb.UserTerra2RxPackets.Val, + "stat_user-terra2-rx_bytes": bb.UserTerra2RxBytes.Val, + "stat_user-terra2-rx_errors": bb.UserTerra2RxErrors.Val, + "stat_user-terra2-rx_dropped": bb.UserTerra2RxDropped.Val, + "stat_user-terra2-rx_crypts": bb.UserTerra2RxCrypts.Val, + "stat_user-terra2-rx_frags": bb.UserTerra2RxFrags.Val, + "stat_user-terra2-tx_packets": bb.UserTerra2TxPackets.Val, + "stat_user-terra2-tx_bytes": bb.UserTerra2TxBytes.Val, + "stat_user-terra2-tx_errors": bb.UserTerra2TxErrors.Val, + "stat_user-terra2-tx_dropped": bb.UserTerra2TxDropped.Val, + "stat_user-terra2-tx_retries": bb.UserTerra2TxRetries.Val, + "stat_user-terra2-mac_filter_rejections": bb.UserTerra2MacFilterRejections.Val, + "stat_user-terra2-wifi_tx_attempts": bb.UserTerra2WifiTxAttempts.Val, + "stat_user-terra2-wifi_tx_dropped": bb.UserTerra2WifiTxDropped.Val, + // Interface-specific stats + "stat_user-wifi0-ath0-rx_packets": bb.UserWifi0Ath0RxPackets.Val, + "stat_user-wifi0-ath0-rx_bytes": bb.UserWifi0Ath0RxBytes.Val, + "stat_user-wifi0-ath0-tx_packets": bb.UserWifi0Ath0TxPackets.Val, + "stat_user-wifi0-ath0-tx_bytes": bb.UserWifi0Ath0TxBytes.Val, + "stat_user-terra2-wlan0-rx_packets": bb.UserTerra2Wlan0RxPackets.Val, + "stat_user-terra2-wlan0-rx_bytes": bb.UserTerra2Wlan0RxBytes.Val, + "stat_user-terra2-wlan0-tx_packets": bb.UserTerra2Wlan0TxPackets.Val, + "stat_user-terra2-wlan0-tx_bytes": bb.UserTerra2Wlan0TxBytes.Val, + "stat_user-terra2-wlan0-tx_dropped": bb.UserTerra2Wlan0TxDropped.Val, + "stat_user-terra2-wlan0-rx_errors": bb.UserTerra2Wlan0RxErrors.Val, + "stat_user-terra2-wlan0-tx_errors": bb.UserTerra2Wlan0TxErrors.Val, } } diff --git a/pkg/promunifi/ubb.go b/pkg/promunifi/ubb.go index 037d2a3d..79e0d6e2 100644 --- a/pkg/promunifi/ubb.go +++ b/pkg/promunifi/ubb.go @@ -4,33 +4,164 @@ import ( "github.com/unpoller/unifi/v5" ) -// exportUBB is a collection of stats from UBB. +// exportUBB is a collection of stats from UBB (UniFi Building Bridge). +// UBB devices are point-to-point wireless bridges with dual radios: +// - wifi0: 5GHz radio (802.11ac) +// - terra2/wlan0/ad: 60GHz radio (802.11ad - Terragraph/WiGig) func (u *promUnifi) exportUBB(r report, d *unifi.UBB) { if !d.Adopted.Val || d.Locating.Val { return } - //var sw *unifi.Bb - //if d.Stat != nil { - // sw = d.Stat.Bb - //} - // unsure of what to do with this yet. - labels := []string{d.Type, d.SiteName, d.Name, d.SourceName} infoLabels := []string{d.Version, d.Model, d.Serial, d.Mac, d.IP, d.ID} - // Shared data (all devices do this). + + // Export UBB-specific stats if available + u.exportUBBstats(r, labels, d.Stat) + + // Export VAP table (Virtual Access Point table - wireless interface stats) + u.exportVAPtable(r, labels, d.VapTable) + + // Export Radio tables (includes 5GHz wifi0 and 60GHz terra2/ad radios) + u.exportRADtable(r, labels, d.RadioTable, d.RadioTableStats) + + // Shared device stats u.exportBYTstats(r, labels, d.TxBytes, d.RxBytes) if d.SysStats != nil && d.SystemStats != nil { u.exportSYSstats(r, labels, *d.SysStats, *d.SystemStats) } - // Dream Machine System Data. + // Device info, uptime, and temperature r.send([]*metric{ {u.Device.Info, gauge, 1.0, append(labels, infoLabels...)}, {u.Device.Uptime, gauge, d.Uptime, labels}, + {u.Device.Temperature, gauge, d.GeneralTemperature.Val, append(labels, d.Name, "general")}, }) - // temperature - r.send([]*metric{{u.Device.Temperature, gauge, d.GeneralTemperature.Val, append(labels, d.Name, "general")}}) + // UBB-specific metrics + if d.P2PStats != nil { + u.exportP2Pstats(r, labels, d.P2PStats) + } + + // Link quality metrics for point-to-point links + r.send([]*metric{ + {u.Device.Counter, gauge, d.LinkQuality.Val, append(labels, "link_quality")}, + {u.Device.Counter, gauge, d.LinkQualityCurrent.Val, append(labels, "link_quality_current")}, + {u.Device.Counter, gauge, d.LinkCapacity.Val, append(labels, "link_capacity")}, + }) +} + +// exportUBBstats exports UBB-specific stats from the Bb structure. +// This includes separate metrics for wifi0 (5GHz) and terra2 (60GHz) radios. +func (u *promUnifi) exportUBBstats(r report, labels []string, stat *unifi.UBBStat) { + if stat == nil || stat.Bb == nil { + return + } + + bb := stat.Bb + + // Export aggregated stats (total across both radios) + labelTotal := append([]string{"total"}, labels[1:]...) + r.send([]*metric{ + {u.UAP.ApRxPackets, counter, bb.RxPackets, labelTotal}, + {u.UAP.ApRxBytes, counter, bb.RxBytes, labelTotal}, + {u.UAP.ApRxErrors, counter, bb.RxErrors, labelTotal}, + {u.UAP.ApRxDropped, counter, bb.RxDropped, labelTotal}, + {u.UAP.ApRxCrypts, counter, bb.RxCrypts, labelTotal}, + {u.UAP.ApRxFrags, counter, bb.RxFrags, labelTotal}, + {u.UAP.ApTxPackets, counter, bb.TxPackets, labelTotal}, + {u.UAP.ApTxBytes, counter, bb.TxBytes, labelTotal}, + {u.UAP.ApTxErrors, counter, bb.TxErrors, labelTotal}, + {u.UAP.ApTxDropped, counter, bb.TxDropped, labelTotal}, + {u.UAP.ApTxRetries, counter, bb.TxRetries, labelTotal}, + {u.UAP.WifiTxAttempts, counter, bb.WifiTxAttempts, labelTotal}, + {u.UAP.MacFilterRejections, counter, bb.MacFilterRejections, labelTotal}, + {u.UAP.ApWifiTxDropped, counter, bb.WifiTxDropped, labelTotal}, + }) + + // Export wifi0 radio stats (5GHz) + labelWifi0 := append([]string{"wifi0"}, labels[1:]...) + r.send([]*metric{ + {u.UAP.ApRxPackets, counter, bb.Wifi0RxPackets, labelWifi0}, + {u.UAP.ApRxBytes, counter, bb.Wifi0RxBytes, labelWifi0}, + {u.UAP.ApRxErrors, counter, bb.Wifi0RxErrors, labelWifi0}, + {u.UAP.ApRxDropped, counter, bb.Wifi0RxDropped, labelWifi0}, + {u.UAP.ApRxCrypts, counter, bb.Wifi0RxCrypts, labelWifi0}, + {u.UAP.ApRxFrags, counter, bb.Wifi0RxFrags, labelWifi0}, + {u.UAP.ApTxPackets, counter, bb.Wifi0TxPackets, labelWifi0}, + {u.UAP.ApTxBytes, counter, bb.Wifi0TxBytes, labelWifi0}, + {u.UAP.ApTxErrors, counter, bb.Wifi0TxErrors, labelWifi0}, + {u.UAP.ApTxDropped, counter, bb.Wifi0TxDropped, labelWifi0}, + {u.UAP.ApTxRetries, counter, bb.Wifi0TxRetries, labelWifi0}, + {u.UAP.WifiTxAttempts, counter, bb.Wifi0WifiTxAttempts, labelWifi0}, + {u.UAP.MacFilterRejections, counter, bb.Wifi0MacFilterRejections, labelWifi0}, + {u.UAP.ApWifiTxDropped, counter, bb.Wifi0WifiTxDropped, labelWifi0}, + }) + + // Export terra2 radio stats (60GHz - 802.11ad) + labelTerra2 := append([]string{"terra2"}, labels[1:]...) + r.send([]*metric{ + {u.UAP.ApRxPackets, counter, bb.Terra2RxPackets, labelTerra2}, + {u.UAP.ApRxBytes, counter, bb.Terra2RxBytes, labelTerra2}, + {u.UAP.ApRxErrors, counter, bb.Terra2RxErrors, labelTerra2}, + {u.UAP.ApRxDropped, counter, bb.Terra2RxDropped, labelTerra2}, + {u.UAP.ApRxCrypts, counter, bb.Terra2RxCrypts, labelTerra2}, + {u.UAP.ApRxFrags, counter, bb.Terra2RxFrags, labelTerra2}, + {u.UAP.ApTxPackets, counter, bb.Terra2TxPackets, labelTerra2}, + {u.UAP.ApTxBytes, counter, bb.Terra2TxBytes, labelTerra2}, + {u.UAP.ApTxErrors, counter, bb.Terra2TxErrors, labelTerra2}, + {u.UAP.ApTxDropped, counter, bb.Terra2TxDropped, labelTerra2}, + {u.UAP.ApTxRetries, counter, bb.Terra2TxRetries, labelTerra2}, + {u.UAP.WifiTxAttempts, counter, bb.Terra2WifiTxAttempts, labelTerra2}, + {u.UAP.MacFilterRejections, counter, bb.Terra2MacFilterRejections, labelTerra2}, + {u.UAP.ApWifiTxDropped, counter, bb.Terra2WifiTxDropped, labelTerra2}, + }) + + // Export user stats for wifi0 + labelUserWifi0 := append([]string{"user-wifi0"}, labels[1:]...) + r.send([]*metric{ + {u.UAP.ApRxPackets, counter, bb.UserWifi0RxPackets, labelUserWifi0}, + {u.UAP.ApRxBytes, counter, bb.UserWifi0RxBytes, labelUserWifi0}, + {u.UAP.ApRxErrors, counter, bb.UserWifi0RxErrors, labelUserWifi0}, + {u.UAP.ApRxDropped, counter, bb.UserWifi0RxDropped, labelUserWifi0}, + {u.UAP.ApRxCrypts, counter, bb.UserWifi0RxCrypts, labelUserWifi0}, + {u.UAP.ApRxFrags, counter, bb.UserWifi0RxFrags, labelUserWifi0}, + {u.UAP.ApTxPackets, counter, bb.UserWifi0TxPackets, labelUserWifi0}, + {u.UAP.ApTxBytes, counter, bb.UserWifi0TxBytes, labelUserWifi0}, + {u.UAP.ApTxErrors, counter, bb.UserWifi0TxErrors, labelUserWifi0}, + {u.UAP.ApTxDropped, counter, bb.UserWifi0TxDropped, labelUserWifi0}, + {u.UAP.ApTxRetries, counter, bb.UserWifi0TxRetries, labelUserWifi0}, + {u.UAP.WifiTxAttempts, counter, bb.UserWifi0WifiTxAttempts, labelUserWifi0}, + {u.UAP.MacFilterRejections, counter, bb.UserWifi0MacFilterRejections, labelUserWifi0}, + {u.UAP.ApWifiTxDropped, counter, bb.UserWifi0WifiTxDropped, labelUserWifi0}, + }) + + // Export user stats for terra2 (60GHz) + labelUserTerra2 := append([]string{"user-terra2"}, labels[1:]...) + r.send([]*metric{ + {u.UAP.ApRxPackets, counter, bb.UserTerra2RxPackets, labelUserTerra2}, + {u.UAP.ApRxBytes, counter, bb.UserTerra2RxBytes, labelUserTerra2}, + {u.UAP.ApRxErrors, counter, bb.UserTerra2RxErrors, labelUserTerra2}, + {u.UAP.ApRxDropped, counter, bb.UserTerra2RxDropped, labelUserTerra2}, + {u.UAP.ApRxCrypts, counter, bb.UserTerra2RxCrypts, labelUserTerra2}, + {u.UAP.ApRxFrags, counter, bb.UserTerra2RxFrags, labelUserTerra2}, + {u.UAP.ApTxPackets, counter, bb.UserTerra2TxPackets, labelUserTerra2}, + {u.UAP.ApTxBytes, counter, bb.UserTerra2TxBytes, labelUserTerra2}, + {u.UAP.ApTxErrors, counter, bb.UserTerra2TxErrors, labelUserTerra2}, + {u.UAP.ApTxDropped, counter, bb.UserTerra2TxDropped, labelUserTerra2}, + {u.UAP.ApTxRetries, counter, bb.UserTerra2TxRetries, labelUserTerra2}, + {u.UAP.WifiTxAttempts, counter, bb.UserTerra2WifiTxAttempts, labelUserTerra2}, + {u.UAP.MacFilterRejections, counter, bb.UserTerra2MacFilterRejections, labelUserTerra2}, + {u.UAP.ApWifiTxDropped, counter, bb.UserTerra2WifiTxDropped, labelUserTerra2}, + }) +} + +// exportP2Pstats exports point-to-point link statistics for UBB devices. +func (u *promUnifi) exportP2Pstats(r report, labels []string, p2p *unifi.P2PStats) { + r.send([]*metric{ + {u.Device.Counter, gauge, p2p.RXRate.Val, append(labels, "p2p_rx_rate")}, + {u.Device.Counter, gauge, p2p.TXRate.Val, append(labels, "p2p_tx_rate")}, + {u.Device.Counter, gauge, p2p.Throughput.Val, append(labels, "p2p_throughput")}, + }) }