add metrics for the udp sockets using SO_MEMINFO (#390)

Retrieve the current socket stats using SO_MEMINFO and report them as
metrics gauges. If SO_MEMINFO isn't supported, we don't report these metrics.
This commit is contained in:
Wade Simmons 2021-03-01 19:51:33 -05:00 committed by GitHub
parent ecfb40f29c
commit d232ccbfab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 0 deletions

View File

@ -268,8 +268,13 @@ func (f *Interface) reloadFirewall(c *Config) {
func (f *Interface) emitStats(i time.Duration) { func (f *Interface) emitStats(i time.Duration) {
ticker := time.NewTicker(i) ticker := time.NewTicker(i)
udpStats := NewUDPStatsEmitter(f.writers)
for range ticker.C { for range ticker.C {
f.firewall.EmitStats() f.firewall.EmitStats()
f.handshakeManager.EmitStats() f.handshakeManager.EmitStats()
udpStats()
} }
} }

View File

@ -96,6 +96,11 @@ func (u *udpConn) reloadConfig(c *Config) {
// TODO // TODO
} }
func NewUDPStatsEmitter(udpConns []*udpConn) func() {
// No UDP stats for non-linux
return func() {}
}
type rawMessage struct { type rawMessage struct {
Len uint32 Len uint32
} }

View File

@ -12,6 +12,7 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/rcrowley/go-metrics"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -55,6 +56,23 @@ type rawSockaddrAny struct {
var x int var x int
// From linux/sock_diag.h
const (
_SK_MEMINFO_RMEM_ALLOC = iota
_SK_MEMINFO_RCVBUF
_SK_MEMINFO_WMEM_ALLOC
_SK_MEMINFO_SNDBUF
_SK_MEMINFO_FWD_ALLOC
_SK_MEMINFO_WMEM_QUEUED
_SK_MEMINFO_OPTMEM
_SK_MEMINFO_BACKLOG
_SK_MEMINFO_DROPS
_SK_MEMINFO_VARS
)
type _SK_MEMINFO [_SK_MEMINFO_VARS]uint32
func NewListener(ip string, port int, multi bool) (*udpConn, error) { func NewListener(ip string, port int, multi bool) (*udpConn, error) {
syscall.ForkLock.RLock() syscall.ForkLock.RLock()
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP) fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
@ -281,6 +299,47 @@ func (u *udpConn) reloadConfig(c *Config) {
} }
} }
func (u *udpConn) getMemInfo(meminfo *_SK_MEMINFO) error {
var vallen uint32 = 4 * _SK_MEMINFO_VARS
_, _, err := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(u.sysFd), uintptr(unix.SOL_SOCKET), uintptr(unix.SO_MEMINFO), uintptr(unsafe.Pointer(meminfo)), uintptr(unsafe.Pointer(&vallen)), 0)
if err != 0 {
return err
}
return nil
}
func NewUDPStatsEmitter(udpConns []*udpConn) func() {
// Check if our kernel supports SO_MEMINFO before registering the gauges
var udpGauges [][_SK_MEMINFO_VARS]metrics.Gauge
var meminfo _SK_MEMINFO
if err := udpConns[0].getMemInfo(&meminfo); err == nil {
udpGauges = make([][_SK_MEMINFO_VARS]metrics.Gauge, len(udpConns))
for i := range udpConns {
udpGauges[i] = [_SK_MEMINFO_VARS]metrics.Gauge{
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rmem_alloc", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.rcvbuf", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_alloc", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.sndbuf", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.fwd_alloc", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.wmem_queued", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.optmem", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.backlog", i), nil),
metrics.GetOrRegisterGauge(fmt.Sprintf("udp.%d.drops", i), nil),
}
}
}
return func() {
for i, gauges := range udpGauges {
if err := udpConns[i].getMemInfo(&meminfo); err == nil {
for j := 0; j < _SK_MEMINFO_VARS; j++ {
gauges[j].Update(int64(meminfo[j]))
}
}
}
}
}
func (ua *udpAddr) Equals(t *udpAddr) bool { func (ua *udpAddr) Equals(t *udpAddr) bool {
if t == nil || ua == nil { if t == nil || ua == nil {
return t == nil && ua == nil return t == nil && ua == nil