Skip to content

Commit

Permalink
Figure out single-stack/dual-stack support before creating the proxier
Browse files Browse the repository at this point in the history
Rather than having this as part of createProxier(), explicitly figure
out what IP families the proxier can support beforehand, and bail out
if this conflicts with the detected IP family.
  • Loading branch information
danwinship committed Jun 30, 2023
1 parent 8abfa89 commit 1f2bf32
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 28 deletions.
13 changes: 12 additions & 1 deletion cmd/kube-proxy/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
38 changes: 26 additions & 12 deletions cmd/kube-proxy/app/server_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
37 changes: 22 additions & 15 deletions cmd/kube-proxy/app/server_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
Expand Down Expand Up @@ -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")
Expand Down

0 comments on commit 1f2bf32

Please sign in to comment.