Skip to content

Commit 59142b2

Browse files
authored
Merge pull request kubernetes#80636 from ebati/issue-80504-test-kubeproxy-mac
Add GetKernelVersion to ipvs.KernelHandler interface
2 parents 39af3cc + 90ce2d5 commit 59142b2

File tree

7 files changed

+275
-96
lines changed

7 files changed

+275
-96
lines changed

cmd/kube-proxy/app/server_others_test.go

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func Test_getProxyMode(t *testing.T) {
3232
iptablesVersion string
3333
ipsetVersion string
3434
kmods []string
35+
kernelVersion string
3536
kernelCompat bool
3637
iptablesError error
3738
ipsetError error
@@ -85,23 +86,33 @@ func Test_getProxyMode(t *testing.T) {
8586
kernelCompat: true,
8687
expected: proxyModeIPTables,
8788
},
88-
{ // flag says ipvs, ipset version ok, kernel modules installed
89-
flag: "ipvs",
90-
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
91-
ipsetVersion: ipvs.MinIPSetCheckVersion,
92-
expected: proxyModeIPVS,
89+
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel before 4.19
90+
flag: "ipvs",
91+
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
92+
kernelVersion: "4.18",
93+
ipsetVersion: ipvs.MinIPSetCheckVersion,
94+
expected: proxyModeIPVS,
95+
},
96+
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel 4.19
97+
flag: "ipvs",
98+
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
99+
kernelVersion: "4.19",
100+
ipsetVersion: ipvs.MinIPSetCheckVersion,
101+
expected: proxyModeIPVS,
93102
},
94103
{ // flag says ipvs, ipset version too low, fallback on iptables mode
95104
flag: "ipvs",
96-
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
105+
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
106+
kernelVersion: "4.19",
97107
ipsetVersion: "0.0",
98108
iptablesVersion: iptables.MinCheckVersion,
99109
kernelCompat: true,
100110
expected: proxyModeIPTables,
101111
},
102112
{ // flag says ipvs, bad ipset version, fallback on iptables mode
103113
flag: "ipvs",
104-
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
114+
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
115+
kernelVersion: "4.19",
105116
ipsetVersion: "a.b.c",
106117
iptablesVersion: iptables.MinCheckVersion,
107118
kernelCompat: true,
@@ -110,6 +121,7 @@ func Test_getProxyMode(t *testing.T) {
110121
{ // flag says ipvs, required kernel modules are not installed, fallback on iptables mode
111122
flag: "ipvs",
112123
kmods: []string{"foo", "bar", "baz"},
124+
kernelVersion: "4.19",
113125
ipsetVersion: ipvs.MinIPSetCheckVersion,
114126
iptablesVersion: iptables.MinCheckVersion,
115127
kernelCompat: true,
@@ -118,14 +130,25 @@ func Test_getProxyMode(t *testing.T) {
118130
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
119131
flag: "ipvs",
120132
kmods: []string{"foo", "bar", "baz"},
133+
kernelVersion: "4.19",
134+
ipsetVersion: ipvs.MinIPSetCheckVersion,
135+
iptablesVersion: "0.0.0",
136+
kernelCompat: true,
137+
expected: proxyModeUserspace,
138+
},
139+
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
140+
flag: "ipvs",
141+
kmods: []string{"foo", "bar", "baz"},
142+
kernelVersion: "4.19",
121143
ipsetVersion: ipvs.MinIPSetCheckVersion,
122144
iptablesVersion: "0.0.0",
123145
kernelCompat: true,
124146
expected: proxyModeUserspace,
125147
},
126148
{ // flag says ipvs, ipset version too low, iptables version too old, kernel not compatible, fallback on userspace mode
127149
flag: "ipvs",
128-
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
150+
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
151+
kernelVersion: "4.19",
129152
ipsetVersion: "0.0",
130153
iptablesVersion: iptables.MinCheckVersion,
131154
kernelCompat: false,
@@ -136,7 +159,10 @@ func Test_getProxyMode(t *testing.T) {
136159
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
137160
kcompater := &fakeKernelCompatTester{c.kernelCompat}
138161
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
139-
khandler := &fakeKernelHandler{c.kmods}
162+
khandler := &fakeKernelHandler{
163+
modules: c.kmods,
164+
kernelVersion: c.kernelVersion,
165+
}
140166
r := getProxyMode(c.flag, versioner, khandler, ipsetver, kcompater)
141167
if r != c.expected {
142168
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)

cmd/kube-proxy/app/server_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,18 @@ func (fake *fakeKernelCompatTester) IsCompatible() error {
7373

7474
// fakeKernelHandler implements KernelHandler.
7575
type fakeKernelHandler struct {
76-
modules []string
76+
modules []string
77+
kernelVersion string
7778
}
7879

7980
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
8081
return fake.modules, nil
8182
}
8283

84+
func (fake *fakeKernelHandler) GetKernelVersion() (string, error) {
85+
return fake.kernelVersion, nil
86+
}
87+
8388
// This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
8489
func TestProxyServerWithCleanupAndExit(t *testing.T) {
8590
// Each bind address below is a separate test case

pkg/proxy/ipvs/proxier.go

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,24 @@ package ipvs
1919
import (
2020
"bytes"
2121
"fmt"
22+
"io"
2223
"io/ioutil"
2324
"net"
25+
"os"
2426
"regexp"
2527
"strconv"
2628
"strings"
2729
"sync"
2830
"sync/atomic"
2931
"time"
3032

31-
"k8s.io/klog"
32-
3333
v1 "k8s.io/api/core/v1"
3434
"k8s.io/apimachinery/pkg/types"
3535
"k8s.io/apimachinery/pkg/util/sets"
36+
"k8s.io/apimachinery/pkg/util/version"
3637
"k8s.io/apimachinery/pkg/util/wait"
3738
"k8s.io/client-go/tools/record"
39+
"k8s.io/klog"
3840
"k8s.io/kubernetes/pkg/proxy"
3941
"k8s.io/kubernetes/pkg/proxy/healthcheck"
4042
"k8s.io/kubernetes/pkg/proxy/metrics"
@@ -473,6 +475,7 @@ func newServiceInfo(port *v1.ServicePort, service *v1.Service, baseInfo *proxy.B
473475
// KernelHandler can handle the current installed kernel modules.
474476
type KernelHandler interface {
475477
GetModules() ([]string, error)
478+
GetKernelVersion() (string, error)
476479
}
477480

478481
// LinuxKernelHandler implements KernelHandler interface.
@@ -490,11 +493,17 @@ func NewLinuxKernelHandler() *LinuxKernelHandler {
490493
// GetModules returns all installed kernel modules.
491494
func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
492495
// Check whether IPVS required kernel modules are built-in
493-
kernelVersion, ipvsModules, err := utilipvs.GetKernelVersionAndIPVSMods(handle.executor)
496+
kernelVersionStr, err := handle.GetKernelVersion()
494497
if err != nil {
495498
return nil, err
496499
}
497-
builtinModsFilePath := fmt.Sprintf("/lib/modules/%s/modules.builtin", kernelVersion)
500+
kernelVersion, err := version.ParseGeneric(kernelVersionStr)
501+
if err != nil {
502+
return nil, fmt.Errorf("error parseing kernel version %q: %v", kernelVersionStr, err)
503+
}
504+
ipvsModules := utilipvs.GetRequiredIPVSModules(kernelVersion)
505+
506+
builtinModsFilePath := fmt.Sprintf("/lib/modules/%s/modules.builtin", kernelVersionStr)
498507
b, err := ioutil.ReadFile(builtinModsFilePath)
499508
if err != nil {
500509
klog.Warningf("Failed to read file %s with error %v. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules", builtinModsFilePath, err)
@@ -516,15 +525,49 @@ func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
516525
}
517526

518527
// Find out loaded kernel modules
519-
out, err := handle.executor.Command("cut", "-f1", "-d", " ", "/proc/modules").CombinedOutput()
528+
modulesFile, err := os.Open("/proc/modules")
520529
if err != nil {
521530
return nil, err
522531
}
523532

524-
mods := strings.Split(string(out), "\n")
533+
mods, err := getFirstColumn(modulesFile)
534+
if err != nil {
535+
return nil, fmt.Errorf("failed to find loaded kernel modules: %v", err)
536+
}
537+
525538
return append(mods, bmods...), nil
526539
}
527540

541+
// getFirstColumn reads all the content from r into memory and return a
542+
// slice which consists of the first word from each line.
543+
func getFirstColumn(r io.Reader) ([]string, error) {
544+
b, err := ioutil.ReadAll(r)
545+
if err != nil {
546+
return nil, err
547+
}
548+
549+
lines := strings.Split(string(b), "\n")
550+
words := make([]string, 0, len(lines))
551+
for i := range lines {
552+
fields := strings.Fields(lines[i])
553+
if len(fields) > 0 {
554+
words = append(words, fields[0])
555+
}
556+
}
557+
return words, nil
558+
}
559+
560+
// GetKernelVersion returns currently running kernel version.
561+
func (handle *LinuxKernelHandler) GetKernelVersion() (string, error) {
562+
kernelVersionFile := "/proc/sys/kernel/osrelease"
563+
fileContent, err := ioutil.ReadFile(kernelVersionFile)
564+
if err != nil {
565+
return "", fmt.Errorf("error reading osrelease file %q: %v", kernelVersionFile, err)
566+
}
567+
568+
return strings.TrimSpace(string(fileContent)), nil
569+
}
570+
528571
// CanUseIPVSProxier returns true if we can use the ipvs Proxier.
529572
// This is determined by checking if all the required kernel modules can be loaded. It may
530573
// return an error if it fails to get the kernel modules information without error, in which
@@ -534,12 +577,21 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner) (bool, err
534577
if err != nil {
535578
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
536579
}
537-
wantModules := sets.NewString()
538580
loadModules := sets.NewString()
539-
linuxKernelHandler := NewLinuxKernelHandler()
540-
_, ipvsModules, _ := utilipvs.GetKernelVersionAndIPVSMods(linuxKernelHandler.executor)
541-
wantModules.Insert(ipvsModules...)
542581
loadModules.Insert(mods...)
582+
583+
kernelVersionStr, err := handle.GetKernelVersion()
584+
if err != nil {
585+
return false, fmt.Errorf("error determining kernel version to find required kernel modules for ipvs support: %v", err)
586+
}
587+
kernelVersion, err := version.ParseGeneric(kernelVersionStr)
588+
if err != nil {
589+
return false, fmt.Errorf("error parseing kernel version %q: %v", kernelVersionStr, err)
590+
}
591+
mods = utilipvs.GetRequiredIPVSModules(kernelVersion)
592+
wantModules := sets.NewString()
593+
wantModules.Insert(mods...)
594+
543595
modules := wantModules.Difference(loadModules).UnsortedList()
544596
var missingMods []string
545597
ConntrackiMissingCounter := 0

0 commit comments

Comments
 (0)