control/controlknobs,net/{batching,tstun},wgengine: add nodecaps to disable UDP & TUN GRO/GSO
Add four control-plane node attributes that let us disable UDP GSO/GRO
on the magicsock UDP socket and UDP/TCP GRO on the Tailscale TUN
device.
These complement the pre-existing TS_DEBUG_DISABLE_UDP_{GRO,GSO} and
TS_TUN_DISABLE_{UDP,TCP}_GRO envknobs. They exist so we can mitigate
upstream Linux kernel regressions on a deployed fleet without
requiring a client release, after two incidents (#13041, #19777) where
buggy kernel patches landed upstream and the fix took an excessively
long time to reach downstream distros.
Knob changes are reacted to in setNetworkMapInternal / SetNetworkMap via
a comparison against a cached "last applied" value and only an actual
transition triggers work: magicsock Rebind()+ReSTUN for UDP,
ApplyGROKnobs for TUN. The TUN side is gated by buildfeatures.HasGRO and
is one-way (wireguard-go GRO disablement is sticky); re-enabling
requires a client restart.
Updates #13041
Updates #19777
Change-Id: I802993070afa659cc06809bb0bfbb7f8a0cdb273
Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
committed by
James Tucker
parent
94af1b00fb
commit
25b8ed8d9e
+36
-1
@@ -130,6 +130,14 @@ type userspaceEngine struct {
|
||||
reconfigureVPN func() error // or nil
|
||||
conn25PacketHooks Conn25PacketHooks // or nil
|
||||
|
||||
// lastAppliedDisableTUNUDPGRO and lastAppliedDisableTUNTCPGRO cache the
|
||||
// controlknobs values that were last applied to the TUN device. They are
|
||||
// read and updated under e.mu and only consulted when buildfeatures.HasGRO
|
||||
// is true. Note: wireguard-go's GRO disablement is one-way (sticky), so
|
||||
// transitions from disabled back to enabled require a client restart.
|
||||
lastAppliedDisableTUNUDPGRO bool
|
||||
lastAppliedDisableTUNTCPGRO bool
|
||||
|
||||
mu sync.Mutex // guards following; see lock order comment below
|
||||
netMap *netmap.NetworkMap // or nil
|
||||
closing bool // Close was called (even if we're still closing)
|
||||
@@ -564,7 +572,15 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
||||
if err := e.router.Up(); err != nil {
|
||||
return nil, fmt.Errorf("router.Up: %w", err)
|
||||
}
|
||||
tsTUNDev.SetLinkFeaturesPostUp()
|
||||
tsTUNDev.SetLinkFeaturesPostUp(e.controlKnobs)
|
||||
if buildfeatures.HasGRO && runtime.GOOS == "linux" && e.controlKnobs != nil {
|
||||
// Seed the cached "last applied" TUN GRO knob values so the first
|
||||
// netmap update doesn't spuriously call ApplyGROKnobs:
|
||||
// SetLinkFeaturesPostUp above already applied these same values. We
|
||||
// only do this on Linux because ApplyGROKnobs is a no-op elsewhere.
|
||||
e.lastAppliedDisableTUNUDPGRO = e.controlKnobs.DisableTUNUDPGRO.Load()
|
||||
e.lastAppliedDisableTUNTCPGRO = e.controlKnobs.DisableTUNTCPGRO.Load()
|
||||
}
|
||||
|
||||
// It's a little pointless to apply no-op settings here (they
|
||||
// should already be empty?), but it at least exercises the
|
||||
@@ -1278,7 +1294,26 @@ func (e *userspaceEngine) linkChange(delta *netmon.ChangeDelta) {
|
||||
func (e *userspaceEngine) SetNetworkMap(nm *netmap.NetworkMap) {
|
||||
e.mu.Lock()
|
||||
e.netMap = nm
|
||||
tunGROKnobsChanged := false
|
||||
var curUDP, curTCP bool
|
||||
if buildfeatures.HasGRO && runtime.GOOS == "linux" && e.controlKnobs != nil {
|
||||
curUDP = e.controlKnobs.DisableTUNUDPGRO.Load()
|
||||
curTCP = e.controlKnobs.DisableTUNTCPGRO.Load()
|
||||
// Only act on transitions toward "disabled"; wireguard-go's GRO
|
||||
// disablement is sticky and cannot be reversed without restart.
|
||||
if (curUDP && !e.lastAppliedDisableTUNUDPGRO) ||
|
||||
(curTCP && !e.lastAppliedDisableTUNTCPGRO) {
|
||||
tunGROKnobsChanged = true
|
||||
}
|
||||
e.lastAppliedDisableTUNUDPGRO = curUDP
|
||||
e.lastAppliedDisableTUNTCPGRO = curTCP
|
||||
}
|
||||
e.mu.Unlock()
|
||||
if buildfeatures.HasGRO && tunGROKnobsChanged {
|
||||
e.logf("wgengine: TUN GRO knobs changed (DisableTUNUDPGRO=%v DisableTUNTCPGRO=%v); applying",
|
||||
curUDP, curTCP)
|
||||
e.tundev.ApplyGROKnobs(e.controlKnobs)
|
||||
}
|
||||
if e.networkLogger.Running() {
|
||||
e.networkLogger.ReconfigNetworkMap(nm)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user