kube-proxy: remove ipvs-to-iptables fallback

If the user passes "--proxy-mode ipvs", and it is not possible to use
IPVS, then error out rather than falling back to iptables.

There was never any good reason to be doing fallback; this was
presumably erroneously added to parallel the iptables-to-userspace
fallback (which only existed because we had wanted iptables to be the
default but not all systems could support it).

In particular, if the user passed configuration options for ipvs, then
they presumably *didn't* pass configuration options for iptables, and
so even if the iptables proxy is able to run, it is likely to be
misconfigured.
This commit is contained in:
Dan Winship
2022-08-11 12:26:23 -04:00
parent 9f69a3a9d4
commit 1609017f2b
4 changed files with 27 additions and 192 deletions

View File

@@ -90,25 +90,9 @@ func newProxyServer(
return nil, fmt.Errorf("unable to register configz: %s", err)
}
var iptInterface utiliptables.Interface
var ipvsInterface utilipvs.Interface
var kernelHandler ipvs.KernelHandler
var ipsetInterface utilipset.Interface
// Create a iptables utils.
execer := exec.New()
kernelHandler = ipvs.NewLinuxKernelHandler()
ipsetInterface = utilipset.New(execer)
canUseIPVS, err := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface, config.IPVS.Scheduler)
if string(config.Mode) == proxyModeIPVS && err != nil {
klog.ErrorS(err, "Can't use the IPVS proxier")
}
if canUseIPVS {
ipvsInterface = utilipvs.New()
}
if len(config.ShowHiddenMetricsForVersion) > 0 {
metrics.SetShowHidden()
}
@@ -145,7 +129,7 @@ func newProxyServer(
var proxier proxy.Provider
var detectLocalMode proxyconfigapi.LocalMode
proxyMode := getProxyMode(string(config.Mode), canUseIPVS)
proxyMode := getProxyMode(string(config.Mode))
detectLocalMode, err = getDetectLocalMode(config)
if err != nil {
return nil, fmt.Errorf("cannot determine detect-local-mode: %v", err)
@@ -167,7 +151,8 @@ func newProxyServer(
if netutils.IsIPv6(nodeIP) {
primaryProtocol = utiliptables.ProtocolIPv6
}
iptInterface = utiliptables.New(execer, primaryProtocol)
execer := exec.New()
iptInterface := utiliptables.New(execer, primaryProtocol)
var ipt [2]utiliptables.Interface
dualStack := true // While we assume that node supports, we do further checks below
@@ -255,6 +240,13 @@ func newProxyServer(
}
proxymetrics.RegisterMetrics()
} else if proxyMode == proxyModeIPVS {
kernelHandler := ipvs.NewLinuxKernelHandler()
ipsetInterface = utilipset.New(execer)
if err := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface, config.IPVS.Scheduler); err != nil {
return nil, fmt.Errorf("can't use the IPVS proxier: %v", err)
}
ipvsInterface = utilipvs.New()
klog.V(0).InfoS("Using ipvs Proxier")
if dualStack {
klog.V(0).InfoS("Creating dualStackProxier for ipvs")
@@ -555,26 +547,13 @@ func cidrTuple(cidrList string) [2]string {
return cidrs
}
func getProxyMode(proxyMode string, canUseIPVS bool) string {
switch proxyMode {
case proxyModeUserspace:
return proxyModeUserspace
case proxyModeIPTables:
func getProxyMode(proxyMode string) string {
if proxyMode == "" {
klog.InfoS("Using iptables proxy")
return proxyModeIPTables
case proxyModeIPVS:
return tryIPVSProxy(canUseIPVS)
} else {
return proxyMode
}
klog.InfoS("Unknown proxy mode, assuming iptables proxy", "proxyMode", proxyMode)
return proxyModeIPTables
}
func tryIPVSProxy(canUseIPVS bool) string {
if canUseIPVS {
return proxyModeIPVS
}
klog.V(1).InfoS("Can't use ipvs proxier, trying iptables proxier")
return proxyModeIPTables
}
// cleanupAndExit remove iptables rules and ipset/ipvs rules

View File

@@ -20,7 +20,6 @@ limitations under the License.
package app
import (
"fmt"
"net"
"reflect"
"testing"
@@ -32,154 +31,11 @@ import (
clientsetfake "k8s.io/client-go/kubernetes/fake"
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
"k8s.io/kubernetes/pkg/proxy/ipvs"
proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables"
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
utiliptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
)
type fakeIPSetVersioner struct {
version string // what to return
err error // what to return
}
func (fake *fakeIPSetVersioner) GetVersion() (string, error) {
return fake.version, fake.err
}
type fakeKernelCompatTester struct {
ok bool
}
func (fake *fakeKernelCompatTester) IsCompatible() error {
if !fake.ok {
return fmt.Errorf("error")
}
return nil
}
// fakeKernelHandler implements KernelHandler.
type fakeKernelHandler struct {
modules []string
kernelVersion string
}
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
return fake.modules, nil
}
func (fake *fakeKernelHandler) GetKernelVersion() (string, error) {
return fake.kernelVersion, nil
}
func Test_getProxyMode(t *testing.T) {
var cases = []struct {
flag string
ipsetVersion string
kmods []string
kernelVersion string
kernelCompat bool
ipsetError error
expected string
scheduler string
}{
{ // flag says userspace
flag: "userspace",
expected: proxyModeUserspace,
},
{ // flag says iptables, kernel not compatible
flag: "iptables",
kernelCompat: false,
expected: proxyModeUserspace,
},
{ // flag says iptables, kernel is compatible
flag: "iptables",
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // detect, kernel not compatible
flag: "",
kernelCompat: false,
expected: proxyModeUserspace,
},
{ // detect, kernel is compatible
flag: "",
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel before 4.19
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
kernelVersion: "4.18",
ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS,
scheduler: "rr",
},
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel 4.19
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
kernelVersion: "4.19",
ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPVS,
scheduler: "rr",
},
{ // flag says ipvs, ipset version too low, fallback on iptables mode
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
kernelVersion: "4.19",
ipsetVersion: "0.0",
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, bad ipset version, fallback on iptables mode
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
kernelVersion: "4.19",
ipsetVersion: "a.b.c",
kernelCompat: true,
expected: proxyModeIPTables,
},
{ // flag says ipvs, required kernel modules are not installed, fallback on iptables mode
flag: "ipvs",
kmods: []string{"foo", "bar", "baz"},
kernelVersion: "4.19",
ipsetVersion: ipvs.MinIPSetCheckVersion,
kernelCompat: true,
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",
},
{ // flag says ipvs, kernel modules not installed for sed scheduler, fallback to iptables
flag: "ipvs",
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
kernelVersion: "4.19",
ipsetVersion: ipvs.MinIPSetCheckVersion,
expected: proxyModeIPTables,
kernelCompat: true,
scheduler: "sed",
},
}
for i, c := range cases {
kcompater := &fakeKernelCompatTester{c.kernelCompat}
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
khandler := &fakeKernelHandler{
modules: c.kmods,
kernelVersion: c.kernelVersion,
}
canUseIPVS, _ := ipvs.CanUseIPVSProxier(khandler, ipsetver, cases[i].scheduler)
r := getProxyMode(c.flag, canUseIPVS, kcompater)
if r != c.expected {
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
}
}
}
func Test_getDetectLocalMode(t *testing.T) {
cases := []struct {
detectLocal string