diff --git a/cmd/kube-proxy/app/server_others_test.go b/cmd/kube-proxy/app/server_others_test.go index b1ea7c36869..22905ea5374 100644 --- a/cmd/kube-proxy/app/server_others_test.go +++ b/cmd/kube-proxy/app/server_others_test.go @@ -151,6 +151,14 @@ func Test_getProxyMode(t *testing.T) { expected: proxyModeIPVS, scheduler: "sed", }, + { // flag says ipvs, ipset version ok, non-existent scheduler + flag: "ipvs", + kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_sed"}, + kernelVersion: "4.19", + ipsetVersion: ipvs.MinIPSetCheckVersion, + expected: proxyModeIPVS, + scheduler: "foobar", + }, } for i, c := range cases { kcompater := &fakeKernelCompatTester{c.kernelCompat} diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index 9d9ad3da8fd..f7f0c9cb689 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -711,7 +711,11 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner, scheduler } mods = utilipvs.GetRequiredIPVSModules(kernelVersion) wantModules := sets.NewString() - mods = append(mods, utilipvs.GetRequiredSchedulerModules(scheduler)) + schedulerMod, modNotFound := utilipvs.GetRequiredSchedulerModules(scheduler) + if modNotFound != nil { + klog.Error(modNotFound) + } + mods = append(mods, schedulerMod) wantModules.Insert(mods...) modules := wantModules.Difference(loadModules).UnsortedList() diff --git a/pkg/proxy/ipvs/proxier_test.go b/pkg/proxy/ipvs/proxier_test.go index 77b5e75317b..32dcb6a17c0 100644 --- a/pkg/proxy/ipvs/proxier_test.go +++ b/pkg/proxy/ipvs/proxier_test.go @@ -348,6 +348,14 @@ func TestCanUseIPVSProxier(t *testing.T) { ipsetVersion: MinIPSetCheckVersion, ok: true, }, + // case 10, non-existent scheduler, fallback to rr + { + mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_dh"}, + scheduler: "foobar", + kernelVersion: "4.19", + ipsetVersion: MinIPSetCheckVersion, + ok: true, + }, } for i := range testCases { diff --git a/pkg/util/ipvs/ipvs.go b/pkg/util/ipvs/ipvs.go index b331a052848..0cc63e86d7c 100644 --- a/pkg/util/ipvs/ipvs.go +++ b/pkg/util/ipvs/ipvs.go @@ -17,6 +17,7 @@ limitations under the License. package ipvs import ( + "fmt" "net" "strconv" "strings" @@ -149,21 +150,24 @@ func IsRsGracefulTerminationNeeded(proto string) bool { } // GetRequiredSchedulerModules returns the required ipvs scheduler module for configured scheduler -func GetRequiredSchedulerModules(scheduler string) string { +func GetRequiredSchedulerModules(scheduler string) (string, error) { switch s := scheduler; s { case "rr": - return KernelModuleIPVSRR + return KernelModuleIPVSRR, nil case "lc": - return KernelModuleIPVSLC + return KernelModuleIPVSLC, nil case "nq": - return KernelModuleIPVSNQ + return KernelModuleIPVSNQ, nil case "dh": - return KernelModuleIPVSDH + return KernelModuleIPVSDH, nil case "sh": - return KernelModuleIPVSSH + return KernelModuleIPVSSH, nil case "sed": - return KernelModuleIPVSSED + return KernelModuleIPVSSED, nil + case "": + return KernelModuleIPVSRR, nil default: - return KernelModuleIPVSRR + notFound := fmt.Errorf("ip_vs_%s is not a supported IPVS scheduler algorithm, falling back to round-robin", scheduler) + return KernelModuleIPVSRR, notFound } } diff --git a/pkg/util/ipvs/ipvs_test.go b/pkg/util/ipvs/ipvs_test.go index 408966818f3..f6119cef7a8 100644 --- a/pkg/util/ipvs/ipvs_test.go +++ b/pkg/util/ipvs/ipvs_test.go @@ -17,6 +17,7 @@ limitations under the License. package ipvs import ( + "fmt" "net" "reflect" "sort" @@ -413,3 +414,51 @@ func TestGetRequiredIPVSModules(t *testing.T) { }) } } + +func TestGetRequiredSchedulerModules(t *testing.T) { + Tests := []struct { + name string + scheduler string + want string + expectedErrs error + }{ + { + name: "scheduler explicitly set to rr", + scheduler: "rr", + want: "ip_vs_rr", + expectedErrs: nil, + }, + { + name: "scheduler set to nq", + scheduler: "nq", + want: "ip_vs_nq", + expectedErrs: nil, + }, + { + name: "unset scheduler", + scheduler: "", + want: "ip_vs_rr", + expectedErrs: nil, + }, + { + name: "invalid scheduler algorithm", + scheduler: "foobar", + want: "ip_vs_rr", + expectedErrs: fmt.Errorf("ip_vs_%s is not a supported IPVS scheduler algorithm, falling back to round-robin", "foobar"), + }, + } + + for _, test := range Tests { + t.Run(test.name, func(t *testing.T) { + got, err := GetRequiredSchedulerModules(test.scheduler) + if !reflect.DeepEqual(got, test.want) { + t.Fatalf("GetRequiredSchedulerModules() = testCase %v failed- expected: %s scheduler, but got: %s", test.name, test.want, got) + } + if err != nil { + if err.Error() != test.expectedErrs.Error() { + t.Fatalf("Expected error: %v, got: %v", test.expectedErrs, err.Error()) + } + } + }) + } +}