From b69b34bec64075d8668eb44013ad3dfe174b9413 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 6 Apr 2023 17:44:05 -0400 Subject: [PATCH 1/2] Move a kube-proxy unit test to the correct file --- cmd/kube-proxy/app/server_others_test.go | 135 --------------------- cmd/kube-proxy/app/server_test.go | 142 ++++++++++++++++++++++- 2 files changed, 139 insertions(+), 138 deletions(-) diff --git a/cmd/kube-proxy/app/server_others_test.go b/cmd/kube-proxy/app/server_others_test.go index c087621a498..5ee22b1de4b 100644 --- a/cmd/kube-proxy/app/server_others_test.go +++ b/cmd/kube-proxy/app/server_others_test.go @@ -21,7 +21,6 @@ package app import ( "fmt" - "net" "os" "path/filepath" "reflect" @@ -107,111 +106,6 @@ func Test_platformApplyDefaults(t *testing.T) { } } -func Test_detectNodeIP(t *testing.T) { - cases := []struct { - name string - nodeInfo *v1.Node - hostname string - bindAddress string - expectedIP net.IP - }{ - { - name: "Bind address IPv4 unicast address and no Node object", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "10.0.0.1", - expectedIP: netutils.ParseIPSloppy("10.0.0.1"), - }, - { - name: "Bind address IPv6 unicast address and no Node object", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "fd00:4321::2", - expectedIP: netutils.ParseIPSloppy("fd00:4321::2"), - }, - { - name: "No Valid IP found", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "", - expectedIP: netutils.ParseIPSloppy("127.0.0.1"), - }, - // Disabled because the GetNodeIP method has a backoff retry mechanism - // and the test takes more than 30 seconds - // ok k8s.io/kubernetes/cmd/kube-proxy/app 34.136s - // { - // name: "No Valid IP found and unspecified bind address", - // nodeInfo: makeNodeWithAddresses("", "", ""), - // hostname: "fakeHost", - // bindAddress: "0.0.0.0", - // expectedIP: net.IP{127,0,0,1), - // }, - { - name: "Bind address 0.0.0.0 and node with IPv4 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("192.168.1.1"), - }, - { - name: "Bind address :: and node with IPv4 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("192.168.1.1"), - }, - { - name: "Bind address 0.0.0.0 and node with IPv6 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), - }, - { - name: "Bind address :: and node with IPv6 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), - }, - { - name: "Bind address 0.0.0.0 and node with only IPv4 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("90.90.90.90"), - }, - { - name: "Bind address :: and node with only IPv4 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("90.90.90.90"), - }, - { - name: "Bind address 0.0.0.0 and node with only IPv6 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("2001:db8::2"), - }, - { - name: "Bind address :: and node with only IPv6 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("2001:db8::2"), - }, - } - for _, c := range cases { - client := clientsetfake.NewSimpleClientset(c.nodeInfo) - ip := detectNodeIP(client, c.hostname, c.bindAddress) - if !ip.Equal(c.expectedIP) { - t.Errorf("Case[%s] Expected IP %q got %q", c.name, c.expectedIP, ip) - } - } -} - func Test_getLocalDetector(t *testing.T) { cases := []struct { mode proxyconfigapi.LocalMode @@ -502,35 +396,6 @@ func Test_getDualStackLocalDetectorTuple(t *testing.T) { } } -func makeNodeWithAddresses(name, internal, external string) *v1.Node { - if name == "" { - return &v1.Node{} - } - - node := &v1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Status: v1.NodeStatus{ - Addresses: []v1.NodeAddress{}, - }, - } - - if internal != "" { - node.Status.Addresses = append(node.Status.Addresses, - v1.NodeAddress{Type: v1.NodeInternalIP, Address: internal}, - ) - } - - if external != "" { - node.Status.Addresses = append(node.Status.Addresses, - v1.NodeAddress{Type: v1.NodeExternalIP, Address: external}, - ) - } - - return node -} - func makeNodeWithPodCIDRs(cidrs ...string) *v1.Node { if len(cidrs) == 0 { return &v1.Node{} diff --git a/cmd/kube-proxy/app/server_test.go b/cmd/kube-proxy/app/server_test.go index 96b1e59872d..7ba0ee5fc15 100644 --- a/cmd/kube-proxy/app/server_test.go +++ b/cmd/kube-proxy/app/server_test.go @@ -19,19 +19,21 @@ package app import ( "errors" "fmt" + "net" "reflect" "testing" "time" "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - "k8s.io/utils/pointer" - + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientsetfake "k8s.io/client-go/kubernetes/fake" componentbaseconfig "k8s.io/component-base/config" kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" + netutils "k8s.io/utils/net" + "k8s.io/utils/pointer" ) // TestLoadConfig tests proper operation of loadConfig() @@ -464,3 +466,137 @@ func TestAddressFromDeprecatedFlags(t *testing.T) { } } + +func makeNodeWithAddresses(name, internal, external string) *v1.Node { + if name == "" { + return &v1.Node{} + } + + node := &v1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Status: v1.NodeStatus{ + Addresses: []v1.NodeAddress{}, + }, + } + + if internal != "" { + node.Status.Addresses = append(node.Status.Addresses, + v1.NodeAddress{Type: v1.NodeInternalIP, Address: internal}, + ) + } + + if external != "" { + node.Status.Addresses = append(node.Status.Addresses, + v1.NodeAddress{Type: v1.NodeExternalIP, Address: external}, + ) + } + + return node +} + +func Test_detectNodeIP(t *testing.T) { + cases := []struct { + name string + nodeInfo *v1.Node + hostname string + bindAddress string + expectedIP net.IP + }{ + { + name: "Bind address IPv4 unicast address and no Node object", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "10.0.0.1", + expectedIP: netutils.ParseIPSloppy("10.0.0.1"), + }, + { + name: "Bind address IPv6 unicast address and no Node object", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "fd00:4321::2", + expectedIP: netutils.ParseIPSloppy("fd00:4321::2"), + }, + { + name: "No Valid IP found", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "", + expectedIP: netutils.ParseIPSloppy("127.0.0.1"), + }, + // Disabled because the GetNodeIP method has a backoff retry mechanism + // and the test takes more than 30 seconds + // ok k8s.io/kubernetes/cmd/kube-proxy/app 34.136s + // { + // name: "No Valid IP found and unspecified bind address", + // nodeInfo: makeNodeWithAddresses("", "", ""), + // hostname: "fakeHost", + // bindAddress: "0.0.0.0", + // expectedIP: net.IP{127,0,0,1), + // }, + { + name: "Bind address 0.0.0.0 and node with IPv4 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedIP: netutils.ParseIPSloppy("192.168.1.1"), + }, + { + name: "Bind address :: and node with IPv4 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "::", + expectedIP: netutils.ParseIPSloppy("192.168.1.1"), + }, + { + name: "Bind address 0.0.0.0 and node with IPv6 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), + }, + { + name: "Bind address :: and node with IPv6 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "::", + expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), + }, + { + name: "Bind address 0.0.0.0 and node with only IPv4 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedIP: netutils.ParseIPSloppy("90.90.90.90"), + }, + { + name: "Bind address :: and node with only IPv4 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "::", + expectedIP: netutils.ParseIPSloppy("90.90.90.90"), + }, + { + name: "Bind address 0.0.0.0 and node with only IPv6 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedIP: netutils.ParseIPSloppy("2001:db8::2"), + }, + { + name: "Bind address :: and node with only IPv6 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "::", + expectedIP: netutils.ParseIPSloppy("2001:db8::2"), + }, + } + for _, c := range cases { + client := clientsetfake.NewSimpleClientset(c.nodeInfo) + ip := detectNodeIP(client, c.hostname, c.bindAddress) + if !ip.Equal(c.expectedIP) { + t.Errorf("Case[%s] Expected IP %q got %q", c.name, c.expectedIP, ip) + } + } +} From 4962e6eacb95e052b1ee85379308ee07ac14ac44 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 13 Apr 2023 11:49:13 -0400 Subject: [PATCH 2/2] Squash detectNodeIP and nodeIPTuple together --- cmd/kube-proxy/app/server.go | 62 ++++---- cmd/kube-proxy/app/server_others.go | 22 ++- cmd/kube-proxy/app/server_others_test.go | 6 +- cmd/kube-proxy/app/server_test.go | 178 +++++++++++++---------- cmd/kube-proxy/app/server_windows.go | 4 +- pkg/proxy/iptables/proxier.go | 6 +- pkg/proxy/ipvs/proxier.go | 6 +- pkg/proxy/winkernel/proxier.go | 12 +- 8 files changed, 168 insertions(+), 128 deletions(-) diff --git a/cmd/kube-proxy/app/server.go b/cmd/kube-proxy/app/server.go index 8c71657d30c..30ffb436627 100644 --- a/cmd/kube-proxy/app/server.go +++ b/cmd/kube-proxy/app/server.go @@ -514,13 +514,14 @@ with the apiserver API to configure the proxy.`, type ProxyServer struct { Config *kubeproxyconfig.KubeProxyConfiguration - Client clientset.Interface - Broadcaster events.EventBroadcaster - Recorder events.EventRecorder - NodeRef *v1.ObjectReference - HealthzServer healthcheck.ProxierHealthUpdater - Hostname string - NodeIP net.IP + Client clientset.Interface + Broadcaster events.EventBroadcaster + Recorder events.EventRecorder + NodeRef *v1.ObjectReference + HealthzServer healthcheck.ProxierHealthUpdater + Hostname string + PrimaryIPFamily v1.IPFamily + NodeIPs map[v1.IPFamily]net.IP podCIDRs []string // only used for LocalModeNodeCIDR @@ -551,8 +552,7 @@ func newProxyServer(config *kubeproxyconfig.KubeProxyConfiguration, master strin return nil, err } - s.NodeIP = detectNodeIP(s.Client, s.Hostname, config.BindAddress) - klog.InfoS("Detected node IP", "address", s.NodeIP.String()) + s.PrimaryIPFamily, s.NodeIPs = detectNodeIPs(s.Client, s.Hostname, config.BindAddress) s.Broadcaster = events.NewBroadcaster(&events.EventSinkImpl{Interface: s.Client.EventsV1()}) s.Recorder = s.Broadcaster.NewRecorder(proxyconfigscheme.Scheme, "kube-proxy") @@ -778,12 +778,23 @@ func (s *ProxyServer) birthCry() { s.Recorder.Eventf(s.NodeRef, nil, api.EventTypeNormal, "Starting", "StartKubeProxy", "") } -// detectNodeIP returns the nodeIP used by the proxier +// detectNodeIPs returns the proxier's "node IP" or IPs, and the IP family to use if the +// node turns out to be incapable of dual-stack. (Note that kube-proxy normally runs as +// dual-stack if the backend is capable of supporting both IP families, regardless of +// whether the node is *actually* configured as dual-stack or not.) + +// (Note that on Linux, the node IPs are used only to determine whether a given +// LoadBalancerSourceRanges value matches the node or not. In particular, they are *not* +// used for NodePort handling.) +// // The order of precedence is: -// 1. config.bindAddress if bindAddress is not 0.0.0.0 or :: -// 2. the primary IP from the Node object, if set -// 3. if no IP is found it defaults to 127.0.0.1 and IPv4 -func detectNodeIP(client clientset.Interface, hostname, bindAddress string) net.IP { +// 1. if bindAddress is not 0.0.0.0 or ::, then it is used as the primary IP. +// 2. if the Node object can be fetched, then its primary IP is used as the primary IP +// (and its secondary IP, if any, is just ignored). +// 3. otherwise the primary node IP is 127.0.0.1. +// +// In all cases, the secondary IP is the zero IP of the other IP family. +func detectNodeIPs(client clientset.Interface, hostname, bindAddress string) (v1.IPFamily, map[v1.IPFamily]net.IP) { nodeIP := netutils.ParseIPSloppy(bindAddress) if nodeIP.IsUnspecified() { nodeIP = utilnode.GetNodeIP(client, hostname) @@ -792,21 +803,16 @@ func detectNodeIP(client clientset.Interface, hostname, bindAddress string) net. klog.InfoS("Can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag") nodeIP = netutils.ParseIPSloppy("127.0.0.1") } - return nodeIP -} -// nodeIPTuple takes an addresses and return a tuple (ipv4,ipv6) -// The returned tuple is guaranteed to have the order (ipv4,ipv6). The address NOT of the passed address -// will have "any" address (0.0.0.0 or ::) inserted. -func nodeIPTuple(bindAddress string) [2]net.IP { - nodes := [2]net.IP{net.IPv4zero, net.IPv6zero} - - adr := netutils.ParseIPSloppy(bindAddress) - if netutils.IsIPv6(adr) { - nodes[1] = adr + if netutils.IsIPv4(nodeIP) { + return v1.IPv4Protocol, map[v1.IPFamily]net.IP{ + v1.IPv4Protocol: nodeIP, + v1.IPv6Protocol: net.IPv6zero, + } } else { - nodes[0] = adr + return v1.IPv6Protocol, map[v1.IPFamily]net.IP{ + v1.IPv4Protocol: net.IPv4zero, + v1.IPv6Protocol: nodeIP, + } } - - return nodes } diff --git a/cmd/kube-proxy/app/server_others.go b/cmd/kube-proxy/app/server_others.go index ac403b2e157..a14f386833e 100644 --- a/cmd/kube-proxy/app/server_others.go +++ b/cmd/kube-proxy/app/server_others.go @@ -92,10 +92,8 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio klog.InfoS("NodeInfo", "podCIDR", nodeInfo.Spec.PodCIDR, "podCIDRs", nodeInfo.Spec.PodCIDRs) } - primaryFamily := v1.IPv4Protocol primaryProtocol := utiliptables.ProtocolIPv4 - if netutils.IsIPv6(s.NodeIP) { - primaryFamily = v1.IPv6Protocol + if s.PrimaryIPFamily == v1.IPv6Protocol { primaryProtocol = utiliptables.ProtocolIPv6 } execer := exec.New() @@ -124,11 +122,11 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio // Validate NodePortAddresses is single-stack npaByFamily := proxyutil.MapCIDRsByIPFamily(config.NodePortAddresses) - secondaryFamily := proxyutil.OtherIPFamily(primaryFamily) + secondaryFamily := proxyutil.OtherIPFamily(s.PrimaryIPFamily) badAddrs := npaByFamily[secondaryFamily] if len(badAddrs) > 0 { klog.InfoS("Ignoring --nodeport-addresses of the wrong family", "ipFamily", secondaryFamily, "addresses", badAddrs) - nodePortAddresses = npaByFamily[primaryFamily] + nodePortAddresses = npaByFamily[s.PrimaryIPFamily] } } @@ -157,7 +155,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio int(*config.IPTables.MasqueradeBit), localDetectors, s.Hostname, - nodeIPTuple(config.BindAddress), + s.NodeIPs, s.Recorder, s.HealthzServer, nodePortAddresses, @@ -172,7 +170,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio // TODO this has side effects that should only happen when Run() is invoked. proxier, err = iptables.NewProxier( - primaryFamily, + s.PrimaryIPFamily, iptInterface, utilsysctl.New(), execer, @@ -183,7 +181,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio int(*config.IPTables.MasqueradeBit), localDetector, s.Hostname, - s.NodeIP, + s.NodeIPs[s.PrimaryIPFamily], s.Recorder, s.HealthzServer, nodePortAddresses, @@ -205,8 +203,6 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio if dualStack { klog.InfoS("Creating dualStackProxier for ipvs") - nodeIPs := nodeIPTuple(config.BindAddress) - // Always ordered to match []ipt var localDetectors [2]proxyutiliptables.LocalTrafficDetector localDetectors, err = getDualStackLocalDetectorTuple(config.DetectLocalMode, config, ipt, nodeInfo) @@ -231,7 +227,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio int(*config.IPTables.MasqueradeBit), localDetectors, s.Hostname, - nodeIPs, + s.NodeIPs, s.Recorder, s.HealthzServer, config.IPVS.Scheduler, @@ -246,7 +242,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio } proxier, err = ipvs.NewProxier( - primaryFamily, + s.PrimaryIPFamily, iptInterface, ipvsInterface, ipsetInterface, @@ -263,7 +259,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio int(*config.IPTables.MasqueradeBit), localDetector, s.Hostname, - s.NodeIP, + s.NodeIPs[s.PrimaryIPFamily], s.Recorder, s.HealthzServer, config.IPVS.Scheduler, diff --git a/cmd/kube-proxy/app/server_others_test.go b/cmd/kube-proxy/app/server_others_test.go index 5ee22b1de4b..06d1a435123 100644 --- a/cmd/kube-proxy/app/server_others_test.go +++ b/cmd/kube-proxy/app/server_others_test.go @@ -21,6 +21,7 @@ package app import ( "fmt" + "net" "os" "path/filepath" "reflect" @@ -677,7 +678,10 @@ func TestProxyServer_createProxier(t *testing.T) { Config: tt.config, Client: client, Hostname: "nodename", - NodeIP: netutils.ParseIPSloppy("127.0.0.1"), + NodeIPs: map[v1.IPFamily]net.IP{ + v1.IPv4Protocol: netutils.ParseIPSloppy("127.0.0.1"), + v1.IPv6Protocol: net.IPv6zero, + }, } _, err := s.createProxier(tt.config) // TODO: mock the exec.Interface to not fail probing iptables diff --git a/cmd/kube-proxy/app/server_test.go b/cmd/kube-proxy/app/server_test.go index 7ba0ee5fc15..8d5f3241510 100644 --- a/cmd/kube-proxy/app/server_test.go +++ b/cmd/kube-proxy/app/server_test.go @@ -19,7 +19,6 @@ package app import ( "errors" "fmt" - "net" "reflect" "testing" "time" @@ -32,7 +31,6 @@ import ( clientsetfake "k8s.io/client-go/kubernetes/fake" componentbaseconfig "k8s.io/component-base/config" kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config" - netutils "k8s.io/utils/net" "k8s.io/utils/pointer" ) @@ -496,107 +494,141 @@ func makeNodeWithAddresses(name, internal, external string) *v1.Node { return node } -func Test_detectNodeIP(t *testing.T) { +func Test_detectNodeIPs(t *testing.T) { cases := []struct { - name string - nodeInfo *v1.Node - hostname string - bindAddress string - expectedIP net.IP + name string + nodeInfo *v1.Node + hostname string + bindAddress string + expectedFamily v1.IPFamily + expectedIPv4 string + expectedIPv6 string }{ { - name: "Bind address IPv4 unicast address and no Node object", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "10.0.0.1", - expectedIP: netutils.ParseIPSloppy("10.0.0.1"), + name: "Bind address IPv4 unicast address and no Node object", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "10.0.0.1", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "10.0.0.1", + expectedIPv6: "::", }, { - name: "Bind address IPv6 unicast address and no Node object", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "fd00:4321::2", - expectedIP: netutils.ParseIPSloppy("fd00:4321::2"), + name: "Bind address IPv6 unicast address and no Node object", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "fd00:4321::2", + expectedFamily: v1.IPv6Protocol, + expectedIPv4: "0.0.0.0", + expectedIPv6: "fd00:4321::2", }, { - name: "No Valid IP found", - nodeInfo: makeNodeWithAddresses("", "", ""), - hostname: "fakeHost", - bindAddress: "", - expectedIP: netutils.ParseIPSloppy("127.0.0.1"), + name: "No Valid IP found", + nodeInfo: makeNodeWithAddresses("", "", ""), + hostname: "fakeHost", + bindAddress: "", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "127.0.0.1", + expectedIPv6: "::", }, // Disabled because the GetNodeIP method has a backoff retry mechanism // and the test takes more than 30 seconds // ok k8s.io/kubernetes/cmd/kube-proxy/app 34.136s // { - // name: "No Valid IP found and unspecified bind address", - // nodeInfo: makeNodeWithAddresses("", "", ""), - // hostname: "fakeHost", - // bindAddress: "0.0.0.0", - // expectedIP: net.IP{127,0,0,1), + // name: "No Valid IP found and unspecified bind address", + // nodeInfo: makeNodeWithAddresses("", "", ""), + // hostname: "fakeHost", + // bindAddress: "0.0.0.0", + // expectedFamily: v1.IPv4Protocol, + // expectedIPv4: "127.0.0.1", + // expectedIPv6: "::", // }, { - name: "Bind address 0.0.0.0 and node with IPv4 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("192.168.1.1"), + name: "Bind address 0.0.0.0 and node with IPv4 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "192.168.1.1", + expectedIPv6: "::", }, { - name: "Bind address :: and node with IPv4 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("192.168.1.1"), + name: "Bind address :: and node with IPv4 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "::", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "192.168.1.1", + expectedIPv6: "::", }, { - name: "Bind address 0.0.0.0 and node with IPv6 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), + name: "Bind address 0.0.0.0 and node with IPv6 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedFamily: v1.IPv6Protocol, + expectedIPv4: "0.0.0.0", + expectedIPv6: "fd00:1234::1", }, { - name: "Bind address :: and node with IPv6 InternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("fd00:1234::1"), + name: "Bind address :: and node with IPv6 InternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "::", + expectedFamily: v1.IPv6Protocol, + expectedIPv4: "0.0.0.0", + expectedIPv6: "fd00:1234::1", }, { - name: "Bind address 0.0.0.0 and node with only IPv4 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("90.90.90.90"), + name: "Bind address 0.0.0.0 and node with only IPv4 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "90.90.90.90", + expectedIPv6: "::", }, { - name: "Bind address :: and node with only IPv4 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("90.90.90.90"), + name: "Bind address :: and node with only IPv4 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"), + hostname: "fakeHost", + bindAddress: "::", + expectedFamily: v1.IPv4Protocol, + expectedIPv4: "90.90.90.90", + expectedIPv6: "::", }, { - name: "Bind address 0.0.0.0 and node with only IPv6 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "0.0.0.0", - expectedIP: netutils.ParseIPSloppy("2001:db8::2"), + name: "Bind address 0.0.0.0 and node with only IPv6 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "0.0.0.0", + expectedFamily: v1.IPv6Protocol, + expectedIPv4: "0.0.0.0", + expectedIPv6: "2001:db8::2", }, { - name: "Bind address :: and node with only IPv6 ExternalIP set", - nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), - hostname: "fakeHost", - bindAddress: "::", - expectedIP: netutils.ParseIPSloppy("2001:db8::2"), + name: "Bind address :: and node with only IPv6 ExternalIP set", + nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"), + hostname: "fakeHost", + bindAddress: "::", + expectedFamily: v1.IPv6Protocol, + expectedIPv4: "0.0.0.0", + expectedIPv6: "2001:db8::2", }, } for _, c := range cases { - client := clientsetfake.NewSimpleClientset(c.nodeInfo) - ip := detectNodeIP(client, c.hostname, c.bindAddress) - if !ip.Equal(c.expectedIP) { - t.Errorf("Case[%s] Expected IP %q got %q", c.name, c.expectedIP, ip) - } + t.Run(c.name, func(t *testing.T) { + client := clientsetfake.NewSimpleClientset(c.nodeInfo) + primaryFamily, ips := detectNodeIPs(client, c.hostname, c.bindAddress) + if primaryFamily != c.expectedFamily { + t.Errorf("Expected family %q got %q", c.expectedFamily, primaryFamily) + } + if ips[v1.IPv4Protocol].String() != c.expectedIPv4 { + t.Errorf("Expected IPv4 %q got %q", c.expectedIPv4, ips[v1.IPv4Protocol].String()) + } + if ips[v1.IPv6Protocol].String() != c.expectedIPv6 { + t.Errorf("Expected IPv6 %q got %q", c.expectedIPv6, ips[v1.IPv6Protocol].String()) + } + }) } } diff --git a/cmd/kube-proxy/app/server_windows.go b/cmd/kube-proxy/app/server_windows.go index 3cb813bfd28..4c3ef13340f 100644 --- a/cmd/kube-proxy/app/server_windows.go +++ b/cmd/kube-proxy/app/server_windows.go @@ -67,7 +67,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio config.IPTables.MinSyncPeriod.Duration, config.ClusterCIDR, s.Hostname, - nodeIPTuple(config.BindAddress), + s.NodeIPs, s.Recorder, s.HealthzServer, config.Winkernel, @@ -79,7 +79,7 @@ func (s *ProxyServer) createProxier(config *proxyconfigapi.KubeProxyConfiguratio config.IPTables.MinSyncPeriod.Duration, config.ClusterCIDR, s.Hostname, - s.NodeIP, + s.NodeIPs[s.PrimaryIPFamily], s.Recorder, s.HealthzServer, config.Winkernel, diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 902da9bfa86..3093dac23e2 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -328,7 +328,7 @@ func NewDualStackProxier( masqueradeBit int, localDetectors [2]proxyutiliptables.LocalTrafficDetector, hostname string, - nodeIP [2]net.IP, + nodeIPs map[v1.IPFamily]net.IP, recorder events.EventRecorder, healthzServer healthcheck.ProxierHealthUpdater, nodePortAddresses []string, @@ -336,14 +336,14 @@ func NewDualStackProxier( // Create an ipv4 instance of the single-stack proxier ipv4Proxier, err := NewProxier(v1.IPv4Protocol, ipt[0], sysctl, exec, syncPeriod, minSyncPeriod, masqueradeAll, localhostNodePorts, masqueradeBit, localDetectors[0], hostname, - nodeIP[0], recorder, healthzServer, nodePortAddresses) + nodeIPs[v1.IPv4Protocol], recorder, healthzServer, nodePortAddresses) if err != nil { return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err) } ipv6Proxier, err := NewProxier(v1.IPv6Protocol, ipt[1], sysctl, exec, syncPeriod, minSyncPeriod, masqueradeAll, false, masqueradeBit, localDetectors[1], hostname, - nodeIP[1], recorder, healthzServer, nodePortAddresses) + nodeIPs[v1.IPv6Protocol], recorder, healthzServer, nodePortAddresses) if err != nil { return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err) } diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index aa672ed690d..81e940be6e5 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -480,7 +480,7 @@ func NewDualStackProxier( masqueradeBit int, localDetectors [2]proxyutiliptables.LocalTrafficDetector, hostname string, - nodeIP [2]net.IP, + nodeIPs map[v1.IPFamily]net.IP, recorder events.EventRecorder, healthzServer healthcheck.ProxierHealthUpdater, scheduler string, @@ -494,7 +494,7 @@ func NewDualStackProxier( ipv4Proxier, err := NewProxier(v1.IPv4Protocol, ipt[0], ipvs, safeIpset, sysctl, exec, syncPeriod, minSyncPeriod, filterCIDRs(false, excludeCIDRs), strictARP, tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit, - localDetectors[0], hostname, nodeIP[0], + localDetectors[0], hostname, nodeIPs[v1.IPv4Protocol], recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler) if err != nil { return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err) @@ -503,7 +503,7 @@ func NewDualStackProxier( ipv6Proxier, err := NewProxier(v1.IPv6Protocol, ipt[1], ipvs, safeIpset, sysctl, exec, syncPeriod, minSyncPeriod, filterCIDRs(true, excludeCIDRs), strictARP, tcpTimeout, tcpFinTimeout, udpTimeout, masqueradeAll, masqueradeBit, - localDetectors[1], hostname, nodeIP[1], + localDetectors[1], hostname, nodeIPs[v1.IPv6Protocol], recorder, healthzServer, scheduler, nodePortAddresses, kernelHandler) if err != nil { return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err) diff --git a/pkg/proxy/winkernel/proxier.go b/pkg/proxy/winkernel/proxier.go index d344fc83284..75011f94566 100644 --- a/pkg/proxy/winkernel/proxier.go +++ b/pkg/proxy/winkernel/proxier.go @@ -809,7 +809,7 @@ func NewDualStackProxier( minSyncPeriod time.Duration, clusterCIDR string, hostname string, - nodeIP [2]net.IP, + nodeIPs map[v1.IPFamily]net.IP, recorder events.EventRecorder, healthzServer healthcheck.ProxierHealthUpdater, config config.KubeProxyWinkernelConfiguration, @@ -818,16 +818,18 @@ func NewDualStackProxier( // Create an ipv4 instance of the single-stack proxier ipv4Proxier, err := NewProxier(syncPeriod, minSyncPeriod, - clusterCIDR, hostname, nodeIP[0], recorder, healthzServer, config, healthzPort) + clusterCIDR, hostname, nodeIPs[v1.IPv4Protocol], recorder, healthzServer, + config, healthzPort) if err != nil { - return nil, fmt.Errorf("unable to create ipv4 proxier: %v, hostname: %s, clusterCIDR : %s, nodeIP:%v", err, hostname, clusterCIDR, nodeIP[0]) + return nil, fmt.Errorf("unable to create ipv4 proxier: %v, hostname: %s, clusterCIDR : %s, nodeIP:%v", err, hostname, clusterCIDR, nodeIPs[v1.IPv4Protocol]) } ipv6Proxier, err := NewProxier(syncPeriod, minSyncPeriod, - clusterCIDR, hostname, nodeIP[1], recorder, healthzServer, config, healthzPort) + clusterCIDR, hostname, nodeIPs[v1.IPv6Protocol], recorder, healthzServer, + config, healthzPort) if err != nil { - return nil, fmt.Errorf("unable to create ipv6 proxier: %v, hostname: %s, clusterCIDR : %s, nodeIP:%v", err, hostname, clusterCIDR, nodeIP[1]) + return nil, fmt.Errorf("unable to create ipv6 proxier: %v, hostname: %s, clusterCIDR : %s, nodeIP:%v", err, hostname, clusterCIDR, nodeIPs[v1.IPv6Protocol]) } // Return a meta-proxier that dispatch calls between the two