Skip to content

Commit f496b9f

Browse files
authored
Merge pull request kubernetes#91725 from aojea/proxyIPv6mode
kube-proxy detect IP family based on nodeIP
2 parents 2bc3210 + 56df70b commit f496b9f

File tree

4 files changed

+183
-48
lines changed

4 files changed

+183
-48
lines changed

cmd/kube-proxy/app/BUILD

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ go_test(
235235
"//pkg/proxy/apis/config:go_default_library",
236236
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
237237
"//staging/src/k8s.io/component-base/config:go_default_library",
238-
"//staging/src/k8s.io/component-base/configz:go_default_library",
239238
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
240239
"//vendor/github.com/stretchr/testify/assert:go_default_library",
241240
"//vendor/k8s.io/utils/pointer:go_default_library",
@@ -246,76 +245,87 @@ go_test(
246245
"//pkg/util/iptables:go_default_library",
247246
"//pkg/util/iptables/testing:go_default_library",
248247
"//staging/src/k8s.io/api/core/v1:go_default_library",
248+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
249249
],
250250
"@io_bazel_rules_go//go/platform:darwin": [
251251
"//pkg/proxy/ipvs:go_default_library",
252252
"//pkg/proxy/util/iptables:go_default_library",
253253
"//pkg/util/iptables:go_default_library",
254254
"//pkg/util/iptables/testing:go_default_library",
255255
"//staging/src/k8s.io/api/core/v1:go_default_library",
256+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
256257
],
257258
"@io_bazel_rules_go//go/platform:dragonfly": [
258259
"//pkg/proxy/ipvs:go_default_library",
259260
"//pkg/proxy/util/iptables:go_default_library",
260261
"//pkg/util/iptables:go_default_library",
261262
"//pkg/util/iptables/testing:go_default_library",
262263
"//staging/src/k8s.io/api/core/v1:go_default_library",
264+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
263265
],
264266
"@io_bazel_rules_go//go/platform:freebsd": [
265267
"//pkg/proxy/ipvs:go_default_library",
266268
"//pkg/proxy/util/iptables:go_default_library",
267269
"//pkg/util/iptables:go_default_library",
268270
"//pkg/util/iptables/testing:go_default_library",
269271
"//staging/src/k8s.io/api/core/v1:go_default_library",
272+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
270273
],
271274
"@io_bazel_rules_go//go/platform:ios": [
272275
"//pkg/proxy/ipvs:go_default_library",
273276
"//pkg/proxy/util/iptables:go_default_library",
274277
"//pkg/util/iptables:go_default_library",
275278
"//pkg/util/iptables/testing:go_default_library",
276279
"//staging/src/k8s.io/api/core/v1:go_default_library",
280+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
277281
],
278282
"@io_bazel_rules_go//go/platform:linux": [
279283
"//pkg/proxy/ipvs:go_default_library",
280284
"//pkg/proxy/util/iptables:go_default_library",
281285
"//pkg/util/iptables:go_default_library",
282286
"//pkg/util/iptables/testing:go_default_library",
283287
"//staging/src/k8s.io/api/core/v1:go_default_library",
288+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
284289
],
285290
"@io_bazel_rules_go//go/platform:nacl": [
286291
"//pkg/proxy/ipvs:go_default_library",
287292
"//pkg/proxy/util/iptables:go_default_library",
288293
"//pkg/util/iptables:go_default_library",
289294
"//pkg/util/iptables/testing:go_default_library",
290295
"//staging/src/k8s.io/api/core/v1:go_default_library",
296+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
291297
],
292298
"@io_bazel_rules_go//go/platform:netbsd": [
293299
"//pkg/proxy/ipvs:go_default_library",
294300
"//pkg/proxy/util/iptables:go_default_library",
295301
"//pkg/util/iptables:go_default_library",
296302
"//pkg/util/iptables/testing:go_default_library",
297303
"//staging/src/k8s.io/api/core/v1:go_default_library",
304+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
298305
],
299306
"@io_bazel_rules_go//go/platform:openbsd": [
300307
"//pkg/proxy/ipvs:go_default_library",
301308
"//pkg/proxy/util/iptables:go_default_library",
302309
"//pkg/util/iptables:go_default_library",
303310
"//pkg/util/iptables/testing:go_default_library",
304311
"//staging/src/k8s.io/api/core/v1:go_default_library",
312+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
305313
],
306314
"@io_bazel_rules_go//go/platform:plan9": [
307315
"//pkg/proxy/ipvs:go_default_library",
308316
"//pkg/proxy/util/iptables:go_default_library",
309317
"//pkg/util/iptables:go_default_library",
310318
"//pkg/util/iptables/testing:go_default_library",
311319
"//staging/src/k8s.io/api/core/v1:go_default_library",
320+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
312321
],
313322
"@io_bazel_rules_go//go/platform:solaris": [
314323
"//pkg/proxy/ipvs:go_default_library",
315324
"//pkg/proxy/util/iptables:go_default_library",
316325
"//pkg/util/iptables:go_default_library",
317326
"//pkg/util/iptables/testing:go_default_library",
318327
"//staging/src/k8s.io/api/core/v1:go_default_library",
328+
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
319329
],
320330
"//conditions:default": [],
321331
}),

cmd/kube-proxy/app/server_others.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,24 @@ func newProxyServer(
9191
return nil, fmt.Errorf("unable to register configz: %s", err)
9292
}
9393

94+
hostname, err := utilnode.GetHostname(config.HostnameOverride)
95+
if err != nil {
96+
return nil, err
97+
}
98+
99+
client, eventClient, err := createClients(config.ClientConnection, master)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
nodeIP := detectNodeIP(client, hostname, config.BindAddress)
105+
94106
protocol := utiliptables.ProtocolIPv4
95-
if net.ParseIP(config.BindAddress).To4() == nil {
96-
klog.V(0).Infof("IPv6 bind address (%s), assume IPv6 operation", config.BindAddress)
107+
if utilsnet.IsIPv6(nodeIP) {
108+
klog.V(0).Infof("kube-proxy node IP is an IPv6 address (%s), assume IPv6 operation", nodeIP.String())
97109
protocol = utiliptables.ProtocolIPv6
110+
} else {
111+
klog.V(0).Infof("kube-proxy node IP is an IPv4 address (%s), assume IPv4 operation", nodeIP.String())
98112
}
99113

100114
var iptInterface utiliptables.Interface
@@ -131,16 +145,7 @@ func newProxyServer(
131145
metrics.SetShowHidden()
132146
}
133147

134-
client, eventClient, err := createClients(config.ClientConnection, master)
135-
if err != nil {
136-
return nil, err
137-
}
138-
139148
// Create event recorder
140-
hostname, err := utilnode.GetHostname(config.HostnameOverride)
141-
if err != nil {
142-
return nil, err
143-
}
144149
eventBroadcaster := record.NewBroadcaster()
145150
recorder := eventBroadcaster.NewRecorder(proxyconfigscheme.Scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})
146151

@@ -175,15 +180,6 @@ func newProxyServer(
175180
klog.Infof("NodeInfo PodCIDR: %v, PodCIDRs: %v", nodeInfo.Spec.PodCIDR, nodeInfo.Spec.PodCIDRs)
176181
}
177182

178-
nodeIP := net.ParseIP(config.BindAddress)
179-
if nodeIP.IsUnspecified() {
180-
nodeIP = utilnode.GetNodeIP(client, hostname)
181-
if nodeIP == nil {
182-
klog.V(0).Infof("can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag")
183-
nodeIP = net.ParseIP("127.0.0.1")
184-
}
185-
}
186-
187183
klog.V(2).Info("DetectLocalMode: '", string(detectLocalMode), "'")
188184

189185
if proxyMode == proxyModeIPTables {
@@ -422,6 +418,23 @@ func waitForPodCIDR(client clientset.Interface, nodeName string) (*v1.Node, erro
422418
return nil, fmt.Errorf("event object not of type node")
423419
}
424420

421+
// detectNodeIP returns the nodeIP used by the proxier
422+
// The order of precedence is:
423+
// 1. config.bindAddress if bindAddress is not 0.0.0.0 or ::
424+
// 2. the primary IP from the Node object, if set
425+
// 3. if no IP is found it defaults to 127.0.0.1 and IPv4
426+
func detectNodeIP(client clientset.Interface, hostname, bindAddress string) net.IP {
427+
nodeIP := net.ParseIP(bindAddress)
428+
if nodeIP.IsUnspecified() {
429+
nodeIP = utilnode.GetNodeIP(client, hostname)
430+
}
431+
if nodeIP == nil {
432+
klog.V(0).Infof("can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag")
433+
nodeIP = net.ParseIP("127.0.0.1")
434+
}
435+
return nodeIP
436+
}
437+
425438
func getDetectLocalMode(config *proxyconfigapi.KubeProxyConfiguration) (proxyconfigapi.LocalMode, error) {
426439
mode := config.DetectLocalMode
427440
switch mode {

cmd/kube-proxy/app/server_others_test.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ package app
2020

2121
import (
2222
"fmt"
23+
"net"
2324
"reflect"
2425
"testing"
2526

2627
v1 "k8s.io/api/core/v1"
28+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29+
30+
clientsetfake "k8s.io/client-go/kubernetes/fake"
31+
2732
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
2833
"k8s.io/kubernetes/pkg/proxy/ipvs"
2934
proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables"
@@ -194,6 +199,111 @@ func Test_getDetectLocalMode(t *testing.T) {
194199
}
195200
}
196201

202+
func Test_detectNodeIP(t *testing.T) {
203+
cases := []struct {
204+
name string
205+
nodeInfo *v1.Node
206+
hostname string
207+
bindAddress string
208+
expectedIP net.IP
209+
}{
210+
{
211+
name: "Bind address IPv4 unicast address and no Node object",
212+
nodeInfo: makeNodeWithAddresses("", "", ""),
213+
hostname: "fakeHost",
214+
bindAddress: "10.0.0.1",
215+
expectedIP: net.ParseIP("10.0.0.1"),
216+
},
217+
{
218+
name: "Bind address IPv6 unicast address and no Node object",
219+
nodeInfo: makeNodeWithAddresses("", "", ""),
220+
hostname: "fakeHost",
221+
bindAddress: "fd00:4321::2",
222+
expectedIP: net.ParseIP("fd00:4321::2"),
223+
},
224+
{
225+
name: "No Valid IP found",
226+
nodeInfo: makeNodeWithAddresses("", "", ""),
227+
hostname: "fakeHost",
228+
bindAddress: "",
229+
expectedIP: net.ParseIP("127.0.0.1"),
230+
},
231+
// Disabled because the GetNodeIP method has a backoff retry mechanism
232+
// and the test takes more than 30 seconds
233+
// ok k8s.io/kubernetes/cmd/kube-proxy/app 34.136s
234+
// {
235+
// name: "No Valid IP found and unspecified bind address",
236+
// nodeInfo: makeNodeWithAddresses("", "", ""),
237+
// hostname: "fakeHost",
238+
// bindAddress: "0.0.0.0",
239+
// expectedIP: net.ParseIP("127.0.0.1"),
240+
// },
241+
{
242+
name: "Bind address 0.0.0.0 and node with IPv4 InternalIP set",
243+
nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"),
244+
hostname: "fakeHost",
245+
bindAddress: "0.0.0.0",
246+
expectedIP: net.ParseIP("192.168.1.1"),
247+
},
248+
{
249+
name: "Bind address :: and node with IPv4 InternalIP set",
250+
nodeInfo: makeNodeWithAddresses("fakeHost", "192.168.1.1", "90.90.90.90"),
251+
hostname: "fakeHost",
252+
bindAddress: "::",
253+
expectedIP: net.ParseIP("192.168.1.1"),
254+
},
255+
{
256+
name: "Bind address 0.0.0.0 and node with IPv6 InternalIP set",
257+
nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"),
258+
hostname: "fakeHost",
259+
bindAddress: "0.0.0.0",
260+
expectedIP: net.ParseIP("fd00:1234::1"),
261+
},
262+
{
263+
name: "Bind address :: and node with IPv6 InternalIP set",
264+
nodeInfo: makeNodeWithAddresses("fakeHost", "fd00:1234::1", "2001:db8::2"),
265+
hostname: "fakeHost",
266+
bindAddress: "::",
267+
expectedIP: net.ParseIP("fd00:1234::1"),
268+
},
269+
{
270+
name: "Bind address 0.0.0.0 and node with only IPv4 ExternalIP set",
271+
nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"),
272+
hostname: "fakeHost",
273+
bindAddress: "0.0.0.0",
274+
expectedIP: net.ParseIP("90.90.90.90"),
275+
},
276+
{
277+
name: "Bind address :: and node with only IPv4 ExternalIP set",
278+
nodeInfo: makeNodeWithAddresses("fakeHost", "", "90.90.90.90"),
279+
hostname: "fakeHost",
280+
bindAddress: "::",
281+
expectedIP: net.ParseIP("90.90.90.90"),
282+
},
283+
{
284+
name: "Bind address 0.0.0.0 and node with only IPv6 ExternalIP set",
285+
nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"),
286+
hostname: "fakeHost",
287+
bindAddress: "0.0.0.0",
288+
expectedIP: net.ParseIP("2001:db8::2"),
289+
},
290+
{
291+
name: "Bind address :: and node with only IPv6 ExternalIP set",
292+
nodeInfo: makeNodeWithAddresses("fakeHost", "", "2001:db8::2"),
293+
hostname: "fakeHost",
294+
bindAddress: "::",
295+
expectedIP: net.ParseIP("2001:db8::2"),
296+
},
297+
}
298+
for _, c := range cases {
299+
client := clientsetfake.NewSimpleClientset(c.nodeInfo)
300+
ip := detectNodeIP(client, c.hostname, c.bindAddress)
301+
if !ip.Equal(c.expectedIP) {
302+
t.Errorf("Case[%s] Expected IP %q got %q", c.name, c.expectedIP, ip)
303+
}
304+
}
305+
}
306+
197307
func Test_getLocalDetector(t *testing.T) {
198308
cases := []struct {
199309
mode proxyconfigapi.LocalMode
@@ -474,6 +584,35 @@ func Test_getDualStackLocalDetectorTuple(t *testing.T) {
474584
}
475585
}
476586

587+
func makeNodeWithAddresses(name, internal, external string) *v1.Node {
588+
if name == "" {
589+
return &v1.Node{}
590+
}
591+
592+
node := &v1.Node{
593+
ObjectMeta: metav1.ObjectMeta{
594+
Name: name,
595+
},
596+
Status: v1.NodeStatus{
597+
Addresses: []v1.NodeAddress{},
598+
},
599+
}
600+
601+
if internal != "" {
602+
node.Status.Addresses = append(node.Status.Addresses,
603+
v1.NodeAddress{Type: v1.NodeInternalIP, Address: internal},
604+
)
605+
}
606+
607+
if external != "" {
608+
node.Status.Addresses = append(node.Status.Addresses,
609+
v1.NodeAddress{Type: v1.NodeExternalIP, Address: external},
610+
)
611+
}
612+
613+
return node
614+
}
615+
477616
func makeNodeWithPodCIDRs(cidrs ...string) *v1.Node {
478617
if len(cidrs) == 0 {
479618
return &v1.Node{}

cmd/kube-proxy/app/server_test.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,9 @@ import (
3636

3737
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3838
componentbaseconfig "k8s.io/component-base/config"
39-
"k8s.io/component-base/configz"
4039
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
4140
)
4241

43-
// This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
44-
func TestProxyServerWithCleanupAndExit(t *testing.T) {
45-
// Each bind address below is a separate test case
46-
bindAddresses := []string{
47-
"0.0.0.0",
48-
"::",
49-
}
50-
for _, addr := range bindAddresses {
51-
options := NewOptions()
52-
53-
options.config = &kubeproxyconfig.KubeProxyConfiguration{
54-
BindAddress: addr,
55-
}
56-
options.CleanupAndExit = true
57-
58-
proxyserver, err := NewProxyServer(options)
59-
60-
assert.Nil(t, err, "unexpected error in NewProxyServer, addr: %s", addr)
61-
assert.NotNil(t, proxyserver, "nil proxy server obj, addr: %s", addr)
62-
assert.NotNil(t, proxyserver.IptInterface, "nil iptables intf, addr: %s", addr)
63-
64-
// Clean up config for next test case
65-
configz.Delete(kubeproxyconfig.GroupName)
66-
}
67-
}
68-
6942
func TestGetConntrackMax(t *testing.T) {
7043
ncores := runtime.NumCPU()
7144
testCases := []struct {

0 commit comments

Comments
 (0)