diff --git a/pkg/proxy/apis/kubeproxyconfig/types.go b/pkg/proxy/apis/kubeproxyconfig/types.go index d8bf19fe5f3..2a971c120d7 100644 --- a/pkg/proxy/apis/kubeproxyconfig/types.go +++ b/pkg/proxy/apis/kubeproxyconfig/types.go @@ -152,17 +152,20 @@ type KubeProxyConfiguration struct { ConfigSyncPeriod metav1.Duration } -// Currently two modes of proxying are available: 'userspace' (older, stable) or 'iptables' -// (newer, faster). If blank, use the best-available proxy (currently iptables, but may -// change in future versions). If the iptables proxy is selected, regardless of how, but -// the system's kernel or iptables versions are insufficient, this always falls back to the -// userspace proxy. +// Currently, four modes of proxying are available total: 'userspace' (older, stable), 'iptables' +// (newer, faster), 'ipvs', and 'kernelspace' (Windows only, newer). +// +// If blank, use the best-available proxy (currently iptables, but may change in +// future versions). If the iptables proxy is selected, regardless of how, but +// the system's kernel or iptables versions are insufficient, this always falls +// back to the userspace proxy. type ProxyMode string const ( - ProxyModeUserspace ProxyMode = "userspace" - ProxyModeIPTables ProxyMode = "iptables" - ProxyModeIPVS ProxyMode = "ipvs" + ProxyModeUserspace ProxyMode = "userspace" + ProxyModeIPTables ProxyMode = "iptables" + ProxyModeIPVS ProxyMode = "ipvs" + ProxyModeKernelspace ProxyMode = "kernelspace" ) // IPVSSchedulerMethod is the algorithm for allocating TCP connections and diff --git a/pkg/proxy/apis/kubeproxyconfig/validation/validation.go b/pkg/proxy/apis/kubeproxyconfig/validation/validation.go index 55bbe7930d5..376d281c9d8 100644 --- a/pkg/proxy/apis/kubeproxyconfig/validation/validation.go +++ b/pkg/proxy/apis/kubeproxyconfig/validation/validation.go @@ -19,6 +19,7 @@ package validation import ( "fmt" "net" + "runtime" "strconv" "strings" @@ -141,7 +142,16 @@ func validateKubeProxyConntrackConfiguration(config kubeproxyconfig.KubeProxyCon } func validateProxyMode(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { + if runtime.GOOS == "windows" { + return validateProxyModeWindows(mode, fldPath) + } + + return validateProxyModeLinux(mode, fldPath) +} + +func validateProxyModeLinux(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} + switch mode { case kubeproxyconfig.ProxyModeUserspace: case kubeproxyconfig.ProxyModeIPTables: @@ -149,7 +159,21 @@ func validateProxyMode(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) fiel case "": default: modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeIPTables), string(kubeproxyconfig.ProxyModeIPVS)} - errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy (currently iptables)", strings.Join(modes, ",")) + errMsg := fmt.Sprintf("must be %s or blank (blank means the best-available proxy [currently iptables])", strings.Join(modes, ",")) + allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)) + } + return allErrs +} + +func validateProxyModeWindows(mode kubeproxyconfig.ProxyMode, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + switch mode { + case kubeproxyconfig.ProxyModeUserspace: + case kubeproxyconfig.ProxyModeKernelspace: + default: + modes := []string{string(kubeproxyconfig.ProxyModeUserspace), string(kubeproxyconfig.ProxyModeKernelspace)} + errMsg := fmt.Sprintf("must be %s or blank (blank means the most-available proxy [currently userspace])", strings.Join(modes, ",")) allErrs = append(allErrs, field.Invalid(fldPath.Child("ProxyMode"), string(mode), errMsg)) } return allErrs diff --git a/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go b/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go index f316a304462..2736e53af66 100644 --- a/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go +++ b/pkg/proxy/apis/kubeproxyconfig/validation/validation_test.go @@ -18,6 +18,7 @@ package validation import ( "fmt" + "runtime" "strings" "testing" "time" @@ -488,11 +489,15 @@ func TestValidateProxyMode(t *testing.T) { newPath := field.NewPath("KubeProxyConfiguration") successCases := []kubeproxyconfig.ProxyMode{ kubeproxyconfig.ProxyModeUserspace, - kubeproxyconfig.ProxyModeIPTables, - kubeproxyconfig.ProxyModeIPVS, kubeproxyconfig.ProxyMode(""), } + if runtime.GOOS == "windows" { + successCases = append(successCases, kubeproxyconfig.ProxyModeKernelspace) + } else { + successCases = append(successCases, kubeproxyconfig.ProxyModeIPTables, kubeproxyconfig.ProxyModeIPVS) + } + for _, successCase := range successCases { if errs := validateProxyMode(successCase, newPath.Child("ProxyMode")); len(errs) != 0 { t.Errorf("expected success: %v", errs) @@ -505,13 +510,13 @@ func TestValidateProxyMode(t *testing.T) { }{ { mode: kubeproxyconfig.ProxyMode("non-existing"), - msg: "or blank (blank means the best-available proxy (currently iptables)", + msg: "or blank (blank means the", }, } for _, errorCase := range errorCases { if errs := validateProxyMode(errorCase.mode, newPath.Child("ProxyMode")); len(errs) == 0 { - t.Errorf("expected failure for %s", errorCase.msg) + t.Errorf("expected failure %s for %v", errorCase.msg, errorCase.mode) } else if !strings.Contains(errs[0].Error(), errorCase.msg) { t.Errorf("unexpected error: %v, expected: %s", errs[0], errorCase.msg) }