From 858b88bceefd170a1fddb3cccf35e6c0c50f4af0 Mon Sep 17 00:00:00 2001 From: Daman Arora Date: Tue, 29 Apr 2025 22:37:02 +0530 Subject: [PATCH] kube-proxy: log ipt errors during platformCheckSupported Signed-off-by: Daman Arora --- cmd/kube-proxy/app/server_linux.go | 14 ++++++----- pkg/kubelet/kubelet_network_linux.go | 8 ++++-- pkg/proxy/iptables/proxier.go | 2 +- pkg/proxy/ipvs/proxier.go | 2 +- pkg/util/iptables/iptables.go | 37 +++++++++++++++++++--------- pkg/util/iptables/iptables_test.go | 2 +- pkg/util/iptables/testing/fake.go | 4 +-- 7 files changed, 44 insertions(+), 25 deletions(-) diff --git a/cmd/kube-proxy/app/server_linux.go b/cmd/kube-proxy/app/server_linux.go index a64926faa48..7b967419705 100644 --- a/cmd/kube-proxy/app/server_linux.go +++ b/cmd/kube-proxy/app/server_linux.go @@ -112,16 +112,18 @@ func (s *ProxyServer) platformCheckSupported(ctx context.Context) (ipv4Supported if isIPTablesBased(s.Config.Mode) { // Check for the iptables and ip6tables binaries. - ipts := utiliptables.NewDualStack() + var ipts map[v1.IPFamily]utiliptables.Interface + ipts, err = utiliptables.NewDualStack() + ipv4Supported = ipts[v1.IPv4Protocol] != nil ipv6Supported = ipts[v1.IPv6Protocol] != nil if !ipv4Supported && !ipv6Supported { - err = fmt.Errorf("iptables is not available on this host") + err = fmt.Errorf("iptables is not available on this host : %w", err) } else if !ipv4Supported { - logger.Info("No iptables support for family", "ipFamily", v1.IPv4Protocol) + logger.Info("No iptables support for family", "ipFamily", v1.IPv4Protocol, "error", err) } else if !ipv6Supported { - logger.Info("No iptables support for family", "ipFamily", v1.IPv6Protocol) + logger.Info("No iptables support for family", "ipFamily", v1.IPv6Protocol, "error", err) } } else { // The nft CLI always supports both families. @@ -151,7 +153,7 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. if config.Mode == proxyconfigapi.ProxyModeIPTables { logger.Info("Using iptables Proxier") - ipts := utiliptables.NewDualStack() + ipts, _ := utiliptables.NewDualStack() if dualStack { // TODO this has side effects that should only happen when Run() is invoked. @@ -205,7 +207,7 @@ func (s *ProxyServer) createProxier(ctx context.Context, config *proxyconfigapi. if err := ipvs.CanUseIPVSProxier(ctx, ipvsInterface, ipsetInterface, config.IPVS.Scheduler); err != nil { return nil, fmt.Errorf("can't use the IPVS proxier: %v", err) } - ipts := utiliptables.NewDualStack() + ipts, _ := utiliptables.NewDualStack() logger.Info("Using ipvs Proxier") if dualStack { diff --git a/pkg/kubelet/kubelet_network_linux.go b/pkg/kubelet/kubelet_network_linux.go index 32ed9eb2429..430e3105da2 100644 --- a/pkg/kubelet/kubelet_network_linux.go +++ b/pkg/kubelet/kubelet_network_linux.go @@ -37,8 +37,12 @@ const ( ) func (kl *Kubelet) initNetworkUtil() { - iptClients := utiliptables.NewDualStack() - if len(iptClients) == 0 { + iptClients, err := utiliptables.NewDualStack() + if err != nil { + klog.ErrorS(err, "Failed to initialize iptables") + } + + if err != nil || len(iptClients) == 0 { klog.InfoS("No iptables support on this system; not creating the KUBE-IPTABLES-HINT chain") return } diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index f410338af0c..09d5abefce8 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -406,7 +406,7 @@ var iptablesCleanupOnlyChains = []iptablesJumpChain{} // CleanupLeftovers removes all iptables rules and chains created by the Proxier // It returns true if an error was encountered. Errors are logged. func CleanupLeftovers(ctx context.Context) (encounteredError bool) { - ipts := utiliptables.NewDualStack() + ipts, _ := utiliptables.NewDualStack() for _, ipt := range ipts { encounteredError = cleanupLeftoversForFamily(ctx, ipt) || encounteredError } diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index 0dda44af00d..ccdb42d0308 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -706,7 +706,7 @@ func CleanupLeftovers(ctx context.Context) (encounteredError bool) { return false } - ipts := utiliptables.NewDualStack() + ipts, _ := utiliptables.NewDualStack() ipsetInterface := utilipset.New() ipvsInterface := utilipvs.New() diff --git a/pkg/util/iptables/iptables.go b/pkg/util/iptables/iptables.go index d38ab0f9d0e..6c30e5a4c51 100644 --- a/pkg/util/iptables/iptables.go +++ b/pkg/util/iptables/iptables.go @@ -97,7 +97,7 @@ type Interface interface { HasRandomFully() bool // Present checks if the kernel supports the iptable interface - Present() bool + Present() error } // Protocol defines the ip protocol either ipv4 or ipv6 @@ -250,29 +250,40 @@ func newInternal(exec utilexec.Interface, protocol Protocol, lockfilePath14x, lo } // New returns a new Interface which will exec iptables. +// Note that this function will return a single iptables Interface *and* an error, if only +// a single family is supported. func New(protocol Protocol) Interface { return newInternal(utilexec.New(), protocol, "", "") } -func newDualStackInternal(exec utilexec.Interface) map[v1.IPFamily]Interface { +func newDualStackInternal(exec utilexec.Interface) (map[v1.IPFamily]Interface, error) { + var err error interfaces := map[v1.IPFamily]Interface{} iptv4 := newInternal(exec, ProtocolIPv4, "", "") - if iptv4.Present() { + if presentErr := iptv4.Present(); presentErr != nil { + err = presentErr + } else { interfaces[v1.IPv4Protocol] = iptv4 } iptv6 := newInternal(exec, ProtocolIPv6, "", "") - if iptv6.Present() { + if presentErr := iptv6.Present(); presentErr != nil { + // If we get an error for both IPv4 and IPv6 Present() calls, it's virtually guaranteed that + // they're going to be the same error. We ignore the error for IPv6 if IPv4 has already failed. + if err == nil { + err = presentErr + } + } else { interfaces[v1.IPv6Protocol] = iptv6 } - return interfaces + return interfaces, err } // NewDualStack returns a map containing an IPv4 Interface (if IPv4 iptables is supported) // and an IPv6 Interface (if IPv6 iptables is supported). If either family is not // supported, no Interface will be returned for that family. -func NewDualStack() map[v1.IPFamily]Interface { +func NewDualStack() (map[v1.IPFamily]Interface, error) { return newDualStackInternal(utilexec.New()) } @@ -654,8 +665,11 @@ func (runner *runner) ChainExists(table Table, chain Chain) (bool, error) { trace := utiltrace.New("iptables ChainExists") defer trace.LogIfLong(2 * time.Second) - _, err := runner.run(opListChain, fullArgs) - return err == nil, err + out, err := runner.run(opListChain, fullArgs) + if err != nil { + return false, fmt.Errorf("error listing chain %q in table %q: %w: %s", chain, table, err, out) + } + return true, nil } type operation string @@ -759,12 +773,11 @@ func (runner *runner) HasRandomFully() bool { // Present tests if iptable is supported on current kernel by checking the existence // of default table and chain -func (runner *runner) Present() bool { +func (runner *runner) Present() error { if _, err := runner.ChainExists(TableNAT, ChainPostrouting); err != nil { - return false + return err } - - return true + return nil } var iptablesNotFoundStrings = []string{ diff --git a/pkg/util/iptables/iptables_test.go b/pkg/util/iptables/iptables_test.go index 26ab3a48e41..e5f41c05c74 100644 --- a/pkg/util/iptables/iptables_test.go +++ b/pkg/util/iptables/iptables_test.go @@ -329,7 +329,7 @@ func TestNewDualStack(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { fexec := fakeExecForCommands(tc.commands) - runners := newDualStackInternal(fexec) + runners, _ := newDualStackInternal(fexec) if tc.ipv4 && runners[v1.IPv4Protocol] == nil { t.Errorf("Expected ipv4 runner, got nil") diff --git a/pkg/util/iptables/testing/fake.go b/pkg/util/iptables/testing/fake.go index 6152113dd15..4658d73263d 100644 --- a/pkg/util/iptables/testing/fake.go +++ b/pkg/util/iptables/testing/fake.go @@ -327,8 +327,8 @@ func (f *FakeIPTables) HasRandomFully() bool { return f.hasRandomFully } -func (f *FakeIPTables) Present() bool { - return true +func (f *FakeIPTables) Present() error { + return nil } var _ = iptables.Interface(&FakeIPTables{})