mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
ipvs: ensure selected scheduler kernel modules are loaded
Signed-off-by: Christopher M. Luciano <cmluciano@us.ibm.com>
This commit is contained in:
parent
240a72b5c0
commit
e2a0eddaf0
@ -122,7 +122,7 @@ func newProxyServer(
|
|||||||
iptInterface = utiliptables.New(execer, protocol)
|
iptInterface = utiliptables.New(execer, protocol)
|
||||||
kernelHandler = ipvs.NewLinuxKernelHandler()
|
kernelHandler = ipvs.NewLinuxKernelHandler()
|
||||||
ipsetInterface = utilipset.New(execer)
|
ipsetInterface = utilipset.New(execer)
|
||||||
canUseIPVS, err := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface)
|
canUseIPVS, err := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface, config.IPVS.Scheduler)
|
||||||
if string(config.Mode) == proxyModeIPVS && err != nil {
|
if string(config.Mode) == proxyModeIPVS && err != nil {
|
||||||
klog.Errorf("Can't use the IPVS proxier: %v", err)
|
klog.Errorf("Can't use the IPVS proxier: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
kernelCompat bool
|
kernelCompat bool
|
||||||
ipsetError error
|
ipsetError error
|
||||||
expected string
|
expected string
|
||||||
|
scheduler string
|
||||||
}{
|
}{
|
||||||
{ // flag says userspace
|
{ // flag says userspace
|
||||||
flag: "userspace",
|
flag: "userspace",
|
||||||
@ -142,6 +143,14 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
expected: proxyModeIPTables,
|
expected: proxyModeIPTables,
|
||||||
},
|
},
|
||||||
|
{ // flag says ipvs, ipset version ok, kernel modules installed for sed scheduler
|
||||||
|
flag: "ipvs",
|
||||||
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_sed"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
|
expected: proxyModeIPVS,
|
||||||
|
scheduler: "sed",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
||||||
@ -150,7 +159,11 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
modules: c.kmods,
|
modules: c.kmods,
|
||||||
kernelVersion: c.kernelVersion,
|
kernelVersion: c.kernelVersion,
|
||||||
}
|
}
|
||||||
canUseIPVS, _ := ipvs.CanUseIPVSProxier(khandler, ipsetver)
|
scheduler := cases[i].scheduler
|
||||||
|
if scheduler == "" {
|
||||||
|
scheduler = "rr"
|
||||||
|
}
|
||||||
|
canUseIPVS, _ := ipvs.CanUseIPVSProxier(khandler, ipsetver, scheduler)
|
||||||
r := getProxyMode(c.flag, canUseIPVS, kcompater)
|
r := getProxyMode(c.flag, canUseIPVS, kcompater)
|
||||||
if r != c.expected {
|
if r != c.expected {
|
||||||
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
||||||
|
@ -693,7 +693,7 @@ func (handle *LinuxKernelHandler) GetKernelVersion() (string, error) {
|
|||||||
// This is determined by checking if all the required kernel modules can be loaded. It may
|
// This is determined by checking if all the required kernel modules can be loaded. It may
|
||||||
// return an error if it fails to get the kernel modules information without error, in which
|
// return an error if it fails to get the kernel modules information without error, in which
|
||||||
// case it will also return false.
|
// case it will also return false.
|
||||||
func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner) (bool, error) {
|
func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner, scheduler string) (bool, error) {
|
||||||
mods, err := handle.GetModules()
|
mods, err := handle.GetModules()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
|
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
|
||||||
@ -711,6 +711,7 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner) (bool, err
|
|||||||
}
|
}
|
||||||
mods = utilipvs.GetRequiredIPVSModules(kernelVersion)
|
mods = utilipvs.GetRequiredIPVSModules(kernelVersion)
|
||||||
wantModules := sets.NewString()
|
wantModules := sets.NewString()
|
||||||
|
mods = append(mods, utilipvs.GetRequiredSchedulerModules(scheduler))
|
||||||
wantModules.Insert(mods...)
|
wantModules.Insert(mods...)
|
||||||
|
|
||||||
modules := wantModules.Difference(loadModules).UnsortedList()
|
modules := wantModules.Difference(loadModules).UnsortedList()
|
||||||
|
@ -259,6 +259,7 @@ func TestCleanupLeftovers(t *testing.T) {
|
|||||||
func TestCanUseIPVSProxier(t *testing.T) {
|
func TestCanUseIPVSProxier(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
mods []string
|
mods []string
|
||||||
|
scheduler string
|
||||||
kernelVersion string
|
kernelVersion string
|
||||||
kernelErr error
|
kernelErr error
|
||||||
ipsetVersion string
|
ipsetVersion string
|
||||||
@ -268,6 +269,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 0, kernel error
|
// case 0, kernel error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
scheduler: "",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
kernelErr: fmt.Errorf("oops"),
|
kernelErr: fmt.Errorf("oops"),
|
||||||
ipsetVersion: "0.0",
|
ipsetVersion: "0.0",
|
||||||
@ -276,6 +278,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 1, ipset error
|
// case 1, ipset error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
scheduler: "",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ipsetErr: fmt.Errorf("oops"),
|
ipsetErr: fmt.Errorf("oops"),
|
||||||
@ -284,6 +287,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 2, missing required kernel modules and ipset version too low
|
// case 2, missing required kernel modules and ipset version too low
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
scheduler: "rr",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "1.1",
|
ipsetVersion: "1.1",
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -291,6 +295,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 3, missing required ip_vs_* kernel modules
|
// case 3, missing required ip_vs_* kernel modules
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "a", "bc", "def"},
|
mods: []string{"ip_vs", "a", "bc", "def"},
|
||||||
|
scheduler: "sed",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -298,6 +303,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 4, ipset version too low
|
// case 4, ipset version too low
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
scheduler: "rr",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "4.3.0",
|
ipsetVersion: "4.3.0",
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -305,6 +311,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 5, ok for linux kernel 4.19
|
// case 5, ok for linux kernel 4.19
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
scheduler: "rr",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: true,
|
ok: true,
|
||||||
@ -312,6 +319,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 6, ok for linux kernel 4.18
|
// case 6, ok for linux kernel 4.18
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||||
|
scheduler: "rr",
|
||||||
kernelVersion: "4.18",
|
kernelVersion: "4.18",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: true,
|
ok: true,
|
||||||
@ -319,16 +327,33 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 7. ok when module list has extra modules
|
// case 7. ok when module list has extra modules
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "bar"},
|
mods: []string{"foo", "ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "bar"},
|
||||||
|
scheduler: "rr",
|
||||||
kernelVersion: "4.19",
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "6.19",
|
ipsetVersion: "6.19",
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
|
// case 8, not ok for sed based IPVS scheduling
|
||||||
|
{
|
||||||
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
scheduler: "sed",
|
||||||
|
kernelVersion: "4.19",
|
||||||
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
|
ok: false,
|
||||||
|
},
|
||||||
|
// case 9, ok for dh based IPVS scheduling
|
||||||
|
{
|
||||||
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_dh"},
|
||||||
|
scheduler: "dh",
|
||||||
|
kernelVersion: "4.19",
|
||||||
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
|
ok: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
handle := &fakeKernelHandler{modules: testCases[i].mods, kernelVersion: testCases[i].kernelVersion}
|
handle := &fakeKernelHandler{modules: testCases[i].mods, kernelVersion: testCases[i].kernelVersion}
|
||||||
versioner := &fakeIPSetVersioner{version: testCases[i].ipsetVersion, err: testCases[i].ipsetErr}
|
versioner := &fakeIPSetVersioner{version: testCases[i].ipsetVersion, err: testCases[i].ipsetErr}
|
||||||
ok, err := CanUseIPVSProxier(handle, versioner)
|
ok, err := CanUseIPVSProxier(handle, versioner, testCases[i].scheduler)
|
||||||
if ok != testCases[i].ok {
|
if ok != testCases[i].ok {
|
||||||
t.Errorf("Case [%d], expect %v, got %v: err: %v", i, testCases[i].ok, ok, err)
|
t.Errorf("Case [%d], expect %v, got %v: err: %v", i, testCases[i].ok, ok, err)
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,14 @@ const (
|
|||||||
KernelModuleIPVSWRR string = "ip_vs_wrr"
|
KernelModuleIPVSWRR string = "ip_vs_wrr"
|
||||||
// KernelModuleIPVSSH is the kernel module "ip_vs_sh"
|
// KernelModuleIPVSSH is the kernel module "ip_vs_sh"
|
||||||
KernelModuleIPVSSH string = "ip_vs_sh"
|
KernelModuleIPVSSH string = "ip_vs_sh"
|
||||||
|
// KernelModuleIPVSLC is the kernel module "ip_vs_lc"
|
||||||
|
KernelModuleIPVSLC string = "ip_vs_lc"
|
||||||
|
// KernelModuleIPVSNQ is the kernel module "ip_vs_nq"
|
||||||
|
KernelModuleIPVSNQ string = "ip_vs_nq"
|
||||||
|
// KernelModuleIPVSDH is the kernel module "ip_vs_dh"
|
||||||
|
KernelModuleIPVSDH string = "ip_vs_dh"
|
||||||
|
// KernelModuleIPVSSED is the kernel module "ip_vs_sed"
|
||||||
|
KernelModuleIPVSSED string = "ip_vs_sed"
|
||||||
// KernelModuleNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
// KernelModuleNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
||||||
KernelModuleNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
KernelModuleNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
||||||
// KernelModuleNfConntrack is the kernel module "nf_conntrack"
|
// KernelModuleNfConntrack is the kernel module "nf_conntrack"
|
||||||
@ -139,3 +147,23 @@ func GetRequiredIPVSModules(kernelVersion *version.Version) []string {
|
|||||||
func IsRsGracefulTerminationNeeded(proto string) bool {
|
func IsRsGracefulTerminationNeeded(proto string) bool {
|
||||||
return !strings.EqualFold(proto, "UDP") && !strings.EqualFold(proto, "SCTP")
|
return !strings.EqualFold(proto, "UDP") && !strings.EqualFold(proto, "SCTP")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRequiredSchedulerModules returns the required ipvs scheduler module for configured scheduler
|
||||||
|
func GetRequiredSchedulerModules(scheduler string) string {
|
||||||
|
switch s := scheduler; s {
|
||||||
|
case "rr":
|
||||||
|
return KernelModuleIPVSRR
|
||||||
|
case "lc":
|
||||||
|
return KernelModuleIPVSLC
|
||||||
|
case "nq":
|
||||||
|
return KernelModuleIPVSNQ
|
||||||
|
case "dh":
|
||||||
|
return KernelModuleIPVSDH
|
||||||
|
case "sh":
|
||||||
|
return KernelModuleIPVSSH
|
||||||
|
case "sed":
|
||||||
|
return KernelModuleIPVSSED
|
||||||
|
default:
|
||||||
|
return KernelModuleIPVSRR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user