ipn/ipnlocal: make Serve idle connection limit configurable (#21179)

* ipn/ipnlocal: make Serve idle connection limit configurable

Allow Kubernetes operator proxy pods to override the per-host idle connection limit through an environment knob.\n\nUpdates tailscale/tailscale#20875

Signed-off-by: maxiscoding28 <max.winslow@icloud.com>

* ipn/ipnlocal: document Serve idle connection default

Signed-off-by: maxiscoding28 <max.winslow@icloud.com>

---------

Signed-off-by: maxiscoding28 <max.winslow@icloud.com>
This commit is contained in:
maxiscoding28 authored and GitHub committed 2026-09-16 11:01:27 +01:00
1 parent 7add2af9ec
commit 044abcc9d2
2 files changed
+26

No files matched your search

+4
View File
@@ -35,6 +35,7 @@
"github.com/pires/go-proxyproto"
"go4.org/mem"
"tailscale.com/envknob"
"tailscale.com/ipn"
"tailscale.com/net/netmon"
"tailscale.com/net/netutil"
@@ -1001,6 +1002,8 @@ func (rp *reverseProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// to the backend. The Transport gets created lazily, at most once.
func (rp *reverseProxy) getTransport() *http.Transport {
return rp.httpTransport.Get(func() *http.Transport {
// Zero preserves http.Transport's default MaxIdleConnsPerHost value.
maxIdleConnsPerHost, _ := envknob.LookupInt("TS_DEBUG_SERVE_MAX_IDLE_CONNS_PER_HOST")
dial := rp.lb.dialer.SystemDial
if rp.socketPath != "" {
dial = func(ctx context.Context, _, _ string) (net.Conn, error) {
@@ -1017,6 +1020,7 @@ func (rp *reverseProxy) getTransport() *http.Transport {
// Values for the following parameters have been copied from http.DefaultTransport.
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
MaxIdleConnsPerHost: maxIdleConnsPerHost,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
+22
View File
@@ -29,9 +29,12 @@
"time"
"tailscale.com/control/controlclient"
"tailscale.com/envknob"
"tailscale.com/health"
"tailscale.com/ipn"
"tailscale.com/ipn/store/mem"
"tailscale.com/net/netmon"
"tailscale.com/net/tsdial"
"tailscale.com/tailcfg"
"tailscale.com/tailcfg/nodecap"
"tailscale.com/tailcfg/peercap"
@@ -1090,6 +1093,25 @@ type test struct {
})
}
func TestServeMaxIdleConnsPerHost(t *testing.T) {
for _, tt := range []struct {
name string
env string
want int
}{
{name: "default", want: 0},
{name: "configured", env: "100", want: 100},
} {
t.Run(tt.name, func(t *testing.T) {
envknob.SetenvForTest(t, "TS_DEBUG_SERVE_MAX_IDLE_CONNS_PER_HOST", tt.env)
rp := &reverseProxy{lb: &LocalBackend{dialer: tsdial.NewDialer(netmon.NewStatic())}}
if got := rp.getTransport().MaxIdleConnsPerHost; got != tt.want {
t.Errorf("MaxIdleConnsPerHost = %d, want %d", got, tt.want)
}
})
}
}
func mustCreateURL(t *testing.T, u string) url.URL {
t.Helper()
uParsed, err := url.Parse(u)