ipvs: check for existence of scheduler module and fail if not found

Signed-off-by: Christopher M. Luciano <cmluciano@us.ibm.com>
This commit is contained in:
Christopher M. Luciano 2020-10-05 12:08:48 -04:00
parent 65ff4e8227
commit 51ed242194
No known key found for this signature in database
GPG Key ID: 5148DBB31F2843F1
5 changed files with 14 additions and 95 deletions

View File

@ -111,6 +111,7 @@ func Test_getProxyMode(t *testing.T) {
kernelVersion: "4.18", kernelVersion: "4.18",
ipsetVersion: ipvs.MinIPSetCheckVersion, ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS, expected: proxyModeIPVS,
scheduler: "rr",
}, },
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel 4.19 { // flag says ipvs, ipset version ok, kernel modules installed for linux kernel 4.19
flag: "ipvs", flag: "ipvs",
@ -118,6 +119,7 @@ func Test_getProxyMode(t *testing.T) {
kernelVersion: "4.19", kernelVersion: "4.19",
ipsetVersion: ipvs.MinIPSetCheckVersion, ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS, expected: proxyModeIPVS,
scheduler: "rr",
}, },
{ // flag says ipvs, ipset version too low, fallback on iptables mode { // flag says ipvs, ipset version too low, fallback on iptables mode
flag: "ipvs", flag: "ipvs",
@ -151,13 +153,14 @@ func Test_getProxyMode(t *testing.T) {
expected: proxyModeIPVS, expected: proxyModeIPVS,
scheduler: "sed", scheduler: "sed",
}, },
{ // flag says ipvs, ipset version ok, non-existent scheduler { // flag says ipvs, kernel modules not installed for sed scheduler, fallback to iptables
flag: "ipvs", flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_sed"}, kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
kernelVersion: "4.19", kernelVersion: "4.19",
ipsetVersion: ipvs.MinIPSetCheckVersion, ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS, expected: proxyModeIPTables,
scheduler: "foobar", kernelCompat: true,
scheduler: "sed",
}, },
} }
for i, c := range cases { for i, c := range cases {
@ -167,11 +170,7 @@ func Test_getProxyMode(t *testing.T) {
modules: c.kmods, modules: c.kmods,
kernelVersion: c.kernelVersion, kernelVersion: c.kernelVersion,
} }
scheduler := cases[i].scheduler canUseIPVS, _ := ipvs.CanUseIPVSProxier(khandler, ipsetver, 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)

View File

@ -711,10 +711,11 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner, scheduler
} }
mods = utilipvs.GetRequiredIPVSModules(kernelVersion) mods = utilipvs.GetRequiredIPVSModules(kernelVersion)
wantModules := sets.NewString() wantModules := sets.NewString()
schedulerMod, modNotFound := utilipvs.GetRequiredSchedulerModules(scheduler) // We check for the existence of the scheduler mod and will trigger a missingMods error if not found
if modNotFound != nil { if scheduler == "" {
klog.Error(modNotFound) scheduler = DefaultScheduler
} }
schedulerMod := "ip_vs_" + scheduler
mods = append(mods, schedulerMod) mods = append(mods, schedulerMod)
wantModules.Insert(mods...) wantModules.Insert(mods...)

View File

@ -348,13 +348,13 @@ func TestCanUseIPVSProxier(t *testing.T) {
ipsetVersion: MinIPSetCheckVersion, ipsetVersion: MinIPSetCheckVersion,
ok: true, ok: true,
}, },
// case 10, non-existent scheduler, fallback to rr // case 10, non-existent scheduler, error due to modules not existing
{ {
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_dh"}, mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "ip_vs_dh"},
scheduler: "foobar", scheduler: "foobar",
kernelVersion: "4.19", kernelVersion: "4.19",
ipsetVersion: MinIPSetCheckVersion, ipsetVersion: MinIPSetCheckVersion,
ok: true, ok: false,
}, },
} }

View File

@ -17,7 +17,6 @@ limitations under the License.
package ipvs package ipvs
import ( import (
"fmt"
"net" "net"
"strconv" "strconv"
"strings" "strings"
@ -84,14 +83,6 @@ 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"
@ -148,26 +139,3 @@ 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, error) {
switch s := scheduler; s {
case "rr":
return KernelModuleIPVSRR, nil
case "lc":
return KernelModuleIPVSLC, nil
case "nq":
return KernelModuleIPVSNQ, nil
case "dh":
return KernelModuleIPVSDH, nil
case "sh":
return KernelModuleIPVSSH, nil
case "sed":
return KernelModuleIPVSSED, nil
case "":
return KernelModuleIPVSRR, nil
default:
notFound := fmt.Errorf("ip_vs_%s is not a supported IPVS scheduler algorithm, falling back to round-robin", scheduler)
return KernelModuleIPVSRR, notFound
}
}

View File

@ -17,7 +17,6 @@ limitations under the License.
package ipvs package ipvs
import ( import (
"fmt"
"net" "net"
"reflect" "reflect"
"sort" "sort"
@ -414,51 +413,3 @@ func TestGetRequiredIPVSModules(t *testing.T) {
}) })
} }
} }
func TestGetRequiredSchedulerModules(t *testing.T) {
Tests := []struct {
name string
scheduler string
want string
expectedErrs error
}{
{
name: "scheduler explicitly set to rr",
scheduler: "rr",
want: "ip_vs_rr",
expectedErrs: nil,
},
{
name: "scheduler set to nq",
scheduler: "nq",
want: "ip_vs_nq",
expectedErrs: nil,
},
{
name: "unset scheduler",
scheduler: "",
want: "ip_vs_rr",
expectedErrs: nil,
},
{
name: "invalid scheduler algorithm",
scheduler: "foobar",
want: "ip_vs_rr",
expectedErrs: fmt.Errorf("ip_vs_%s is not a supported IPVS scheduler algorithm, falling back to round-robin", "foobar"),
},
}
for _, test := range Tests {
t.Run(test.name, func(t *testing.T) {
got, err := GetRequiredSchedulerModules(test.scheduler)
if !reflect.DeepEqual(got, test.want) {
t.Fatalf("GetRequiredSchedulerModules() = testCase %v failed- expected: %s scheduler, but got: %s", test.name, test.want, got)
}
if err != nil {
if err.Error() != test.expectedErrs.Error() {
t.Fatalf("Expected error: %v, got: %v", test.expectedErrs, err.Error())
}
}
})
}
}