mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 11:28:58 +00:00
Move setupConntrack from server_linux.go to conntrack.go
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
@@ -19,18 +22,24 @@ package app
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/machine"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
|
||||
"k8s.io/component-helpers/node/util/sysctl"
|
||||
"k8s.io/klog/v2"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
|
||||
)
|
||||
|
||||
// Conntracker is an interface to the global sysctl. Descriptions of the various
|
||||
// sysctl fields can be found here:
|
||||
// conntrackConfigurer is a mockable interface for setting conntrack sysctls.
|
||||
//
|
||||
// Descriptions of the various sysctl fields can be found here:
|
||||
// https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl.txt
|
||||
type Conntracker interface {
|
||||
type conntrackConfigurer interface {
|
||||
// SetMax adjusts nf_conntrack_max.
|
||||
SetMax(ctx context.Context, max int) error
|
||||
// SetTCPEstablishedTimeout adjusts nf_conntrack_tcp_timeout_established.
|
||||
@@ -45,10 +54,86 @@ type Conntracker interface {
|
||||
SetUDPStreamTimeout(ctx context.Context, seconds int) error
|
||||
}
|
||||
|
||||
type realConntracker struct {
|
||||
func setupConntrack(ctx context.Context, ct conntrackConfigurer, config *proxyconfigapi.KubeProxyConntrackConfiguration) error {
|
||||
max, err := getConntrackMax(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if max > 0 {
|
||||
err := ct.SetMax(ctx, max)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.TCPEstablishedTimeout != nil && config.TCPEstablishedTimeout.Duration > 0 {
|
||||
timeout := int(config.TCPEstablishedTimeout.Duration / time.Second)
|
||||
if err := ct.SetTCPEstablishedTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.TCPCloseWaitTimeout != nil && config.TCPCloseWaitTimeout.Duration > 0 {
|
||||
timeout := int(config.TCPCloseWaitTimeout.Duration / time.Second)
|
||||
if err := ct.SetTCPCloseWaitTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.TCPBeLiberal {
|
||||
if err := ct.SetTCPBeLiberal(ctx, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.UDPTimeout.Duration > 0 {
|
||||
timeout := int(config.UDPTimeout.Duration / time.Second)
|
||||
if err := ct.SetUDPTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.UDPStreamTimeout.Duration > 0 {
|
||||
timeout := int(config.UDPStreamTimeout.Duration / time.Second)
|
||||
if err := ct.SetUDPStreamTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetMax(ctx context.Context, max int) error {
|
||||
func getConntrackMax(ctx context.Context, config *proxyconfigapi.KubeProxyConntrackConfiguration) (int, error) {
|
||||
logger := klog.FromContext(ctx)
|
||||
if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
|
||||
floor := 0
|
||||
if config.Min != nil {
|
||||
floor = int(*config.Min)
|
||||
}
|
||||
scaled := int(*config.MaxPerCore) * detectNumCPU()
|
||||
if scaled > floor {
|
||||
logger.V(3).Info("GetConntrackMax: using scaled conntrack-max-per-core")
|
||||
return scaled, nil
|
||||
}
|
||||
logger.V(3).Info("GetConntrackMax: using conntrack-min")
|
||||
return floor, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func detectNumCPU() int {
|
||||
// try get numCPU from /sys firstly due to a known issue (https://github.com/kubernetes/kubernetes/issues/99225)
|
||||
_, numCPU, err := machine.GetTopology(sysfs.NewRealSysFs())
|
||||
if err != nil || numCPU < 1 {
|
||||
return runtime.NumCPU()
|
||||
}
|
||||
return numCPU
|
||||
}
|
||||
|
||||
type realConntrackConfigurer struct {
|
||||
}
|
||||
|
||||
func (rct realConntrackConfigurer) SetMax(ctx context.Context, max int) error {
|
||||
logger := klog.FromContext(ctx)
|
||||
logger.Info("Setting nf_conntrack_max", "nfConntrackMax", max)
|
||||
if err := rct.setIntSysCtl(ctx, "nf_conntrack_max", max); err != nil {
|
||||
@@ -68,27 +153,27 @@ func (rct realConntracker) SetMax(ctx context.Context, max int) error {
|
||||
return writeIntStringFile("/sys/module/nf_conntrack/parameters/hashsize", max/4)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetTCPEstablishedTimeout(ctx context.Context, seconds int) error {
|
||||
func (rct realConntrackConfigurer) SetTCPEstablishedTimeout(ctx context.Context, seconds int) error {
|
||||
return rct.setIntSysCtl(ctx, "nf_conntrack_tcp_timeout_established", seconds)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetTCPCloseWaitTimeout(ctx context.Context, seconds int) error {
|
||||
func (rct realConntrackConfigurer) SetTCPCloseWaitTimeout(ctx context.Context, seconds int) error {
|
||||
return rct.setIntSysCtl(ctx, "nf_conntrack_tcp_timeout_close_wait", seconds)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetTCPBeLiberal(ctx context.Context, value int) error {
|
||||
func (rct realConntrackConfigurer) SetTCPBeLiberal(ctx context.Context, value int) error {
|
||||
return rct.setIntSysCtl(ctx, "nf_conntrack_tcp_be_liberal", value)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetUDPTimeout(ctx context.Context, seconds int) error {
|
||||
func (rct realConntrackConfigurer) SetUDPTimeout(ctx context.Context, seconds int) error {
|
||||
return rct.setIntSysCtl(ctx, "nf_conntrack_udp_timeout", seconds)
|
||||
}
|
||||
|
||||
func (rct realConntracker) SetUDPStreamTimeout(ctx context.Context, seconds int) error {
|
||||
func (rct realConntrackConfigurer) SetUDPStreamTimeout(ctx context.Context, seconds int) error {
|
||||
return rct.setIntSysCtl(ctx, "nf_conntrack_udp_timeout_stream", seconds)
|
||||
}
|
||||
|
||||
func (rct realConntracker) setIntSysCtl(ctx context.Context, name string, value int) error {
|
||||
func (rct realConntrackConfigurer) setIntSysCtl(ctx context.Context, name string, value int) error {
|
||||
logger := klog.FromContext(ctx)
|
||||
entry := "net/netfilter/" + name
|
||||
|
||||
|
||||
241
cmd/kube-proxy/app/conntrack_test.go
Normal file
241
cmd/kube-proxy/app/conntrack_test.go
Normal file
@@ -0,0 +1,241 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
|
||||
"k8s.io/kubernetes/test/utils/ktesting"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func TestGetConntrackMax(t *testing.T) {
|
||||
ncores := runtime.NumCPU()
|
||||
testCases := []struct {
|
||||
min int32
|
||||
maxPerCore int32
|
||||
expected int
|
||||
err string
|
||||
}{
|
||||
{
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
maxPerCore: 67890, // use this if Max is 0
|
||||
min: 1, // avoid 0 default
|
||||
expected: 67890 * ncores,
|
||||
},
|
||||
{
|
||||
maxPerCore: 1, // ensure that Min is considered
|
||||
min: 123456,
|
||||
expected: 123456,
|
||||
},
|
||||
{
|
||||
maxPerCore: 0, // leave system setting
|
||||
min: 123456,
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
cfg := proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
Min: ptr.To(tc.min),
|
||||
MaxPerCore: ptr.To(tc.maxPerCore),
|
||||
}
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
x, e := getConntrackMax(ctx, &cfg)
|
||||
if e != nil {
|
||||
if tc.err == "" {
|
||||
t.Errorf("[%d] unexpected error: %v", i, e)
|
||||
} else if !strings.Contains(e.Error(), tc.err) {
|
||||
t.Errorf("[%d] expected an error containing %q: %v", i, tc.err, e)
|
||||
}
|
||||
} else if x != tc.expected {
|
||||
t.Errorf("[%d] expected %d, got %d", i, tc.expected, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeConntracker struct {
|
||||
called []string
|
||||
err error
|
||||
}
|
||||
|
||||
// SetMax value is calculated based on the number of CPUs by getConntrackMax()
|
||||
func (fc *fakeConntracker) SetMax(ctx context.Context, max int) error {
|
||||
fc.called = append(fc.called, "SetMax")
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPEstablishedTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPEstablishedTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPCloseWaitTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPCloseWaitTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPBeLiberal(ctx context.Context, value int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPBeLiberal(%d)", value))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetUDPTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetUDPTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetUDPStreamTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetUDPStreamTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
|
||||
func TestSetupConntrack(t *testing.T) {
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
config proxyconfigapi.KubeProxyConntrackConfiguration
|
||||
expect []string
|
||||
conntrackErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "do nothing if conntrack config is empty",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetMax is called if conntrack.maxPerCore is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: ptr.To(int32(12)),
|
||||
},
|
||||
expect: []string{"SetMax"},
|
||||
},
|
||||
{
|
||||
name: "SetMax is not called if conntrack.maxPerCore is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: ptr.To(int32(0)),
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPEstablishedTimeout is called if conntrack.tcpEstablishedTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPEstablishedTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPEstablishedTimeout is not called if conntrack.tcpEstablishedTimeout is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPCloseWaitTimeout is called if conntrack.tcpCloseWaitTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPCloseWaitTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPCloseWaitTimeout is not called if conntrack.tcpCloseWaitTimeout is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPBeLiberal is called if conntrack.tcpBeLiberal is true",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPBeLiberal: true,
|
||||
},
|
||||
expect: []string{"SetTCPBeLiberal(1)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPBeLiberal is not called if conntrack.tcpBeLiberal is false",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPBeLiberal: false,
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetUDPTimeout is called if conntrack.udpTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetUDPTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetUDPTimeout is called if conntrack.udpTimeout is zero",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetUDPStreamTimeout is called if conntrack.udpStreamTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPStreamTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetUDPStreamTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetUDPStreamTimeout is called if conntrack.udpStreamTimeout is zero",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPStreamTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "an error is returned if conntrack.SetTCPEstablishedTimeout fails",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPEstablishedTimeout(5)"},
|
||||
conntrackErr: errors.New("random error"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fc := &fakeConntracker{err: test.conntrackErr}
|
||||
err := setupConntrack(ctx, fc, &test.config)
|
||||
if test.wantErr && err == nil {
|
||||
t.Errorf("Test %q: Expected error, got nil", test.name)
|
||||
}
|
||||
if !test.wantErr && err != nil {
|
||||
t.Errorf("Test %q: Expected no error, got %v", test.name, err)
|
||||
}
|
||||
if !cmp.Equal(fc.called, test.expect) {
|
||||
t.Errorf("Test %q: Expected conntrack calls: %v, got: %v", test.name, test.expect, fc.called)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
goruntime "runtime"
|
||||
"time"
|
||||
|
||||
"github.com/google/cadvisor/machine"
|
||||
"github.com/google/cadvisor/utils/sysfs"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
utilsysctl "k8s.io/component-helpers/node/util/sysctl"
|
||||
@@ -69,8 +64,8 @@ func (o *Options) platformApplyDefaults(config *proxyconfigapi.KubeProxyConfigur
|
||||
// Proxier. It should fill in any platform-specific fields and perform other
|
||||
// platform-specific setup.
|
||||
func (s *ProxyServer) platformSetup(ctx context.Context) error {
|
||||
ct := &realConntracker{}
|
||||
err := s.setupConntrack(ctx, ct)
|
||||
ct := &realConntrackConfigurer{}
|
||||
err := setupConntrack(ctx, ct, &s.Config.Linux.Conntrack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -296,82 +291,6 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi.
|
||||
return proxier, nil
|
||||
}
|
||||
|
||||
func (s *ProxyServer) setupConntrack(ctx context.Context, ct Conntracker) error {
|
||||
max, err := getConntrackMax(ctx, s.Config.Linux.Conntrack)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if max > 0 {
|
||||
err := ct.SetMax(ctx, max)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.Linux.Conntrack.TCPEstablishedTimeout != nil && s.Config.Linux.Conntrack.TCPEstablishedTimeout.Duration > 0 {
|
||||
timeout := int(s.Config.Linux.Conntrack.TCPEstablishedTimeout.Duration / time.Second)
|
||||
if err := ct.SetTCPEstablishedTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.Linux.Conntrack.TCPCloseWaitTimeout != nil && s.Config.Linux.Conntrack.TCPCloseWaitTimeout.Duration > 0 {
|
||||
timeout := int(s.Config.Linux.Conntrack.TCPCloseWaitTimeout.Duration / time.Second)
|
||||
if err := ct.SetTCPCloseWaitTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.Linux.Conntrack.TCPBeLiberal {
|
||||
if err := ct.SetTCPBeLiberal(ctx, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.Linux.Conntrack.UDPTimeout.Duration > 0 {
|
||||
timeout := int(s.Config.Linux.Conntrack.UDPTimeout.Duration / time.Second)
|
||||
if err := ct.SetUDPTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if s.Config.Linux.Conntrack.UDPStreamTimeout.Duration > 0 {
|
||||
timeout := int(s.Config.Linux.Conntrack.UDPStreamTimeout.Duration / time.Second)
|
||||
if err := ct.SetUDPStreamTimeout(ctx, timeout); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getConntrackMax(ctx context.Context, config proxyconfigapi.KubeProxyConntrackConfiguration) (int, error) {
|
||||
logger := klog.FromContext(ctx)
|
||||
if config.MaxPerCore != nil && *config.MaxPerCore > 0 {
|
||||
floor := 0
|
||||
if config.Min != nil {
|
||||
floor = int(*config.Min)
|
||||
}
|
||||
scaled := int(*config.MaxPerCore) * detectNumCPU()
|
||||
if scaled > floor {
|
||||
logger.V(3).Info("GetConntrackMax: using scaled conntrack-max-per-core")
|
||||
return scaled, nil
|
||||
}
|
||||
logger.V(3).Info("GetConntrackMax: using conntrack-min")
|
||||
return floor, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func detectNumCPU() int {
|
||||
// try get numCPU from /sys firstly due to a known issue (https://github.com/kubernetes/kubernetes/issues/99225)
|
||||
_, numCPU, err := machine.GetTopology(sysfs.NewRealSysFs())
|
||||
if err != nil || numCPU < 1 {
|
||||
return goruntime.NumCPU()
|
||||
}
|
||||
return numCPU
|
||||
}
|
||||
|
||||
func getLocalDetectors(logger klog.Logger, primaryIPFamily v1.IPFamily, config *proxyconfigapi.KubeProxyConfiguration, nodePodCIDRs []string) map[v1.IPFamily]proxyutil.LocalTrafficDetector {
|
||||
localDetectors := map[v1.IPFamily]proxyutil.LocalTrafficDetector{
|
||||
v1.IPv4Protocol: proxyutil.NewNoOpLocalDetector(),
|
||||
|
||||
@@ -20,25 +20,19 @@ limitations under the License.
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
goruntime "runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/spf13/pflag"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
|
||||
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
|
||||
"k8s.io/kubernetes/test/utils/ktesting"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func Test_platformApplyDefaults(t *testing.T) {
|
||||
@@ -555,214 +549,3 @@ detectLocalMode: "BridgeInterface"`)
|
||||
tearDown(file, tempDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConntrackMax(t *testing.T) {
|
||||
ncores := goruntime.NumCPU()
|
||||
testCases := []struct {
|
||||
min int32
|
||||
maxPerCore int32
|
||||
expected int
|
||||
err string
|
||||
}{
|
||||
{
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
maxPerCore: 67890, // use this if Max is 0
|
||||
min: 1, // avoid 0 default
|
||||
expected: 67890 * ncores,
|
||||
},
|
||||
{
|
||||
maxPerCore: 1, // ensure that Min is considered
|
||||
min: 123456,
|
||||
expected: 123456,
|
||||
},
|
||||
{
|
||||
maxPerCore: 0, // leave system setting
|
||||
min: 123456,
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
cfg := proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
Min: ptr.To(tc.min),
|
||||
MaxPerCore: ptr.To(tc.maxPerCore),
|
||||
}
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
x, e := getConntrackMax(ctx, cfg)
|
||||
if e != nil {
|
||||
if tc.err == "" {
|
||||
t.Errorf("[%d] unexpected error: %v", i, e)
|
||||
} else if !strings.Contains(e.Error(), tc.err) {
|
||||
t.Errorf("[%d] expected an error containing %q: %v", i, tc.err, e)
|
||||
}
|
||||
} else if x != tc.expected {
|
||||
t.Errorf("[%d] expected %d, got %d", i, tc.expected, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeConntracker struct {
|
||||
called []string
|
||||
err error
|
||||
}
|
||||
|
||||
// SetMax value is calculated based on the number of CPUs by getConntrackMax()
|
||||
func (fc *fakeConntracker) SetMax(ctx context.Context, max int) error {
|
||||
fc.called = append(fc.called, "SetMax")
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPEstablishedTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPEstablishedTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPCloseWaitTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPCloseWaitTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetTCPBeLiberal(ctx context.Context, value int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetTCPBeLiberal(%d)", value))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetUDPTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetUDPTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
func (fc *fakeConntracker) SetUDPStreamTimeout(ctx context.Context, seconds int) error {
|
||||
fc.called = append(fc.called, fmt.Sprintf("SetUDPStreamTimeout(%d)", seconds))
|
||||
return fc.err
|
||||
}
|
||||
|
||||
func TestSetupConntrack(t *testing.T) {
|
||||
_, ctx := ktesting.NewTestContext(t)
|
||||
tests := []struct {
|
||||
name string
|
||||
config proxyconfigapi.KubeProxyConntrackConfiguration
|
||||
expect []string
|
||||
conntrackErr error
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "do nothing if conntrack config is empty",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetMax is called if conntrack.maxPerCore is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: ptr.To(int32(12)),
|
||||
},
|
||||
expect: []string{"SetMax"},
|
||||
},
|
||||
{
|
||||
name: "SetMax is not called if conntrack.maxPerCore is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
MaxPerCore: ptr.To(int32(0)),
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPEstablishedTimeout is called if conntrack.tcpEstablishedTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPEstablishedTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPEstablishedTimeout is not called if conntrack.tcpEstablishedTimeout is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPCloseWaitTimeout is called if conntrack.tcpCloseWaitTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPCloseWaitTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPCloseWaitTimeout is not called if conntrack.tcpCloseWaitTimeout is 0",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPCloseWaitTimeout: &metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetTCPBeLiberal is called if conntrack.tcpBeLiberal is true",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPBeLiberal: true,
|
||||
},
|
||||
expect: []string{"SetTCPBeLiberal(1)"},
|
||||
},
|
||||
{
|
||||
name: "SetTCPBeLiberal is not called if conntrack.tcpBeLiberal is false",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPBeLiberal: false,
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetUDPTimeout is called if conntrack.udpTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetUDPTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetUDPTimeout is called if conntrack.udpTimeout is zero",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "SetUDPStreamTimeout is called if conntrack.udpStreamTimeout is specified",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPStreamTimeout: metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetUDPStreamTimeout(5)"},
|
||||
},
|
||||
{
|
||||
name: "SetUDPStreamTimeout is called if conntrack.udpStreamTimeout is zero",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
UDPStreamTimeout: metav1.Duration{Duration: 0 * time.Second},
|
||||
},
|
||||
expect: nil,
|
||||
},
|
||||
{
|
||||
name: "an error is returned if conntrack.SetTCPEstablishedTimeout fails",
|
||||
config: proxyconfigapi.KubeProxyConntrackConfiguration{
|
||||
TCPEstablishedTimeout: &metav1.Duration{Duration: 5 * time.Second},
|
||||
},
|
||||
expect: []string{"SetTCPEstablishedTimeout(5)"},
|
||||
conntrackErr: errors.New("random error"),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fc := &fakeConntracker{err: test.conntrackErr}
|
||||
s := &ProxyServer{
|
||||
Config: &proxyconfigapi.KubeProxyConfiguration{
|
||||
Linux: proxyconfigapi.KubeProxyLinuxConfiguration{
|
||||
Conntrack: test.config,
|
||||
},
|
||||
},
|
||||
}
|
||||
err := s.setupConntrack(ctx, fc)
|
||||
if test.wantErr && err == nil {
|
||||
t.Errorf("Test %q: Expected error, got nil", test.name)
|
||||
}
|
||||
if !test.wantErr && err != nil {
|
||||
t.Errorf("Test %q: Expected no error, got %v", test.name, err)
|
||||
}
|
||||
if !cmp.Equal(fc.called, test.expect) {
|
||||
t.Errorf("Test %q: Expected conntrack calls: %v, got: %v", test.name, test.expect, fc.called)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user