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, 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 {