From 4c2f67a1d09bb6d66f39cbd8a9269157aaed0955 Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Wed, 8 Mar 2023 13:52:03 -0800 Subject: [PATCH] net/sockstat: fix per-interface statistics not always being available withSockStats may be called before setLinkMonitor, in which case we don't have a populated knownInterfaces map. Since we pre-populate the per-interface counters at creation time, we would end up with an empty map. To mitigate this, we do an on-demand request for the list of interfaces. This would most often happen with the logtail instrumentation, since we initialize it very early on. Updates tailscale/corp#9230 Signed-off-by: Mihai Parparita --- net/sockstats/sockstats_tsgo.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/net/sockstats/sockstats_tsgo.go b/net/sockstats/sockstats_tsgo.go index 478b0fcd8..479f2a9b7 100644 --- a/net/sockstats/sockstats_tsgo.go +++ b/net/sockstats/sockstats_tsgo.go @@ -53,9 +53,22 @@ func withSockStats(ctx context.Context, label Label) context.Context { rxBytesByInterface: make(map[int]*atomic.Uint64), txBytesByInterface: make(map[int]*atomic.Uint64), } - for iface := range sockStats.knownInterfaces { - counters.rxBytesByInterface[iface] = &atomic.Uint64{} - counters.txBytesByInterface[iface] = &atomic.Uint64{} + + // We might be called before setLinkMonitor has been called (and we've + // had a chance to populate knownInterfaces). In that case, we'll have + // to get the list of interfaces ourselves. + if len(sockStats.knownInterfaces) == 0 { + if ifaces, err := interfaces.GetList(); err == nil { + for _, iface := range ifaces { + counters.rxBytesByInterface[iface.Index] = &atomic.Uint64{} + counters.txBytesByInterface[iface.Index] = &atomic.Uint64{} + } + } + } else { + for iface := range sockStats.knownInterfaces { + counters.rxBytesByInterface[iface] = &atomic.Uint64{} + counters.txBytesByInterface[iface] = &atomic.Uint64{} + } } sockStats.countersByLabel[label] = counters }