tailscale/net/udprelay/metrics_test.go
Alex Valiushko 8476aa8dd5 net/udprelay: expose peer relay metrics
Adding both user and client metrics for peer relay forwarded bytes and
packets, and the total endpoints gauge.

User metrics:
tailscaled_relay_forwarded_packets_total{trainsport_in, transport_out}
tailscaled_relay_forwarded_bytes_total{trainsport_in, transport_out}
tailscaled_relay_endpoints_total{}

Where the transport labels can be of "udp4" or "udp6".

Client metrics:
udprelay_forwarded_(packets|bytes)_udp(4|6)_udp(4|6)
udprelay_endpoints

RELNOTE: Expose tailscaled metrics for peer relay.

Updates tailscale/corp#30820

Change-Id: I1a905d15bdc5ee84e28017e0b93210e2d9660259
Signed-off-by: Alex Valiushko <alexvaliushko@tailscale.com>
2025-12-17 09:35:30 -08:00

141 lines
4.6 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package udprelay
import (
"net/netip"
"slices"
"testing"
qt "github.com/frankban/quicktest"
"tailscale.com/util/usermetric"
)
func resetClientMetrics() {
// clientmetrics are global and must be reset between test cases
// for the assertMetricsMatch to work.
metricForwarded44Packets.Set(0)
metricForwarded46Packets.Set(0)
metricForwarded64Packets.Set(0)
metricForwarded66Packets.Set(0)
metricForwarded44Bytes.Set(0)
metricForwarded46Bytes.Set(0)
metricForwarded64Bytes.Set(0)
metricForwarded66Bytes.Set(0)
metricEndpoints.Set(0)
}
func assertMetricsMatch(t *testing.T, s *Server) {
t.Helper()
s.mu.Lock()
defer s.mu.Unlock()
c := qt.New(t)
var (
ps44, ps46, ps64, ps66 uint64
bs44, bs46, bs64, bs66 uint64
es = len(s.serverEndpointByDisco)
)
for _, e := range s.serverEndpointByDisco {
cs := e.extractClientInfo()
a, b := cs[0], cs[1]
a4, b4 := a.Endpoint.Addr().Is4(), b.Endpoint.Addr().Is4()
if a4 && b4 {
ps44 += b.PacketsTx
ps44 += a.PacketsTx
bs44 += b.BytesTx
bs44 += a.BytesTx
} else if a4 && !b4 {
ps46 += b.PacketsTx
ps64 += a.PacketsTx
bs46 += b.BytesTx
bs64 += a.BytesTx
} else if !a4 && b4 {
ps64 += b.PacketsTx
ps46 += a.PacketsTx
bs64 += b.BytesTx
bs46 += a.BytesTx
} else if !a4 && !b4 {
ps66 += b.PacketsTx
ps66 += a.PacketsTx
bs66 += b.BytesTx
bs66 += a.BytesTx
}
}
c.Assert(s.metrics.forwarded44Packets.Value(), qt.Equals, int64(ps44))
c.Assert(s.metrics.forwarded46Packets.Value(), qt.Equals, int64(ps46))
c.Assert(s.metrics.forwarded64Packets.Value(), qt.Equals, int64(ps64))
c.Assert(s.metrics.forwarded66Packets.Value(), qt.Equals, int64(ps66))
c.Assert(s.metrics.forwarded44Bytes.Value(), qt.Equals, int64(bs44))
c.Assert(s.metrics.forwarded46Bytes.Value(), qt.Equals, int64(bs46))
c.Assert(s.metrics.forwarded64Bytes.Value(), qt.Equals, int64(bs64))
c.Assert(s.metrics.forwarded66Bytes.Value(), qt.Equals, int64(bs66))
c.Assert(s.metrics.endpoints.Value(), qt.Equals, int64(es))
c.Assert(metricForwarded44Packets.Value(), qt.Equals, int64(ps44))
c.Assert(metricForwarded46Packets.Value(), qt.Equals, int64(ps46))
c.Assert(metricForwarded64Packets.Value(), qt.Equals, int64(ps64))
c.Assert(metricForwarded66Packets.Value(), qt.Equals, int64(ps66))
c.Assert(metricForwarded44Bytes.Value(), qt.Equals, int64(bs44))
c.Assert(metricForwarded46Bytes.Value(), qt.Equals, int64(bs46))
c.Assert(metricForwarded64Bytes.Value(), qt.Equals, int64(bs64))
c.Assert(metricForwarded66Bytes.Value(), qt.Equals, int64(bs66))
c.Assert(metricEndpoints.Value(), qt.Equals, int64(es))
}
func TestMetrics(t *testing.T) {
c := qt.New(t)
resetClientMetrics()
r := &usermetric.Registry{}
m := registerMetrics(r)
// Expect certain prom names registered.
have := r.MetricNames()
want := []string{
"tailscaled_relay_forwarded_packets_total",
"tailscaled_relay_forwarded_bytes_total",
"tailscaled_relay_endpoints_total",
}
slices.Sort(have)
slices.Sort(want)
c.Assert(have, qt.CmpEquals(), want)
// Validate addEndpoints.
m.addEndpoints(1)
c.Assert(m.endpoints.Value(), qt.Equals, int64(1))
c.Assert(metricEndpoints.Value(), qt.Equals, int64(1))
m.addEndpoints(-1)
c.Assert(m.endpoints.Value(), qt.Equals, int64(0))
c.Assert(metricEndpoints.Value(), qt.Equals, int64(0))
// Validate countForwarded.
var (
ip4 = netip.AddrFrom4([4]byte{1, 1, 1, 1})
ip6 = netip.AddrFrom16([16]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})
)
m.countForwarded(ip4, ip4, []byte{1})
c.Assert(m.forwarded44Bytes.Value(), qt.Equals, int64(1))
c.Assert(m.forwarded44Packets.Value(), qt.Equals, int64(1))
c.Assert(metricForwarded44Bytes.Value(), qt.Equals, int64(1))
c.Assert(metricForwarded44Packets.Value(), qt.Equals, int64(1))
m.countForwarded(ip4, ip6, []byte{1, 2})
c.Assert(m.forwarded46Bytes.Value(), qt.Equals, int64(2))
c.Assert(m.forwarded46Packets.Value(), qt.Equals, int64(1))
c.Assert(metricForwarded46Bytes.Value(), qt.Equals, int64(2))
c.Assert(metricForwarded46Packets.Value(), qt.Equals, int64(1))
m.countForwarded(ip6, ip4, []byte{1, 2, 3})
c.Assert(m.forwarded64Bytes.Value(), qt.Equals, int64(3))
c.Assert(m.forwarded64Packets.Value(), qt.Equals, int64(1))
c.Assert(metricForwarded64Bytes.Value(), qt.Equals, int64(3))
c.Assert(metricForwarded64Packets.Value(), qt.Equals, int64(1))
m.countForwarded(ip6, ip6, []byte{1, 2, 3, 4})
c.Assert(m.forwarded66Bytes.Value(), qt.Equals, int64(4))
c.Assert(m.forwarded66Packets.Value(), qt.Equals, int64(1))
c.Assert(metricForwarded66Bytes.Value(), qt.Equals, int64(4))
c.Assert(metricForwarded66Packets.Value(), qt.Equals, int64(1))
}