mirror of
https://github.com/tailscale/tailscale.git
synced 2026-06-25 00:11:39 -04:00
wgengine/netlog: stop using netmap.NetworkMap type, use LocalBackend
The Logger previously took a *netmap.NetworkMap at Startup and on every ReconfigNetworkMap call, denormalizing it into per-IP and self lookup maps. That denormalization is O(n) over all peers and ran on every netmap update, contributing to the broader quadratic behavior we want to eliminate when a single peer is added or removed. Instead, this makes netlog ask LocalBackend (well, nodeBackend) for the info it needs, letting us remove the netmap.NetworkMap type entirely from the netlog package. This is a dependency to removing the netmap.NetworkMap type from upstream callers, like wgengine.Engine in general. Updates #12542 Change-Id: Ib5f2de96e788a667332c0a6f7ac833b3d0053b5c Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
994b2c8459
commit
8f210454dd
@@ -919,7 +919,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack from tailscale.com/tsnet
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -194,7 +194,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -215,7 +215,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
||||
tailscale.com/wgengine/wgcfg from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -503,7 +503,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack from tailscale.com/cmd/tailscaled
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/cmd/tailscaled+
|
||||
|
||||
@@ -317,7 +317,7 @@ tailscale.com/cmd/tsidp dependencies: (generated by github.com/tailscale/depawar
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack from tailscale.com/tsnet
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/magicsock"
|
||||
"tailscale.com/wgengine/netlog"
|
||||
"tailscale.com/wgengine/router"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
"tailscale.com/wgengine/wgcfg/nmcfg"
|
||||
@@ -645,6 +646,7 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
|
||||
|
||||
e.SetPeerByIPPacketFunc(b.lookupPeerByIP)
|
||||
e.SetPeerSessionStateFunc(b.onPeerWireGuardState)
|
||||
e.SetNetLogNodeSource(netLogNodeSource{b})
|
||||
|
||||
if sys.InitialConfig != nil {
|
||||
if err := b.initPrefsFromConfig(sys.InitialConfig); err != nil {
|
||||
@@ -8046,6 +8048,40 @@ func (n noiseRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
|
||||
return n.lb.DoNoiseRequest(req)
|
||||
}
|
||||
|
||||
// netLogNodeSource adapts LocalBackend's nodeBackend to [netlog.NodeSource].
|
||||
// Each method consults [LocalBackend.currentNode] so that profile rotations
|
||||
// are picked up automatically without re-installing the source.
|
||||
type netLogNodeSource struct {
|
||||
b *LocalBackend
|
||||
}
|
||||
|
||||
func (s netLogNodeSource) SelfNode() (tailcfg.NodeView, tailcfg.UserProfileView) {
|
||||
nb := s.b.currentNode()
|
||||
self := nb.Self()
|
||||
if !self.Valid() {
|
||||
return tailcfg.NodeView{}, tailcfg.UserProfileView{}
|
||||
}
|
||||
up, _ := nb.UserByID(self.User())
|
||||
return self, up
|
||||
}
|
||||
|
||||
func (s netLogNodeSource) NodeByAddr(addr netip.Addr) (_ tailcfg.NodeView, _ tailcfg.UserProfileView, ok bool) {
|
||||
nb := s.b.currentNode()
|
||||
nid, ok := nb.NodeByAddr(addr)
|
||||
if !ok {
|
||||
return tailcfg.NodeView{}, tailcfg.UserProfileView{}, false
|
||||
}
|
||||
nv, ok := nb.NodeByID(nid)
|
||||
if !ok {
|
||||
return tailcfg.NodeView{}, tailcfg.UserProfileView{}, false
|
||||
}
|
||||
up, _ := nb.UserByID(nv.User())
|
||||
return nv, up, true
|
||||
}
|
||||
|
||||
// Compile-time assertion that netLogNodeSource implements [netlog.NodeSource].
|
||||
var _ netlog.NodeSource = netLogNodeSource{}
|
||||
|
||||
// ActiveSSHConns returns the number of active SSH connections,
|
||||
// or 0 if SSH is not linked into the binary or available on the platform.
|
||||
func (b *LocalBackend) ActiveSSHConns() int {
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
"tailscale.com/wgengine"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/magicsock"
|
||||
"tailscale.com/wgengine/netlog"
|
||||
"tailscale.com/wgengine/router"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
"tailscale.com/wgengine/wgint"
|
||||
@@ -1984,6 +1985,7 @@ func (e *mockEngine) InstallCaptureHook(packet.CaptureCallback) {}
|
||||
func (e *mockEngine) SetPeerByIPPacketFunc(func(netip.Addr) (_ key.NodePublic, ok bool)) {}
|
||||
func (e *mockEngine) SetPeerSessionStateFunc(func(key.NodePublic, wgengine.PeerWireGuardState)) {
|
||||
}
|
||||
func (e *mockEngine) SetNetLogNodeSource(netlog.NodeSource) {}
|
||||
|
||||
func (e *mockEngine) Close() {
|
||||
e.mu.Lock()
|
||||
|
||||
@@ -312,7 +312,7 @@ tailscale.com/tsnet dependencies: (generated by github.com/tailscale/depaware)
|
||||
tailscale.com/wgengine/filter from tailscale.com/control/controlclient+
|
||||
tailscale.com/wgengine/filter/filtertype from tailscale.com/types/netmap+
|
||||
💣 tailscale.com/wgengine/magicsock from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine
|
||||
tailscale.com/wgengine/netlog from tailscale.com/wgengine+
|
||||
tailscale.com/wgengine/netstack from tailscale.com/tsnet
|
||||
tailscale.com/wgengine/netstack/gro from tailscale.com/net/tstun+
|
||||
tailscale.com/wgengine/router from tailscale.com/ipn/ipnlocal+
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
"tailscale.com/net/sockstats"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/logid"
|
||||
"tailscale.com/types/netlogfunc"
|
||||
"tailscale.com/types/netlogtype"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/util/eventbus"
|
||||
"tailscale.com/util/set"
|
||||
"tailscale.com/wgengine/router"
|
||||
@@ -51,6 +51,19 @@ type noopDevice struct{
|
||||
|
||||
func (noopDevice) SetConnectionCounter(netlogfunc.ConnectionCounter) {}
|
||||
|
||||
// NodeSource provides node lookups for the network logger.
|
||||
// Methods may be called concurrently.
|
||||
type NodeSource interface {
|
||||
// SelfNode returns the local node and its owning user profile.
|
||||
// Both views may be invalid if no self node is known yet.
|
||||
SelfNode() (node tailcfg.NodeView, user tailcfg.UserProfileView)
|
||||
|
||||
// NodeByAddr returns the node assigned the given address along with
|
||||
// its owning user profile.
|
||||
// ok is false if no node is known to own addr.
|
||||
NodeByAddr(addr netip.Addr) (node tailcfg.NodeView, user tailcfg.UserProfileView, ok bool)
|
||||
}
|
||||
|
||||
// Logger logs statistics about every connection.
|
||||
// At present, it only logs connections within a tailscale network.
|
||||
// By default, exit node traffic is not logged for privacy reasons
|
||||
@@ -69,10 +82,8 @@ type Logger struct {
|
||||
recordsChan chan record // set to nil when shutdown
|
||||
flushTimer *time.Timer // fires when record should flush to recordsChan
|
||||
|
||||
// Information about Tailscale nodes.
|
||||
// These are read-only once updated by ReconfigNetworkMap.
|
||||
selfNode nodeUser
|
||||
allNodes map[netip.Addr]nodeUser // includes selfNode; nodeUser values are always valid
|
||||
// source provides node lookups. Set by Startup, cleared by shutdownLocked.
|
||||
source NodeSource
|
||||
|
||||
// Information about routes.
|
||||
// These are read-only once updated by ReconfigRoutes.
|
||||
@@ -115,14 +126,20 @@ func (nl *Logger) Running() bool {
|
||||
// The sock is used to populated the PhysicalTraffic field in [netlogtype.Message].
|
||||
//
|
||||
// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
|
||||
func (nl *Logger) Startup(logf logger.Logf, nm *netmap.NetworkMap, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor, health *health.Tracker, bus *eventbus.Bus, logExitFlowEnabledEnabled bool) error {
|
||||
//
|
||||
// source provides on-demand node lookups for connections seen by the logger.
|
||||
// It must be non-nil.
|
||||
func (nl *Logger) Startup(logf logger.Logf, source NodeSource, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor, health *health.Tracker, bus *eventbus.Bus, logExitFlowEnabledEnabled bool) error {
|
||||
nl.mu.Lock()
|
||||
defer nl.mu.Unlock()
|
||||
|
||||
if nl.shutdownLocked != nil {
|
||||
return fmt.Errorf("network logger already running")
|
||||
}
|
||||
nl.selfNode, nl.allNodes = makeNodeMaps(nm)
|
||||
if source == nil {
|
||||
return fmt.Errorf("network logger requires a non-nil NodeSource")
|
||||
}
|
||||
nl.source = source
|
||||
|
||||
// Startup a log stream to Tailscale's logging service.
|
||||
if logf == nil {
|
||||
@@ -194,8 +211,7 @@ func (nl *Logger) Startup(logf logger.Logf, nm *netmap.NetworkMap, nodeLogID, do
|
||||
|
||||
// Purge state.
|
||||
nl.shutdownLocked = nil
|
||||
nl.selfNode = nodeUser{}
|
||||
nl.allNodes = nil
|
||||
nl.source = nil
|
||||
nl.routeAddrs = nil
|
||||
nl.routePrefixes = nil
|
||||
|
||||
@@ -249,15 +265,15 @@ func (nl *Logger) addNewVirtConnLocked(c netlogtype.Connection) connType {
|
||||
var srcNodeLen, dstNodeLen int
|
||||
srcNode, srcSeen := nl.record.seenNodes[c.Src.Addr()]
|
||||
if !srcSeen {
|
||||
srcNode = nl.allNodes[c.Src.Addr()]
|
||||
if srcNode.Valid() {
|
||||
if node, user, ok := nl.source.NodeByAddr(c.Src.Addr()); ok {
|
||||
srcNode = nodeUser{node, user}
|
||||
srcNodeLen = srcNode.jsonLen()
|
||||
}
|
||||
}
|
||||
dstNode, dstSeen := nl.record.seenNodes[c.Dst.Addr()]
|
||||
if !dstSeen {
|
||||
dstNode = nl.allNodes[c.Dst.Addr()]
|
||||
if dstNode.Valid() {
|
||||
if node, user, ok := nl.source.NodeByAddr(c.Dst.Addr()); ok {
|
||||
dstNode = nodeUser{node, user}
|
||||
dstNodeLen = dstNode.jsonLen()
|
||||
}
|
||||
}
|
||||
@@ -279,12 +295,10 @@ func (nl *Logger) addNewVirtConnLocked(c netlogtype.Connection) connType {
|
||||
nl.recordLen += netlogtype.MaxConnectionCountsJSONSize + srcNodeLen + dstNodeLen
|
||||
|
||||
// Classify the traffic type.
|
||||
var srcIsSelfNode bool
|
||||
if nl.selfNode.Valid() {
|
||||
srcIsSelfNode = nl.selfNode.Addresses().ContainsFunc(func(p netip.Prefix) bool {
|
||||
return c.Src.Addr() == p.Addr() && p.IsSingleIP()
|
||||
})
|
||||
}
|
||||
// srcNode == self iff NodeByAddr resolved the source to the same node as
|
||||
// the current record's self.
|
||||
srcIsSelfNode := srcNode.Valid() && nl.record.selfNode.Valid() &&
|
||||
srcNode.ID() == nl.record.selfNode.ID()
|
||||
switch {
|
||||
case srcIsSelfNode && dstNode.Valid():
|
||||
return virtualTraffic
|
||||
@@ -335,8 +349,8 @@ func (nl *Logger) addNewPhysConnLocked(c netlogtype.Connection) {
|
||||
var srcNodeLen int
|
||||
srcNode, srcSeen := nl.record.seenNodes[c.Src.Addr()]
|
||||
if !srcSeen {
|
||||
srcNode = nl.allNodes[c.Src.Addr()]
|
||||
if srcNode.Valid() {
|
||||
if node, user, ok := nl.source.NodeByAddr(c.Src.Addr()); ok {
|
||||
srcNode = nodeUser{node, user}
|
||||
srcNodeLen = srcNode.jsonLen()
|
||||
}
|
||||
}
|
||||
@@ -361,14 +375,16 @@ func (nl *Logger) initRecordLocked() {
|
||||
if nl.recordLen != 0 {
|
||||
return
|
||||
}
|
||||
node, user := nl.source.SelfNode()
|
||||
self := nodeUser{node, user}
|
||||
nl.record = record{
|
||||
selfNode: nl.selfNode,
|
||||
selfNode: self,
|
||||
start: time.Now().UTC(),
|
||||
seenNodes: make(map[netip.Addr]nodeUser),
|
||||
virtConns: make(map[netlogtype.Connection]countsType),
|
||||
physConns: make(map[netlogtype.Connection]netlogtype.Counts),
|
||||
}
|
||||
nl.recordLen = netlogtype.MinMessageJSONSize + nl.selfNode.jsonLen()
|
||||
nl.recordLen = netlogtype.MinMessageJSONSize + self.jsonLen()
|
||||
|
||||
// Start a time to auto-flush the record.
|
||||
// Avoid tickers since continually waking up a goroutine
|
||||
@@ -406,39 +422,6 @@ func (nl *Logger) flushRecordLocked() {
|
||||
nl.recordLen = 0
|
||||
}
|
||||
|
||||
func makeNodeMaps(nm *netmap.NetworkMap) (selfNode nodeUser, allNodes map[netip.Addr]nodeUser) {
|
||||
if nm == nil {
|
||||
return
|
||||
}
|
||||
allNodes = make(map[netip.Addr]nodeUser)
|
||||
if nm.SelfNode.Valid() {
|
||||
selfNode = nodeUser{nm.SelfNode, nm.UserProfiles[nm.SelfNode.User()]}
|
||||
for _, addr := range nm.SelfNode.Addresses().All() {
|
||||
if addr.IsSingleIP() {
|
||||
allNodes[addr.Addr()] = selfNode
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, peer := range nm.Peers {
|
||||
if peer.Valid() {
|
||||
for _, addr := range peer.Addresses().All() {
|
||||
if addr.IsSingleIP() {
|
||||
allNodes[addr.Addr()] = nodeUser{peer, nm.UserProfiles[peer.User()]}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selfNode, allNodes
|
||||
}
|
||||
|
||||
// ReconfigNetworkMap configures the network logger with an updated netmap.
|
||||
func (nl *Logger) ReconfigNetworkMap(nm *netmap.NetworkMap) {
|
||||
selfNode, allNodes := makeNodeMaps(nm) // avoid holding lock while making maps
|
||||
nl.mu.Lock()
|
||||
nl.selfNode, nl.allNodes = selfNode, allNodes
|
||||
nl.mu.Unlock()
|
||||
}
|
||||
|
||||
func makeRouteMaps(cfg *router.Config) (addrs set.Set[netip.Addr], prefixes []netip.Prefix) {
|
||||
addrs = make(set.Set[netip.Addr])
|
||||
insertPrefixes := func(rs []netip.Prefix) {
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
type Logger struct{}
|
||||
|
||||
func (*Logger) Startup(...any) error { return nil }
|
||||
func (*Logger) Running() bool { return false }
|
||||
func (*Logger) Shutdown(any) error { return nil }
|
||||
func (*Logger) ReconfigNetworkMap(any) {}
|
||||
func (*Logger) ReconfigRoutes(any) {}
|
||||
// NodeSource is a stub kept so the omit build does not break consumers that
|
||||
// reference the type. It has no methods.
|
||||
type NodeSource any
|
||||
|
||||
func (*Logger) Startup(...any) error { return nil }
|
||||
func (*Logger) Running() bool { return false }
|
||||
func (*Logger) Shutdown(any) error { return nil }
|
||||
func (*Logger) ReconfigRoutes(any) {}
|
||||
|
||||
@@ -21,22 +21,74 @@
|
||||
"tailscale.com/types/bools"
|
||||
"tailscale.com/types/ipproto"
|
||||
"tailscale.com/types/netlogtype"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/wgengine/router"
|
||||
)
|
||||
|
||||
// nodeAndUser pairs a [tailcfg.NodeView] with its owning user profile.
|
||||
type nodeAndUser struct {
|
||||
node tailcfg.NodeView
|
||||
user tailcfg.UserProfileView
|
||||
}
|
||||
|
||||
// fakeNodeSource is a [NodeSource] implementation backed by static maps,
|
||||
// for tests.
|
||||
type fakeNodeSource struct {
|
||||
self tailcfg.NodeView
|
||||
selfUser tailcfg.UserProfileView
|
||||
byAddr map[netip.Addr]nodeAndUser
|
||||
}
|
||||
|
||||
func (s *fakeNodeSource) SelfNode() (tailcfg.NodeView, tailcfg.UserProfileView) {
|
||||
return s.self, s.selfUser
|
||||
}
|
||||
|
||||
func (s *fakeNodeSource) NodeByAddr(a netip.Addr) (_ tailcfg.NodeView, _ tailcfg.UserProfileView, ok bool) {
|
||||
nu, ok := s.byAddr[a]
|
||||
return nu.node, nu.user, ok
|
||||
}
|
||||
|
||||
// newFakeNodeSource builds a [fakeNodeSource] from a self [tailcfg.NodeView],
|
||||
// a list of peer [tailcfg.NodeView] values, and a UserProfile map.
|
||||
// All single-IP addresses on self and the peers are indexed for NodeByAddr.
|
||||
func newFakeNodeSource(self tailcfg.NodeView, peers []tailcfg.NodeView, users map[tailcfg.UserID]tailcfg.UserProfileView) *fakeNodeSource {
|
||||
s := &fakeNodeSource{
|
||||
byAddr: map[netip.Addr]nodeAndUser{},
|
||||
}
|
||||
if self.Valid() {
|
||||
s.self = self
|
||||
s.selfUser = users[self.User()]
|
||||
for _, p := range self.Addresses().All() {
|
||||
if p.IsSingleIP() {
|
||||
s.byAddr[p.Addr()] = nodeAndUser{self, s.selfUser}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, peer := range peers {
|
||||
if !peer.Valid() {
|
||||
continue
|
||||
}
|
||||
pu := users[peer.User()]
|
||||
for _, p := range peer.Addresses().All() {
|
||||
if p.IsSingleIP() {
|
||||
s.byAddr[p.Addr()] = nodeAndUser{peer, pu}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func TestEmbedNodeInfo(t *testing.T) {
|
||||
// Initialize the logger with a particular view of the netmap.
|
||||
// Initialize the logger with a particular view of the node state.
|
||||
var logger Logger
|
||||
logger.ReconfigNetworkMap(&netmap.NetworkMap{
|
||||
SelfNode: (&tailcfg.Node{
|
||||
logger.source = newFakeNodeSource(
|
||||
(&tailcfg.Node{
|
||||
StableID: "n123456CNTL",
|
||||
ID: 123456,
|
||||
Name: "test.tail123456.ts.net",
|
||||
Addresses: []netip.Prefix{prefix("100.1.2.3")},
|
||||
Tags: []string{"tag:foo", "tag:bar"},
|
||||
}).View(),
|
||||
Peers: []tailcfg.NodeView{
|
||||
[]tailcfg.NodeView{
|
||||
(&tailcfg.Node{
|
||||
StableID: "n123457CNTL",
|
||||
ID: 123457,
|
||||
@@ -52,10 +104,10 @@ func TestEmbedNodeInfo(t *testing.T) {
|
||||
User: 54321,
|
||||
}).View(),
|
||||
},
|
||||
UserProfiles: map[tailcfg.UserID]tailcfg.UserProfileView{
|
||||
map[tailcfg.UserID]tailcfg.UserProfileView{
|
||||
54321: (&tailcfg.UserProfile{ID: 54321, LoginName: "peer@example.com"}).View(),
|
||||
},
|
||||
})
|
||||
)
|
||||
logger.ReconfigRoutes(&router.Config{
|
||||
SubnetRoutes: []netip.Prefix{
|
||||
prefix("172.16.1.1/16"),
|
||||
@@ -148,6 +200,9 @@ func TestEmbedNodeInfo(t *testing.T) {
|
||||
|
||||
func TestUpdateRace(t *testing.T) {
|
||||
var logger Logger
|
||||
// Install an empty fake source so NodeByAddr / SelfNode are exercised on
|
||||
// the lookup path without returning any matches.
|
||||
logger.source = &fakeNodeSource{}
|
||||
logger.recordsChan = make(chan record, 1)
|
||||
go func(recordsChan chan record) {
|
||||
for range recordsChan {
|
||||
@@ -167,11 +222,6 @@ func TestUpdateRace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
})
|
||||
group.Go(func() {
|
||||
for range 1000 {
|
||||
logger.ReconfigNetworkMap(new(netmap.NetworkMap))
|
||||
}
|
||||
})
|
||||
group.Go(func() {
|
||||
for range 1000 {
|
||||
logger.ReconfigRoutes(new(router.Config))
|
||||
@@ -194,6 +244,7 @@ func randAddrPort() netip.AddrPort {
|
||||
|
||||
func TestAutoFlushMaxConns(t *testing.T) {
|
||||
var logger Logger
|
||||
logger.source = &fakeNodeSource{}
|
||||
logger.recordsChan = make(chan record, 1)
|
||||
for i := 0; len(logger.recordsChan) == 0; i++ {
|
||||
logger.updateVirtConn(0, netip.AddrPortFrom(netip.Addr{}, uint16(i)), netip.AddrPort{}, 1, 1, false)
|
||||
@@ -206,6 +257,7 @@ func TestAutoFlushMaxConns(t *testing.T) {
|
||||
|
||||
func TestAutoFlushTimeout(t *testing.T) {
|
||||
var logger Logger
|
||||
logger.source = &fakeNodeSource{}
|
||||
logger.recordsChan = make(chan record, 1)
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
logger.updateVirtConn(0, netip.AddrPort{}, netip.AddrPort{}, 1, 1, false)
|
||||
@@ -222,6 +274,7 @@ func TestAutoFlushTimeout(t *testing.T) {
|
||||
|
||||
func BenchmarkUpdateSameConn(b *testing.B) {
|
||||
var logger Logger
|
||||
logger.source = &fakeNodeSource{}
|
||||
b.ReportAllocs()
|
||||
for range b.N {
|
||||
logger.updateVirtConn(0, netip.AddrPort{}, netip.AddrPort{}, 1, 1, false)
|
||||
@@ -230,6 +283,7 @@ func BenchmarkUpdateSameConn(b *testing.B) {
|
||||
|
||||
func BenchmarkUpdateNewConns(b *testing.B) {
|
||||
var logger Logger
|
||||
logger.source = &fakeNodeSource{}
|
||||
b.ReportAllocs()
|
||||
for i := range b.N {
|
||||
logger.updateVirtConn(0, netip.AddrPortFrom(netip.Addr{}, uint16(i)), netip.AddrPort{}, 1, 1, false)
|
||||
|
||||
@@ -157,6 +157,11 @@ type userspaceEngine struct {
|
||||
// networkLogger logs statistics about network connections.
|
||||
networkLogger netlog.Logger
|
||||
|
||||
// netLogSource is the [netlog.NodeSource] installed via
|
||||
// [Engine.SetNetLogNodeSource]; it is read when starting up the network
|
||||
// logger from inside Reconfig. It may be nil if no source was installed.
|
||||
netLogSource syncs.AtomicValue[netlog.NodeSource]
|
||||
|
||||
// tsmpLearnedDisco tracks per node key if a peer disco key was learned via TSMP.
|
||||
// wgLock must be held when using this map.
|
||||
tsmpLearnedDisco map[key.NodePublic]key.DiscoPublic
|
||||
@@ -735,6 +740,12 @@ func (e *userspaceEngine) SetPeerSessionStateFunc(fn func(key.NodePublic, PeerWi
|
||||
})
|
||||
}
|
||||
|
||||
// SetNetLogNodeSource installs the [netlog.NodeSource] used by the engine's
|
||||
// network logger.
|
||||
func (e *userspaceEngine) SetNetLogNodeSource(src netlog.NodeSource) {
|
||||
e.netLogSource.Store(src)
|
||||
}
|
||||
|
||||
func peerWireGuardStateFromDevice(state device.PeerSessionState) PeerWireGuardState {
|
||||
switch state {
|
||||
case device.PeerSessionNone:
|
||||
@@ -969,7 +980,10 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
tid := cfg.NetworkLogging.DomainID
|
||||
logExitFlowEnabled := cfg.NetworkLogging.LogExitFlowEnabled
|
||||
e.logf("wgengine: Reconfig: starting up network logger (node:%s tailnet:%s)", nid.Public(), tid.Public())
|
||||
if err := e.networkLogger.Startup(e.logf, nm, nid, tid, e.tundev, e.magicConn, e.netMon, e.health, e.eventBus, logExitFlowEnabled); err != nil {
|
||||
src := e.netLogSource.Load()
|
||||
if src == nil {
|
||||
e.logf("wgengine: Reconfig: no NodeSource installed; network logger not started")
|
||||
} else if err := e.networkLogger.Startup(e.logf, src, nid, tid, e.tundev, e.magicConn, e.netMon, e.health, e.eventBus, logExitFlowEnabled); err != nil {
|
||||
e.logf("wgengine: Reconfig: error starting up network logger: %v", err)
|
||||
}
|
||||
e.networkLogger.ReconfigRoutes(routerCfg)
|
||||
@@ -1309,9 +1323,6 @@ func (e *userspaceEngine) SetNetworkMap(nm *netmap.NetworkMap) {
|
||||
curUDP, curTCP)
|
||||
e.tundev.ApplyGROKnobs(e.controlKnobs)
|
||||
}
|
||||
if e.networkLogger.Running() {
|
||||
e.networkLogger.ReconfigNetworkMap(nm)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) UpdateStatus(sb *ipnstate.StatusBuilder) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/wgengine/filter"
|
||||
"tailscale.com/wgengine/netlog"
|
||||
"tailscale.com/wgengine/router"
|
||||
"tailscale.com/wgengine/wgcfg"
|
||||
"tailscale.com/wgengine/wgint"
|
||||
@@ -164,6 +165,13 @@ type Engine interface {
|
||||
// look up which peer should handle an outbound packet by destination IP.
|
||||
SetPeerByIPPacketFunc(func(netip.Addr) (_ key.NodePublic, ok bool))
|
||||
|
||||
// SetNetLogNodeSource installs the [netlog.NodeSource] used by the engine's
|
||||
// network logger to look up Tailscale node info on demand.
|
||||
//
|
||||
// It is expected to be called once during LocalBackend construction,
|
||||
// before any [Engine.Reconfig] call that starts up the network logger.
|
||||
SetNetLogNodeSource(netlog.NodeSource)
|
||||
|
||||
// SetPeerSessionStateFunc installs a callback used to observe WireGuard
|
||||
// peer session state transitions.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user