mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-15 01:53:08 -04:00
control/controlknobs,wgengine/magicsock: disable TSMP disco advert if netmap caching is disabled
Updates #20081 Signed-off-by: Jordan Whited <jordan@tailscale.com>
This commit is contained in:
committed by
Jordan Whited
parent
8f210454dd
commit
be2f554dd3
@@ -135,6 +135,11 @@ type Knobs struct {
|
|||||||
// underlay UDP packet TX path on Linux. Applies to magicsock and peer relay
|
// underlay UDP packet TX path on Linux. Applies to magicsock and peer relay
|
||||||
// UDP sockets. See [tailcfg.NodeAttrNeverGSOEqualTail].
|
// UDP sockets. See [tailcfg.NodeAttrNeverGSOEqualTail].
|
||||||
NeverGSOEqualTail atomic.Bool
|
NeverGSOEqualTail atomic.Bool
|
||||||
|
|
||||||
|
// CacheNetworkMaps is whether the node should persistently cache network
|
||||||
|
// maps and use them to establish peer connectivity on start, if doing so
|
||||||
|
// is supported by the client and storage is available.
|
||||||
|
CacheNetworkMaps atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFromNodeAttributes updates k (if non-nil) based on the provided self
|
// UpdateFromNodeAttributes updates k (if non-nil) based on the provided self
|
||||||
@@ -170,6 +175,7 @@ func (k *Knobs) UpdateFromNodeAttributes(capMap tailcfg.NodeCapMap) {
|
|||||||
disableTUNUDPGRO = has(tailcfg.NodeAttrDisableTUNUDPGRO)
|
disableTUNUDPGRO = has(tailcfg.NodeAttrDisableTUNUDPGRO)
|
||||||
disableTUNTCPGRO = has(tailcfg.NodeAttrDisableTUNTCPGRO)
|
disableTUNTCPGRO = has(tailcfg.NodeAttrDisableTUNTCPGRO)
|
||||||
neverGSOEqualTail = has(tailcfg.NodeAttrNeverGSOEqualTail)
|
neverGSOEqualTail = has(tailcfg.NodeAttrNeverGSOEqualTail)
|
||||||
|
cacheNetworkMaps = has(tailcfg.NodeAttrCacheNetworkMaps)
|
||||||
)
|
)
|
||||||
|
|
||||||
if has(tailcfg.NodeAttrOneCGNATEnable) {
|
if has(tailcfg.NodeAttrOneCGNATEnable) {
|
||||||
@@ -203,6 +209,7 @@ func (k *Knobs) UpdateFromNodeAttributes(capMap tailcfg.NodeCapMap) {
|
|||||||
k.DisableTUNUDPGRO.Store(disableTUNUDPGRO)
|
k.DisableTUNUDPGRO.Store(disableTUNUDPGRO)
|
||||||
k.DisableTUNTCPGRO.Store(disableTUNTCPGRO)
|
k.DisableTUNTCPGRO.Store(disableTUNTCPGRO)
|
||||||
k.NeverGSOEqualTail.Store(neverGSOEqualTail)
|
k.NeverGSOEqualTail.Store(neverGSOEqualTail)
|
||||||
|
k.CacheNetworkMaps.Store(cacheNetworkMaps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsDebugJSON returns k as something that can be marshalled with json.Marshal
|
// AsDebugJSON returns k as something that can be marshalled with json.Marshal
|
||||||
|
|||||||
@@ -4526,8 +4526,10 @@ type NewDiscoKeyAvailable struct {
|
|||||||
|
|
||||||
// maybeSendTSMPDiscoAdvert conditionally emits an event indicating that we
|
// maybeSendTSMPDiscoAdvert conditionally emits an event indicating that we
|
||||||
// should send our DiscoKey to the first node address of the magicksock endpoint.
|
// should send our DiscoKey to the first node address of the magicksock endpoint.
|
||||||
// The event is only emitted if we are not already communicating directly and
|
//
|
||||||
// more than 60 seconds has passed since the last DiscoKey was sent.
|
// The event is suppressed if we are already communicating directly or
|
||||||
|
// less than 60 seconds has passed since the last DiscoKey was sent, or netmap
|
||||||
|
// caching is disabled on this node.
|
||||||
//
|
//
|
||||||
// We do not need the Conn to be locked, but the endpoint should be.
|
// We do not need the Conn to be locked, but the endpoint should be.
|
||||||
func (c *Conn) maybeSendTSMPDiscoAdvert(de *endpoint) {
|
func (c *Conn) maybeSendTSMPDiscoAdvert(de *endpoint) {
|
||||||
@@ -4535,6 +4537,17 @@ func (c *Conn) maybeSendTSMPDiscoAdvert(de *endpoint) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable TSMP disco advert by default, unless network map caching is
|
||||||
|
// enabled for the local node. Caching network maps on the remote node is
|
||||||
|
// what really matters in terms of handling a TSMP disco advert and applying
|
||||||
|
// it in a useful way, but the TSMP disco advert implementation as it exists
|
||||||
|
// here has pathological behaviors. Therefore, it should be disabled for
|
||||||
|
// almost all tailnets, and we lean on the network map caching control knob
|
||||||
|
// for this purpose. See #20081.
|
||||||
|
if c.controlKnobs == nil || !c.controlKnobs.CacheNetworkMaps.Load() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
de.mu.Lock()
|
de.mu.Lock()
|
||||||
defer de.mu.Unlock()
|
defer de.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -4515,6 +4515,10 @@ func TestSendingTSMPDiscoTimer(t *testing.T) {
|
|||||||
tw := eventbustest.NewWatcher(t, conn.eventBus)
|
tw := eventbustest.NewWatcher(t, conn.eventBus)
|
||||||
t.Cleanup(func() { conn.Close() })
|
t.Cleanup(func() { conn.Close() })
|
||||||
|
|
||||||
|
// maybeSendTSMPDiscoAdvert only advertises when netmap caching is enabled.
|
||||||
|
conn.controlKnobs = new(controlknobs.Knobs)
|
||||||
|
conn.controlKnobs.CacheNetworkMaps.Store(true)
|
||||||
|
|
||||||
peerKey := key.NewNode().Public()
|
peerKey := key.NewNode().Public()
|
||||||
ep := &endpoint{
|
ep := &endpoint{
|
||||||
nodeID: 1,
|
nodeID: 1,
|
||||||
@@ -4576,3 +4580,43 @@ func TestSendingTSMPDiscoTimer(t *testing.T) {
|
|||||||
t.Errorf("expected only one event, got: %s", err)
|
t.Errorf("expected only one event, got: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestSendingTSMPDiscoCachingDisabled verifies that maybeSendTSMPDiscoAdvert
|
||||||
|
// early-returns (sends no advert) when netmap caching is not enabled via the
|
||||||
|
// CacheNetworkMaps control knob, including when no knobs are present at all.
|
||||||
|
func TestSendingTSMPDiscoCachingDisabled(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
knobs *controlknobs.Knobs
|
||||||
|
}{
|
||||||
|
{name: "no-knobs", knobs: nil},
|
||||||
|
// Knobs present but CacheNetworkMaps left at its false default.
|
||||||
|
{name: "caching-disabled", knobs: new(controlknobs.Knobs)},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
conn := newTestConn(t)
|
||||||
|
t.Cleanup(func() { conn.Close() })
|
||||||
|
conn.controlKnobs = tt.knobs
|
||||||
|
|
||||||
|
ep := &endpoint{
|
||||||
|
nodeID: 1,
|
||||||
|
publicKey: key.NewNode().Public(),
|
||||||
|
nodeAddr: netip.MustParseAddr("100.64.0.1"),
|
||||||
|
}
|
||||||
|
ep.c = conn
|
||||||
|
|
||||||
|
// A fresh endpoint with a zero lastDiscoKeyAdvertisement and no
|
||||||
|
// direct bestAddr would otherwise advertise; the only thing
|
||||||
|
// suppressing it here is the disabled caching knob. On early
|
||||||
|
// return the timestamp is left untouched (zero).
|
||||||
|
conn.maybeSendTSMPDiscoAdvert(ep)
|
||||||
|
|
||||||
|
ep.mu.Lock()
|
||||||
|
defer ep.mu.Unlock()
|
||||||
|
if !ep.lastDiscoKeyAdvertisement.IsZero() {
|
||||||
|
t.Errorf("lastDiscoKeyAdvertisement = %v; want zero (advert should have been suppressed)", ep.lastDiscoKeyAdvertisement)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user