From 2db27ff2fa2a796537754bab3d8fae95d53f0912 Mon Sep 17 00:00:00 2001 From: Danilo Egea Gondolfo Date: Sun, 27 Apr 2025 14:30:06 +0100 Subject: [PATCH] netstat_freebsd: add support for some UDP metrics Metrics added: - udp_transmit_packets_total - udp_receive_packets_total Signed-off-by: Danilo Egea Gondolfo --- collector/netstat_freebsd.go | 51 +++++++++++++++++++++++++++++++ collector/netstat_freebsd_test.go | 20 ++++++++++++ 2 files changed, 71 insertions(+) diff --git a/collector/netstat_freebsd.go b/collector/netstat_freebsd.go index c3671785..903e97d2 100644 --- a/collector/netstat_freebsd.go +++ b/collector/netstat_freebsd.go @@ -33,6 +33,7 @@ import ( #include #include #include +#include #include #include */ @@ -42,6 +43,8 @@ var ( sysctlRaw = unix.SysctlRaw tcpSendTotal = "bsdNetstatTcpSendPacketsTotal" tcpRecvTotal = "bsdNetstatTcpRecvPacketsTotal" + udpSendTotal = "bsdNetstatUdpSendPacketsTotal" + udpRecvTotal = "bsdNetstatUdpRecvPacketsTotal" ipv4SendTotal = "bsdNetstatIPv4SendPacketsTotal" ipv4RawSendTotal = "bsdNetstatIPv4RawSendPacketsTotal" ipv4RecvTotal = "bsdNetstatIPv4RecvPacketsTotal" @@ -65,6 +68,14 @@ var ( prometheus.BuildFQName(namespace, "netstat", "tcp_receive_packets_total"), "TCP packets received", nil, nil), + // UDP stats + udpSendTotal: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "netstat", "udp_transmit_packets_total"), + "UDP packets sent", nil, nil), + udpRecvTotal: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "netstat", "udp_receive_packets_total"), + "UDP packets received", nil, nil), + // IPv4 stats ipv4SendTotal: prometheus.NewDesc( prometheus.BuildFQName(namespace, "netstat", "ip4_transmit_packets_total"), @@ -140,6 +151,29 @@ func (netstatMetric *NetstatTCPData) GetData() (NetstatMetrics, error) { }, nil } +type NetstatUDPData NetstatData + +func NewUDPStat() *NetstatUDPData { + return &NetstatUDPData{ + structSize: int(unsafe.Sizeof(C.struct_udpstat{})), + sysctl: "net.inet.udp.stats", + } +} + +func (netstatMetric *NetstatUDPData) GetData() (NetstatMetrics, error) { + data, err := getData(netstatMetric.sysctl, netstatMetric.structSize) + if err != nil { + return nil, err + } + + udpStats := *(*C.struct_udpstat)(unsafe.Pointer(&data[0])) + + return NetstatMetrics{ + udpSendTotal: float64(udpStats.udps_opackets), + udpRecvTotal: float64(udpStats.udps_ipackets), + }, nil +} + type NetstatIPv4Data NetstatData func NewIPv4Stat() *NetstatIPv4Data { @@ -234,6 +268,11 @@ func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error { return err } + udpStats, err := NewUDPStat().GetData() + if err != nil { + return err + } + ipv4Stats, err := NewIPv4Stat().GetData() if err != nil { return err @@ -250,6 +289,10 @@ func (c *netStatCollector) Update(ch chan<- prometheus.Metric) error { allStats[k] = v } + for k, v := range udpStats { + allStats[k] = v + } + for k, v := range ipv4Stats { allStats[k] = v } @@ -280,6 +323,14 @@ func getFreeBSDDataMock(sysctl string) []byte { size := int(unsafe.Sizeof(C.struct_tcpstat{})) return unsafe.Slice((*byte)(unsafe.Pointer(&tcpStats)), size) + } else if sysctl == "net.inet.udp.stats" { + udpStats := C.struct_udpstat{ + udps_opackets: 1234, + udps_ipackets: 4321, + } + size := int(unsafe.Sizeof(C.struct_udpstat{})) + + return unsafe.Slice((*byte)(unsafe.Pointer(&udpStats)), size) } else if sysctl == "net.inet.ip.stats" { ipStats := C.struct_ipstat{ ips_localout: 1234, diff --git a/collector/netstat_freebsd_test.go b/collector/netstat_freebsd_test.go index fb70b053..3d00f3de 100644 --- a/collector/netstat_freebsd_test.go +++ b/collector/netstat_freebsd_test.go @@ -62,6 +62,26 @@ func TestGetTCPMetrics(t *testing.T) { } } +func TestGetUDPMetrics(t *testing.T) { + testSetup() + + udpData, err := NewUDPStat().GetData() + if err != nil { + t.Fatal("unexpected error:", err) + } + + sndTotal := udpData[udpSendTotal] + rcvTotal := udpData[udpRecvTotal] + + if got, want := sndTotal, float64(1234); got != want { + t.Errorf("unexpected sndTotal value: want %f, got %f", want, got) + } + + if got, want := rcvTotal, float64(4321); got != want { + t.Errorf("unexpected rcvTotal value: want %f, got %f", want, got) + } +} + func TestGetIPv4Metrics(t *testing.T) { testSetup()