WIP: rebase fork onto upstream/main (v1.103.0) #15
@@ -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 @@ import (
|
||||
"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 @@ import (
|
||||
"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()
|
||||
|
||||
+1
-1
@@ -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+
|
||||
|
||||
+39
-56
@@ -24,12 +24,12 @@ import (
|
||||
"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 @@ var testClient *http.Client
|
||||
// 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 @@ package netlog
|
||||
|
||||
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 @@ import (
|
||||
"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)
|
||||
|
||||
+15
-4
@@ -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 @@ import (
|
||||
"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