From 75b18b86ddc48a67d5069912f9965b40cfff62c4 Mon Sep 17 00:00:00 2001 From: Daman Arora Date: Wed, 3 Jul 2024 17:48:37 +0530 Subject: [PATCH 1/2] proxy/utils/nfacct: API to check if nfacct sub-system is present Signed-off-by: Daman Arora --- pkg/proxy/util/nfacct/nfacct_linux.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pkg/proxy/util/nfacct/nfacct_linux.go b/pkg/proxy/util/nfacct/nfacct_linux.go index ad0cfe03197..a5fb7ccecb9 100644 --- a/pkg/proxy/util/nfacct/nfacct_linux.go +++ b/pkg/proxy/util/nfacct/nfacct_linux.go @@ -59,13 +59,26 @@ type runner struct { handler handler } -// New returns a new Interface. +// New returns a new Interface. If the netfilter_nfacct subsystem is +// not available in the kernel it will return error. func New() (Interface, error) { hndlr, err := newNetlinkHandler() if err != nil { return nil, err } - return newInternal(hndlr) + + rnr, err := newInternal(hndlr) + if err != nil { + return nil, err + } + + // check if nfacct is supported on the current kernel by attempting to retrieve a counter. + // the following GET call should either succeed or return ENOENT. + _, err = rnr.Get("IMayExist") + if err != nil && !errors.Is(err, ErrObjectNotFound) { + return nil, ErrNotSupported + } + return rnr, nil } // newInternal returns a new Interface with the given handler. @@ -155,6 +168,7 @@ var ErrObjectAlreadyExists = errors.New("object already exists") var ErrNameExceedsMaxLength = fmt.Errorf("object name exceeds the maximum allowed length of %d characters", MaxLength) var ErrEmptyName = errors.New("object name cannot be empty") var ErrUnexpected = errors.New("unexpected error") +var ErrNotSupported = errors.New("nfacct sub-system not available") func handleError(err error) error { switch { From 33bac685a7e9db22d76be2ab77eb7500fa512c9c Mon Sep 17 00:00:00 2001 From: Daman Arora Date: Wed, 3 Jul 2024 17:57:11 +0530 Subject: [PATCH 2/2] conditionally register nfacct metrics and ensure nfacct counters If the nfacct sub-system is not available in the kernel then: 1. nfacct based metrics won't be registered. 2. proxier will not attempt to ensure the counters Signed-off-by: Daman Arora --- pkg/proxy/iptables/proxier.go | 2 +- pkg/proxy/metrics/metrics.go | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index d286c84323b..e5e96eee480 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -280,7 +280,7 @@ func NewProxier(ctx context.Context, serviceHealthServer := healthcheck.NewServiceHealthServer(hostname, recorder, nodePortAddresses, healthzServer) nfacctRunner, err := nfacct.New() if err != nil { - logger.Error(err, "Failed to create nfacct runner") + logger.Error(err, "Failed to create nfacct runner, nfacct based metrics won't be available") } proxier := &Proxier{ diff --git a/pkg/proxy/metrics/metrics.go b/pkg/proxy/metrics/metrics.go index 15682f25eaa..55696e147fb 100644 --- a/pkg/proxy/metrics/metrics.go +++ b/pkg/proxy/metrics/metrics.go @@ -299,8 +299,12 @@ func RegisterMetrics(mode kubeproxyconfig.ProxyMode) { switch mode { case kubeproxyconfig.ProxyModeIPTables: - legacyregistry.CustomMustRegister(iptablesCTStateInvalidDroppedMetricCollector) - legacyregistry.CustomMustRegister(localhostNodePortsAcceptedMetricsCollector) + if iptablesCTStateInvalidDroppedMetricCollector != nil { + legacyregistry.CustomMustRegister(iptablesCTStateInvalidDroppedMetricCollector) + } + if localhostNodePortsAcceptedMetricsCollector != nil { + legacyregistry.CustomMustRegister(localhostNodePortsAcceptedMetricsCollector) + } legacyregistry.MustRegister(SyncFullProxyRulesLatency) legacyregistry.MustRegister(SyncPartialProxyRulesLatency) legacyregistry.MustRegister(IPTablesRestoreFailuresTotal) @@ -332,6 +336,7 @@ func newNFAcctMetricCollector(counter string, description *metrics.Desc) *nfacct client, err := nfacct.New() if err != nil { klog.ErrorS(err, "failed to initialize nfacct client") + return nil } return &nfacctMetricCollector{ client: client,