diff --git a/cmd/kube-proxy/app/server.go b/cmd/kube-proxy/app/server.go index 6b12ab4e6cb6c..99992b2da2e4e 100644 --- a/cmd/kube-proxy/app/server.go +++ b/cmd/kube-proxy/app/server.go @@ -572,7 +572,18 @@ func newProxyServer(config *kubeproxyconfig.KubeProxyConfiguration, master strin return nil, err } - s.Proxier, err = s.createProxier(config) + ipv4Supported, ipv6Supported, dualStackSupported, err := s.platformCheckSupported() + if err != nil { + return nil, err + } else if (s.PrimaryIPFamily == v1.IPv4Protocol && !ipv4Supported) || (s.PrimaryIPFamily == v1.IPv6Protocol && !ipv6Supported) { + return nil, fmt.Errorf("no support for primary IP family %q", s.PrimaryIPFamily) + } else if dualStackSupported { + klog.InfoS("kube-proxy running in dual-stack mode", "primary ipFamily", s.PrimaryIPFamily) + } else { + klog.InfoS("kube-proxy running in single-stack mode", "ipFamily", s.PrimaryIPFamily) + } + + s.Proxier, err = s.createProxier(config, dualStackSupported) if err != nil { return nil, err } diff --git a/cmd/kube-proxy/app/server_others.go b/cmd/kube-proxy/app/server_others.go index 3ad02d7840f54..4eee907f2d194 100644 --- a/cmd/kube-proxy/app/server_others.go +++ b/cmd/kube-proxy/app/server_others.go @@ -101,8 +101,32 @@ func (s *ProxyServer) platformSetup() error { return nil } +// platformCheckSupported is called immediately before creating the Proxier, to check +// what IP families are supported (and whether the configuration is usable at all). +func (s *ProxyServer) platformCheckSupported() (ipv4Supported, ipv6Supported, dualStackSupported bool, err error) { + execer := exec.New() + ipt := utiliptables.New(execer, utiliptables.ProtocolIPv4) + ipv4Supported = ipt.Present() + ipt = utiliptables.New(execer, utiliptables.ProtocolIPv6) + ipv6Supported = ipt.Present() + + // The Linux proxies can always support dual-stack if they can support both IPv4 + // and IPv6. + dualStackSupported = ipv4Supported && ipv6Supported + + if !ipv4Supported && !ipv6Supported { + err = fmt.Errorf("iptables is not available on this host") + } else if !ipv4Supported { + klog.InfoS("No iptables support for family", "ipFamily", v1.IPv4Protocol) + } else if !ipv6Supported { + klog.InfoS("No iptables support for family", "ipFamily", v1.IPv6Protocol) + } + + return +} + // createProxier creates the proxy.Provider -func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration) (proxy.Provider, error) { +func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStack bool) (proxy.Provider, error) { var proxier proxy.Provider var err error @@ -114,7 +138,6 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio iptInterface := utiliptables.New(execer, primaryProtocol) var ipt [2]utiliptables.Interface - dualStack := true // While we assume that node supports, we do further checks below // Create iptables handlers for both families, one is already created // Always ordered as IPv4, IPv6 @@ -126,12 +149,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio ipt[1] = iptInterface } - if !ipt[0].Present() { - return nil, fmt.Errorf("iptables is not supported for primary IP family %q", primaryProtocol) - } else if !ipt[1].Present() { - klog.InfoS("kube-proxy running in single-stack mode: secondary ipFamily is not supported", "ipFamily", ipt[1].Protocol()) - dualStack = false - + if !dualStack { // Validate NodePortAddresses is single-stack npaByFamily := proxyutil.MapCIDRsByIPFamily(config.NodePortAddresses) secondaryFamily := proxyutil.OtherIPFamily(s.PrimaryIPFamily) @@ -145,8 +163,6 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio klog.InfoS("Using iptables Proxier") if dualStack { - klog.InfoS("kube-proxy running in dual-stack mode", "ipFamily", iptInterface.Protocol()) - klog.InfoS("Creating dualStackProxier for iptables") // Always ordered to match []ipt var localDetectors [2]proxyutiliptables.LocalTrafficDetector localDetectors, err = getDualStackLocalDetectorTuple(config.DetectLocalMode, config, ipt, s.podCIDRs) @@ -212,8 +228,6 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio klog.InfoS("Using ipvs Proxier") if dualStack { - klog.InfoS("Creating dualStackProxier for ipvs") - // Always ordered to match []ipt var localDetectors [2]proxyutiliptables.LocalTrafficDetector localDetectors, err = getDualStackLocalDetectorTuple(config.DetectLocalMode, config, ipt, s.podCIDRs) diff --git a/cmd/kube-proxy/app/server_windows.go b/cmd/kube-proxy/app/server_windows.go index c076abf90dc3e..62adf4a41d1f1 100644 --- a/cmd/kube-proxy/app/server_windows.go +++ b/cmd/kube-proxy/app/server_windows.go @@ -30,7 +30,6 @@ import ( // Enable pprof HTTP handlers. _ "net/http/pprof" - "k8s.io/klog/v2" "k8s.io/kubernetes/pkg/proxy" proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config" "k8s.io/kubernetes/pkg/proxy/winkernel" @@ -52,26 +51,38 @@ func (s *ProxyServer) platformSetup() error { return nil } +// platformCheckSupported is called immediately before creating the Proxier, to check +// what IP families are supported (and whether the configuration is usable at all). +func (s *ProxyServer) platformCheckSupported() (ipv4Supported, ipv6Supported, dualStackSupported bool, err error) { + // Check if Kernel proxier can be used at all + _, err = winkernel.CanUseWinKernelProxier(winkernel.WindowsKernelCompatTester{}) + if err != nil { + return false, false, false, err + } + + // winkernel always supports both single-stack IPv4 and single-stack IPv6, but may + // not support dual-stack. + ipv4Supported = true + ipv6Supported = true + + compatTester := winkernel.DualStackCompatTester{} + dualStackSupported = compatTester.DualStackCompatible(s.Config.Winkernel.NetworkName) + + return +} + // createProxier creates the proxy.Provider -func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration) (proxy.Provider, error) { +func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguration, dualStackMode bool) (proxy.Provider, error) { var healthzPort int if len(config.HealthzBindAddress) > 0 { _, port, _ := net.SplitHostPort(config.HealthzBindAddress) healthzPort, _ = strconv.Atoi(port) } - // Check if Kernel Space can be used. - canUseWinKernelProxy, err := winkernel.CanUseWinKernelProxier(winkernel.WindowsKernelCompatTester{}) - if !canUseWinKernelProxy && err != nil { - return nil, err - } - var proxier proxy.Provider + var err error - dualStackMode := getDualStackMode(config.Winkernel.NetworkName, winkernel.DualStackCompatTester{}) if dualStackMode { - klog.InfoS("Creating dualStackProxier for Windows kernel.") - proxier, err = winkernel.NewDualStackProxier( config.IPTables.SyncPeriod.Duration, config.IPTables.MinSyncPeriod.Duration, @@ -103,10 +114,6 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio return proxier, nil } -func getDualStackMode(networkname string, compatTester winkernel.StackCompatTester) bool { - return compatTester.DualStackCompatible(networkname) -} - // cleanupAndExit cleans up after a previous proxy run func cleanupAndExit() error { return errors.New("--cleanup-and-exit is not implemented on Windows")