From 4b765dcd052db33f290d261faf31e2c8bf38f279 Mon Sep 17 00:00:00 2001
From: Michi Mutsuzaki <michi@isovalent.com>
Date: Wed, 20 Nov 2024 23:55:04 +0000
Subject: [PATCH] Prepare for v1.16.4 release

Signed-off-by: Michi Mutsuzaki <michi@isovalent.com>
---
 CHANGELOG.md                                  |  12 +
 go.mod                                        |   4 +-
 go.sum                                        |  11 +-
 vendor/github.com/cilium/cilium/AUTHORS       |  11 +-
 .../cilium/pkg/clustermesh/types/option.go    |  16 +
 .../linux/safenetlink/netlink_linux.go        | 395 ++++++++++++++
 .../linux/safenetlink/netlink_unspecified.go  | 141 +++++
 .../cilium/cilium/pkg/mac/mac_linux.go        |   6 +-
 .../cilium/cilium/pkg/option/config.go        |  12 +-
 .../cilium/cilium/pkg/resiliency/error.go     |  14 +
 .../cilium/cilium/pkg/resiliency/errorset.go  |  63 +++
 .../cilium/cilium/pkg/resiliency/helpers.go   |  32 ++
 .../cilium/cilium/pkg/resiliency/retry.go     |  13 +
 .../github.com/vishvananda/netlink/.gitignore |   1 +
 .../vishvananda/netlink/addr_linux.go         |  15 +-
 .../vishvananda/netlink/bridge_linux.go       |  15 +-
 .../vishvananda/netlink/chain_linux.go        |  16 +-
 .../vishvananda/netlink/class_linux.go        |  14 +-
 .../vishvananda/netlink/conntrack_linux.go    | 328 +++++++++++-
 .../netlink/conntrack_unspecified.go          |  19 +
 .../vishvananda/netlink/devlink_linux.go      |  40 +-
 .../vishvananda/netlink/filter_linux.go       |  22 +-
 vendor/github.com/vishvananda/netlink/fou.go  |  15 +-
 .../vishvananda/netlink/fou_linux.go          |  66 +--
 .../vishvananda/netlink/fou_unspecified.go    |   1 +
 .../vishvananda/netlink/genetlink_linux.go    |  13 +-
 .../vishvananda/netlink/gtp_linux.go          |  13 +-
 .../vishvananda/netlink/inet_diag.go          |   4 +
 vendor/github.com/vishvananda/netlink/link.go |  41 +-
 .../vishvananda/netlink/link_linux.go         | 159 ++++--
 .../vishvananda/netlink/neigh_linux.go        |  34 +-
 .../vishvananda/netlink/netlink_linux.go      |   3 +
 .../vishvananda/netlink/nl/conntrack_linux.go |  37 ++
 .../vishvananda/netlink/nl/link_linux.go      |   8 +-
 .../vishvananda/netlink/nl/nl_linux.go        | 218 ++++++--
 .../vishvananda/netlink/nl/seg6local_linux.go |   4 +
 .../vishvananda/netlink/protinfo_linux.go     |  13 +-
 .../github.com/vishvananda/netlink/qdisc.go   |   2 +
 .../vishvananda/netlink/qdisc_linux.go        |  33 +-
 .../vishvananda/netlink/rdma_link_linux.go    |  24 +-
 .../vishvananda/netlink/route_linux.go        | 181 +++++--
 vendor/github.com/vishvananda/netlink/rule.go |  13 +-
 .../vishvananda/netlink/rule_linux.go         |  81 ++-
 .../vishvananda/netlink/rule_nonlinux.go      |   8 +
 .../github.com/vishvananda/netlink/socket.go  |  67 +++
 .../vishvananda/netlink/socket_linux.go       | 296 ++++++-----
 .../vishvananda/netlink/socket_xdp_linux.go   | 207 ++++++++
 .../vishvananda/netlink/vdpa_linux.go         |  60 ++-
 .../vishvananda/netlink/xdp_diag.go           |  34 ++
 .../vishvananda/netlink/xdp_linux.go          |  46 ++
 .../vishvananda/netlink/xfrm_policy_linux.go  |  15 +-
 .../vishvananda/netlink/xfrm_state_linux.go   |  15 +-
 .../apimachinery/pkg/util/runtime/runtime.go  | 177 ++++++
 .../apimachinery/pkg/util/wait/backoff.go     | 502 ++++++++++++++++++
 .../apimachinery/pkg/util/wait/delay.go       |  51 ++
 .../k8s.io/apimachinery/pkg/util/wait/doc.go  |  19 +
 .../apimachinery/pkg/util/wait/error.go       |  96 ++++
 .../k8s.io/apimachinery/pkg/util/wait/loop.go |  95 ++++
 .../k8s.io/apimachinery/pkg/util/wait/poll.go | 315 +++++++++++
 .../apimachinery/pkg/util/wait/timer.go       | 121 +++++
 .../k8s.io/apimachinery/pkg/util/wait/wait.go | 223 ++++++++
 vendor/k8s.io/utils/clock/README.md           |   4 +
 vendor/k8s.io/utils/clock/clock.go            | 178 +++++++
 vendor/modules.txt                            |   9 +-
 64 files changed, 4256 insertions(+), 445 deletions(-)
 create mode 100644 vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_linux.go
 create mode 100644 vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_unspecified.go
 create mode 100644 vendor/github.com/cilium/cilium/pkg/resiliency/error.go
 create mode 100644 vendor/github.com/cilium/cilium/pkg/resiliency/errorset.go
 create mode 100644 vendor/github.com/cilium/cilium/pkg/resiliency/helpers.go
 create mode 100644 vendor/github.com/cilium/cilium/pkg/resiliency/retry.go
 create mode 100644 vendor/github.com/vishvananda/netlink/rule_nonlinux.go
 create mode 100644 vendor/github.com/vishvananda/netlink/socket_xdp_linux.go
 create mode 100644 vendor/github.com/vishvananda/netlink/xdp_diag.go
 create mode 100644 vendor/github.com/vishvananda/netlink/xdp_linux.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/delay.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/doc.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/error.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/loop.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/poll.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/timer.go
 create mode 100644 vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
 create mode 100644 vendor/k8s.io/utils/clock/README.md
 create mode 100644 vendor/k8s.io/utils/clock/clock.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b8fe754a2..77de8ea5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [v1.16.4] - 2024-11-20
+[v1.16.4]: https://github.com/cilium/cilium/compare/v1.16.3...v1.16.4
+
+**Misc Changes:**
+* hubble: Add 'release' Make target (Backport PR cilium/cilium#35781, Upstream PR cilium/cilium#35561, @michi-covalent)
+* chore(deps): update dependency helm/helm to v3.16.3 (cilium/hubble#1619, @renovate[bot])
+* chore(deps): update dependency kubernetes-sigs/kind to v0.25.0 (cilium/hubble#1616, @renovate[bot])
+* chore(deps): update docker.io/library/alpine:3.20.3 docker digest to 1e42bbe (cilium/hubble#1617, @renovate[bot])
+* chore(deps): update golang (cilium/hubble#1618, @renovate[bot])
+* chore(deps): update golang to v1.23.3 (patch) (cilium/hubble#1614, @renovate[bot])
+* Update stable release to 1.16.3 (cilium/hubble#1611, @michi-covalent)
+
 ## [v1.16.3] - 2024-10-25
 [v1.16.3]: https://github.com/cilium/cilium/compare/v1.16.2...v1.16.3
 
diff --git a/go.mod b/go.mod
index 6c8e5349f..053dd4d11 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module github.com/cilium/hubble
 
 go 1.22.2
 
-require github.com/cilium/cilium v1.16.3
+require github.com/cilium/cilium v1.16.4
 
 require (
 	github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
@@ -48,7 +48,7 @@ require (
 	github.com/spf13/viper v1.19.0 // indirect
 	github.com/stoewer/go-strcase v1.3.0 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
-	github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21 // indirect
+	github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 // indirect
 	github.com/vishvananda/netns v0.0.4 // indirect
 	go.mongodb.org/mongo-driver v1.14.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
diff --git a/go.sum b/go.sum
index 89a0716b2..0da56ae8e 100644
--- a/go.sum
+++ b/go.sum
@@ -8,8 +8,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/cilium/cilium v1.16.3 h1:Pdm3FdcdrGZ0Zh2i1oADmM89WE9xbePhRiL/8UqxEWY=
-github.com/cilium/cilium v1.16.3/go.mod h1:w6huXlvvCbDrOdKW1P5FXjT3JIXzEREtXbvhhMZHxKM=
+github.com/cilium/cilium v1.16.4 h1:YVyed/90Pfy5zyV1/v2uFLgcyWLj9/I4Sr3x3QGNRag=
+github.com/cilium/cilium v1.16.4/go.mod h1:Wgi1kl0UaiOmnzFxNAr7rON5tMp4GaiQrIvp0b2gJE0=
 github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
 github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
 github.com/cilium/hive v0.0.0-20240529072208-d997f86e4219 h1:iX4v9lg63iTv8x8MWUMVbeWqtAGcV6yh/w3Zp9sP3ME=
@@ -154,9 +154,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21 h1:tcHUxOT8j/R+0S+A1j8D2InqguXFNxAiij+8QFOlX7Y=
-github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21/go.mod h1:whJevzBpTrid75eZy99s3DqCmy05NfibNaF2Ol5Ox5A=
-github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 h1:9fkQcQYvtTr9ayFXuMfDMVuDt4+BYG9FwsGLnrBde0M=
+github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
 github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
 github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
 go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
@@ -179,9 +178,9 @@ golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
 golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
 golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
diff --git a/vendor/github.com/cilium/cilium/AUTHORS b/vendor/github.com/cilium/cilium/AUTHORS
index d92733fb5..8427fe1f9 100644
--- a/vendor/github.com/cilium/cilium/AUTHORS
+++ b/vendor/github.com/cilium/cilium/AUTHORS
@@ -52,7 +52,7 @@ Andrew Titmuss                          iandrewt@icloud.com
 Andrey Devyatkin                        andrey.devyatkin@fivexl.io
 Andrey Klimentyev                       andrey.klimentyev@flant.com
 Andrey Voronkov                         voronkovaa@gmail.com
-Andrii Iuspin                           57713382+ayuspin@users.noreply.github.com
+Andrii Iuspin                           andrii.iuspin@isovalent.com
 Andrzej Mamak                           nqaegg@gmail.com
 Andy Allred                             andy@punasusi.com
 andychuang                              andy.chuang@shoplineapp.com
@@ -77,6 +77,7 @@ Archana Shinde                          archana.m.shinde@intel.com
 Archer Wu                               archerwu9425@icloud.com
 Ardika Bagus                            me@ardikabs.com
 Arika Chen                              eaglesora@gmail.com
+Arkadiusz Kaliwoda (akaliwod)           akaliwod@cisco.com
 Arnaud Meukam                           ameukam@gmail.com
 Arseniy Belorukov                       a.belorukov@team.bumble.com
 Arthur Chiao                            arthurchiao@hotmail.com
@@ -242,6 +243,7 @@ Dylan Reimerink                         dylan.reimerink@isovalent.com
 Ekene Nwobodo                           nwobodoe71@gmail.com
 Electron                                alokaks601@gmail.com
 El-Fadel Bonfoh                         elfadel@accuknox.com
+Elias Hernandez                         elirayhernandez@gmail.com
 eliranw                                 39266788+eliranw@users.noreply.github.com
 Ellie Springsteen                       ellie.springsteen@appian.com
 Eloy Coto                               eloy.coto@acalustra.com
@@ -260,7 +262,7 @@ Erik Chang                              erik.chang@nordstrom.com
 Eugene Starchenko                       17835122+eugenestarchenko@users.noreply.github.com
 Ewout Prangsma                          ewout@prangsma.net
 Fabian Fischer                          fabian.fischer@isovalent.com
-Fabio Falzoi                            fabio.falzoi84@gmail.com
+Fabio Falzoi                            fabio.falzoi@isovalent.com
 Faiyaz Ahmed                            faiyaza@gmail.com
 Fankaixi Li                             fankaixi.li@bytedance.com
 Federico Hernandez                      f@ederi.co
@@ -279,6 +281,7 @@ Francois Allard                         francois@breathelife.com
 François Joulaud                        francois.joulaud@radiofrance.com
 Frank Villaro-Dixon                     frank.villaro@infomaniak.com
 Frederic Branczyk                       fbranczyk@gmail.com
+Fred Heinecke                           fred.heinecke@yahoo.com
 Fred Hsu                                fredlhsu@gmail.com
 Fredrik Lönnegren                       fredrik.lonnegren@gmail.com
 Fulvio Risso                            fulvio.risso@polito.it
@@ -511,6 +514,7 @@ Mathis Joffre                           51022808+Joffref@users.noreply.github.co
 Matt Anderson                           matanderson@equinix.com
 Matthew Fenwick                         mfenwick100@gmail.com
 Matthew Gumport                         me@gum.pt
+Matthias Baur                           m.baur@syseleven.de
 Matthieu Antoine                        matthieu.antoine@jumo.world
 Matthieu MOREL                          matthieu.morel35@gmail.com
 Matt Layher                             mdlayher@gmail.com
@@ -571,7 +575,7 @@ Nick Young                              ynick@cisco.com
 Niclas Mietz                            solidnerd@users.noreply.github.com
 Nico Berlee                             nico.berlee@on2it.net
 Nicolas Busseneau                       nicolas@isovalent.com
-Nico Vibert                             nicolas.vibert@isovalent.com
+Nico Vibert                             nvibert@cisco.com
 Nikhil Jha                              nikhiljha@users.noreply.github.com
 Nikhil Sharma                           nikhilsharma230303@gmail.com
 Nikolay Aleksandrov                     nikolay@isovalent.com
@@ -594,6 +598,7 @@ Oliver Wang                             a0924100192@gmail.com
 Omar Aloraini                           ooraini.dev@gmail.com
 Ondrej Blazek                           ondrej.blazek@firma.seznam.cz
 Ondrej Sika                             ondrej@ondrejsika.com
+oneumyvakin                             oneumyvaking@mail.ru
 Oshan Galwaduge                         oshan304@gmail.com
 Osthues                                 osthues.matthias@gmail.com
 Ovidiu Tirla                            otirla@google.com
diff --git a/vendor/github.com/cilium/cilium/pkg/clustermesh/types/option.go b/vendor/github.com/cilium/cilium/pkg/clustermesh/types/option.go
index 00b5673f6..444b25651 100644
--- a/vendor/github.com/cilium/cilium/pkg/clustermesh/types/option.go
+++ b/vendor/github.com/cilium/cilium/pkg/clustermesh/types/option.go
@@ -4,12 +4,14 @@
 package types
 
 import (
+	"errors"
 	"fmt"
 
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/pflag"
 
 	"github.com/cilium/cilium/pkg/defaults"
+	ipamOption "github.com/cilium/cilium/pkg/ipam/option"
 	"github.com/cilium/cilium/pkg/logging/logfields"
 )
 
@@ -66,6 +68,20 @@ func (c ClusterInfo) ValidateStrict(log logrus.FieldLogger) error {
 	return c.validateName(log)
 }
 
+// ValidateBuggyClusterID returns an error if a buggy cluster ID (i.e., with the
+// 7th bit set) is used in combination with ENI IPAM mode or AWS CNI chaining.
+func (c ClusterInfo) ValidateBuggyClusterID(ipamMode, chainingMode string) error {
+	if (c.ID&0x80) != 0 && (ipamMode == ipamOption.IPAMENI || ipamMode == ipamOption.IPAMAlibabaCloud || chainingMode == "aws-cni") {
+		return errors.New("Cilium is currently affected by a bug that causes traffic matched " +
+			"by network policies to be incorrectly dropped when running in either ENI mode (both " +
+			"AWS and AlibabaCloud) or AWS VPC CNI chaining mode, if the cluster ID is 128-255 (and " +
+			"384-511 when max-connected-clusters=511). " +
+			"Please refer to https://github.com/cilium/cilium/issues/21330 for additional details.")
+	}
+
+	return nil
+}
+
 func (c ClusterInfo) validateName(log logrus.FieldLogger) error {
 	if err := ValidateClusterName(c.Name); err != nil {
 		log.WithField(logfields.ClusterName, c.Name).WithError(err).
diff --git a/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_linux.go b/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_linux.go
new file mode 100644
index 000000000..8b1216dd9
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_linux.go
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package safenetlink
+
+import (
+	"context"
+	"errors"
+	"net"
+
+	"github.com/vishvananda/netlink"
+	"github.com/vishvananda/netlink/nl"
+
+	"github.com/cilium/cilium/pkg/resiliency"
+	"github.com/cilium/cilium/pkg/time"
+)
+
+const (
+	netlinkRetryInterval = 1 * time.Millisecond
+	netlinkRetryMax      = 30
+)
+
+// WithRetry runs the netlinkFunc. If netlinkFunc returns netlink.ErrDumpInterrupted, the function is retried.
+// If success or any other error is returned, WithRetry returns immediately, propagating the error.
+func WithRetry(netlinkFunc func() error) error {
+	return resiliency.Retry(context.Background(), netlinkRetryInterval, netlinkRetryMax, func(ctx context.Context, retries int) (bool, error) {
+		err := netlinkFunc()
+		if errors.Is(err, netlink.ErrDumpInterrupted) {
+			return false, nil // retry
+		}
+
+		return true, err
+	})
+}
+
+// WithRetryResult works like WithRetry, but allows netlinkFunc to have a return value besides the error
+func WithRetryResult[T any](netlinkFunc func() (T, error)) (out T, err error) {
+	err = WithRetry(func() error {
+		out, err = netlinkFunc()
+		return err
+	})
+	return out, err
+}
+
+// AddrList wraps netlink.AddrList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func AddrList(link netlink.Link, family int) ([]netlink.Addr, error) {
+	return WithRetryResult(func() ([]netlink.Addr, error) {
+		return netlink.AddrList(link, family)
+	})
+}
+
+// BridgeVlanList wraps netlink.BridgeVlanList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
+	return WithRetryResult(func() (map[int32][]*nl.BridgeVlanInfo, error) {
+		return netlink.BridgeVlanList()
+	})
+}
+
+// ChainList wraps netlink.ChainList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func ChainList(link netlink.Link, parent uint32) ([]netlink.Chain, error) {
+	return WithRetryResult(func() ([]netlink.Chain, error) {
+		return netlink.ChainList(link, parent)
+	})
+}
+
+// ClassList wraps netlink.ClassList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func ClassList(link netlink.Link, parent uint32) ([]netlink.Class, error) {
+	return WithRetryResult(func() ([]netlink.Class, error) {
+		return netlink.ClassList(link, parent)
+	})
+}
+
+// ConntrackTableList wraps netlink.ConntrackTableList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func ConntrackTableList(table netlink.ConntrackTableType, family netlink.InetFamily) ([]*netlink.ConntrackFlow, error) {
+	return WithRetryResult(func() ([]*netlink.ConntrackFlow, error) {
+		return netlink.ConntrackTableList(table, family)
+	})
+}
+
+// DevLinkGetDeviceList wraps netlink.DevLinkGetDeviceList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func DevLinkGetDeviceList() ([]*netlink.DevlinkDevice, error) {
+	return WithRetryResult(func() ([]*netlink.DevlinkDevice, error) {
+		return netlink.DevLinkGetDeviceList()
+	})
+}
+
+// DevLinkGetAllPortList wraps netlink.DevLinkGetAllPortList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func DevLinkGetAllPortList() ([]*netlink.DevlinkPort, error) {
+	return WithRetryResult(func() ([]*netlink.DevlinkPort, error) {
+		return netlink.DevLinkGetAllPortList()
+	})
+}
+
+// DevlinkGetDeviceParams wraps netlink.DevlinkGetDeviceParams, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func DevlinkGetDeviceParams(bus string, device string) ([]*netlink.DevlinkParam, error) {
+	return WithRetryResult(func() ([]*netlink.DevlinkParam, error) {
+		return netlink.DevlinkGetDeviceParams(bus, device)
+	})
+}
+
+// FilterList wraps netlink.FilterList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func FilterList(link netlink.Link, parent uint32) ([]netlink.Filter, error) {
+	return WithRetryResult(func() ([]netlink.Filter, error) {
+		return netlink.FilterList(link, parent)
+	})
+}
+
+// FouList wraps netlink.FouList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func FouList(fam int) ([]netlink.Fou, error) {
+	return WithRetryResult(func() ([]netlink.Fou, error) {
+		return netlink.FouList(fam)
+	})
+}
+
+// GenlFamilyList wraps netlink.GenlFamilyList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func GenlFamilyList() ([]*netlink.GenlFamily, error) {
+	return WithRetryResult(func() ([]*netlink.GenlFamily, error) {
+		return netlink.GenlFamilyList()
+	})
+}
+
+// GTPPDPList wraps netlink.GTPPDPList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func GTPPDPList() ([]*netlink.PDP, error) {
+	return WithRetryResult(func() ([]*netlink.PDP, error) {
+		return netlink.GTPPDPList()
+	})
+}
+
+// LinkByName wraps netlink.LinkByName, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func LinkByName(name string) (netlink.Link, error) {
+	return WithRetryResult(func() (netlink.Link, error) {
+		return netlink.LinkByName(name)
+	})
+}
+
+// LinkByAlias wraps netlink.LinkByAlias, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func LinkByAlias(alias string) (netlink.Link, error) {
+	return WithRetryResult(func() (netlink.Link, error) {
+		return netlink.LinkByAlias(alias)
+	})
+}
+
+// LinkList wraps netlink.LinkList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func LinkList() ([]netlink.Link, error) {
+	return WithRetryResult(func() ([]netlink.Link, error) {
+		return netlink.LinkList()
+	})
+}
+
+// LinkSubscribeWithOptions wraps netlink.LinkSubscribeWithOptions, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func LinkSubscribeWithOptions(ch chan<- netlink.LinkUpdate, done <-chan struct{}, options netlink.LinkSubscribeOptions) error {
+	return WithRetry(func() error {
+		return netlink.LinkSubscribeWithOptions(ch, done, options)
+	})
+}
+
+// NeighList wraps netlink.NeighList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func NeighList(linkIndex, family int) ([]netlink.Neigh, error) {
+	return WithRetryResult(func() ([]netlink.Neigh, error) {
+		return netlink.NeighList(linkIndex, family)
+	})
+}
+
+// NeighProxyList wraps netlink.NeighProxyList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func NeighProxyList(linkIndex, family int) ([]netlink.Neigh, error) {
+	return WithRetryResult(func() ([]netlink.Neigh, error) {
+		return netlink.NeighProxyList(linkIndex, family)
+	})
+}
+
+// NeighListExecute wraps netlink.NeighListExecute, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func NeighListExecute(msg netlink.Ndmsg) ([]netlink.Neigh, error) {
+	return WithRetryResult(func() ([]netlink.Neigh, error) {
+		return netlink.NeighListExecute(msg)
+	})
+}
+
+// LinkGetProtinfo wraps netlink.LinkGetProtinfo, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func LinkGetProtinfo(link netlink.Link) (netlink.Protinfo, error) {
+	return WithRetryResult(func() (netlink.Protinfo, error) {
+		return netlink.LinkGetProtinfo(link)
+	})
+}
+
+// QdiscList wraps netlink.QdiscList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func QdiscList(link netlink.Link) ([]netlink.Qdisc, error) {
+	return WithRetryResult(func() ([]netlink.Qdisc, error) {
+		return netlink.QdiscList(link)
+	})
+}
+
+// RdmaLinkList wraps netlink.RdmaLinkList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RdmaLinkList() ([]*netlink.RdmaLink, error) {
+	return WithRetryResult(func() ([]*netlink.RdmaLink, error) {
+		return netlink.RdmaLinkList()
+	})
+}
+
+// RdmaLinkByName wraps netlink.RdmaLinkByName, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RdmaLinkByName(name string) (*netlink.RdmaLink, error) {
+	return WithRetryResult(func() (*netlink.RdmaLink, error) {
+		return netlink.RdmaLinkByName(name)
+	})
+}
+
+// RdmaLinkDel wraps netlink.RdmaLinkDel, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RdmaLinkDel(name string) error {
+	return WithRetry(func() error {
+		return netlink.RdmaLinkDel(name)
+	})
+}
+
+// RouteList wraps netlink.RouteList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RouteList(link netlink.Link, family int) ([]netlink.Route, error) {
+	return WithRetryResult(func() ([]netlink.Route, error) {
+		return netlink.RouteList(link, family)
+	})
+}
+
+// RouteListFiltered wraps netlink.RouteListFiltered, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RouteListFiltered(family int, filter *netlink.Route, filterMask uint64) ([]netlink.Route, error) {
+	return WithRetryResult(func() ([]netlink.Route, error) {
+		return netlink.RouteListFiltered(family, filter, filterMask)
+	})
+}
+
+// RouteListFilteredIter wraps netlink.RouteListFilteredIter, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RouteListFilteredIter(family int, filter *netlink.Route, filterMask uint64, f func(netlink.Route) (cont bool)) error {
+	return WithRetry(func() error {
+		return netlink.RouteListFilteredIter(family, filter, filterMask, f)
+	})
+}
+
+// RouteSubscribeWithOptions wraps netlink.RouteSubscribeWithOptions, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RouteSubscribeWithOptions(ch chan<- netlink.RouteUpdate, done <-chan struct{}, options netlink.RouteSubscribeOptions) error {
+	return WithRetry(func() error {
+		return netlink.RouteSubscribeWithOptions(ch, done, options)
+	})
+}
+
+// RuleList wraps netlink.RuleList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RuleList(family int) ([]netlink.Rule, error) {
+	return WithRetryResult(func() ([]netlink.Rule, error) {
+		return netlink.RuleList(family)
+	})
+}
+
+// RuleListFiltered wraps netlink.RuleListFiltered, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func RuleListFiltered(family int, filter *netlink.Rule, filterMask uint64) ([]netlink.Rule, error) {
+	return WithRetryResult(func() ([]netlink.Rule, error) {
+		return netlink.RuleListFiltered(family, filter, filterMask)
+	})
+}
+
+// SocketGet wraps netlink.SocketGet, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketGet(local, remote net.Addr) (*netlink.Socket, error) {
+	return WithRetryResult(func() (*netlink.Socket, error) {
+		return netlink.SocketGet(local, remote)
+	})
+}
+
+// SocketDiagTCPInfo wraps netlink.SocketDiagTCPInfo, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketDiagTCPInfo(family uint8) ([]*netlink.InetDiagTCPInfoResp, error) {
+	return WithRetryResult(func() ([]*netlink.InetDiagTCPInfoResp, error) {
+		return netlink.SocketDiagTCPInfo(family)
+	})
+}
+
+// SocketDiagTCP wraps netlink.SocketDiagTCP, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketDiagTCP(family uint8) ([]*netlink.Socket, error) {
+	return WithRetryResult(func() ([]*netlink.Socket, error) {
+		return netlink.SocketDiagTCP(family)
+	})
+}
+
+// SocketDiagUDPInfo wraps netlink.SocketDiagUDPInfo, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketDiagUDPInfo(family uint8) ([]*netlink.InetDiagUDPInfoResp, error) {
+	return WithRetryResult(func() ([]*netlink.InetDiagUDPInfoResp, error) {
+		return netlink.SocketDiagUDPInfo(family)
+	})
+}
+
+// SocketDiagUDP wraps netlink.SocketDiagUDP, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketDiagUDP(family uint8) ([]*netlink.Socket, error) {
+	return WithRetryResult(func() ([]*netlink.Socket, error) {
+		return netlink.SocketDiagUDP(family)
+	})
+}
+
+// UnixSocketDiagInfo wraps netlink.UnixSocketDiagInfo, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func UnixSocketDiagInfo() ([]*netlink.UnixDiagInfoResp, error) {
+	return WithRetryResult(func() ([]*netlink.UnixDiagInfoResp, error) {
+		return netlink.UnixSocketDiagInfo()
+	})
+}
+
+// UnixSocketDiag wraps netlink.UnixSocketDiag, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func UnixSocketDiag() ([]*netlink.UnixSocket, error) {
+	return WithRetryResult(func() ([]*netlink.UnixSocket, error) {
+		return netlink.UnixSocketDiag()
+	})
+}
+
+// SocketXDPGetInfo wraps netlink.SocketXDPGetInfo, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketXDPGetInfo(ino uint32, cookie uint64) (*netlink.XDPDiagInfoResp, error) {
+	return WithRetryResult(func() (*netlink.XDPDiagInfoResp, error) {
+		return netlink.SocketXDPGetInfo(ino, cookie)
+	})
+}
+
+// SocketDiagXDP wraps netlink.SocketDiagXDP, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func SocketDiagXDP() ([]*netlink.XDPDiagInfoResp, error) {
+	return WithRetryResult(func() ([]*netlink.XDPDiagInfoResp, error) {
+		return netlink.SocketDiagXDP()
+	})
+}
+
+// VDPAGetDevList wraps netlink.VDPAGetDevList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func VDPAGetDevList() ([]*netlink.VDPADev, error) {
+	return WithRetryResult(func() ([]*netlink.VDPADev, error) {
+		return netlink.VDPAGetDevList()
+	})
+}
+
+// VDPAGetDevConfigList wraps netlink.VDPAGetDevConfigList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func VDPAGetDevConfigList() ([]*netlink.VDPADevConfig, error) {
+	return WithRetryResult(func() ([]*netlink.VDPADevConfig, error) {
+		return netlink.VDPAGetDevConfigList()
+	})
+}
+
+// VDPAGetMGMTDevList wraps netlink.VDPAGetMGMTDevList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func VDPAGetMGMTDevList() ([]*netlink.VDPAMGMTDev, error) {
+	return WithRetryResult(func() ([]*netlink.VDPAMGMTDev, error) {
+		return netlink.VDPAGetMGMTDevList()
+	})
+}
+
+// XfrmPolicyList wraps netlink.XfrmPolicyList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func XfrmPolicyList(family int) ([]netlink.XfrmPolicy, error) {
+	return WithRetryResult(func() ([]netlink.XfrmPolicy, error) {
+		return netlink.XfrmPolicyList(family)
+	})
+}
+
+// XfrmStateList wraps netlink.XfrmStateList, but retries the call automatically
+// if netlink.ErrDumpInterrupted is returned
+func XfrmStateList(family int) ([]netlink.XfrmState, error) {
+	return WithRetryResult(func() ([]netlink.XfrmState, error) {
+		return netlink.XfrmStateList(family)
+	})
+}
diff --git a/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_unspecified.go b/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_unspecified.go
new file mode 100644
index 000000000..046c03f99
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/datapath/linux/safenetlink/netlink_unspecified.go
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+//go:build !linux
+
+// This file duplicates the stubs that exist in vishvananda/netlink outside the linux build. Not all
+// functions defined in found in netlink_linux.go are present here, because not all have a stub in
+// vishvananda/netlink, and thus some of the necessary function signature types are missing outside
+// the linux build.
+
+package safenetlink
+
+import (
+	"net"
+
+	"github.com/vishvananda/netlink"
+)
+
+func AddrList(link netlink.Link, family int) ([]netlink.Addr, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func ChainList(link netlink.Link, parent uint32) ([]netlink.Chain, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func ClassList(link netlink.Link, parent uint32) ([]netlink.Class, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func ConntrackTableList(table netlink.ConntrackTableType, family netlink.InetFamily) ([]*netlink.ConntrackFlow, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func FilterList(link netlink.Link, parent uint32) ([]netlink.Filter, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func FouList(fam int) ([]netlink.Fou, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func GenlFamilyList() ([]*netlink.GenlFamily, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func LinkByName(name string) (netlink.Link, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func LinkByAlias(alias string) (netlink.Link, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func LinkList() ([]netlink.Link, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func NeighList(linkIndex, family int) ([]netlink.Neigh, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func NeighProxyList(linkIndex, family int) ([]netlink.Neigh, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func LinkGetProtinfo(link netlink.Link) (netlink.Protinfo, error) {
+	return netlink.Protinfo{}, netlink.ErrNotImplemented
+}
+
+func QdiscList(link netlink.Link) ([]netlink.Qdisc, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func RdmaLinkDel(name string) error {
+	return netlink.ErrNotImplemented
+}
+
+func RouteList(link netlink.Link, family int) ([]netlink.Route, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func RouteListFiltered(family int, filter *netlink.Route, filterMask uint64) ([]netlink.Route, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func RouteListFilteredIter(family int, filter *netlink.Route, filterMask uint64, f func(netlink.Route) (cont bool)) error {
+	return netlink.ErrNotImplemented
+}
+
+func RuleList(family int) ([]netlink.Rule, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func RuleListFiltered(family int, filter *netlink.Rule, filterMask uint64) ([]netlink.Rule, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketGet(local, remote net.Addr) (*netlink.Socket, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketDiagTCPInfo(family uint8) ([]*netlink.InetDiagTCPInfoResp, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketDiagTCP(family uint8) ([]*netlink.Socket, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketDiagUDPInfo(family uint8) ([]*netlink.InetDiagUDPInfoResp, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketDiagUDP(family uint8) ([]*netlink.Socket, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func UnixSocketDiagInfo() ([]*netlink.UnixDiagInfoResp, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func UnixSocketDiag() ([]*netlink.UnixSocket, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketXDPGetInfo(ino uint32, cookie uint64) (*netlink.XDPDiagInfoResp, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func SocketDiagXDP() ([]*netlink.XDPDiagInfoResp, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func XfrmPolicyList(family int) ([]netlink.XfrmPolicy, error) {
+	return nil, netlink.ErrNotImplemented
+}
+
+func XfrmStateList(family int) ([]netlink.XfrmState, error) {
+	return nil, netlink.ErrNotImplemented
+}
diff --git a/vendor/github.com/cilium/cilium/pkg/mac/mac_linux.go b/vendor/github.com/cilium/cilium/pkg/mac/mac_linux.go
index 9e9dd69ea..8f0d415e7 100644
--- a/vendor/github.com/cilium/cilium/pkg/mac/mac_linux.go
+++ b/vendor/github.com/cilium/cilium/pkg/mac/mac_linux.go
@@ -8,11 +8,13 @@ import (
 	"net"
 
 	"github.com/vishvananda/netlink"
+
+	"github.com/cilium/cilium/pkg/datapath/linux/safenetlink"
 )
 
 // HasMacAddr returns true if the given network interface has L2 addr.
 func HasMacAddr(iface string) bool {
-	link, err := netlink.LinkByName(iface)
+	link, err := safenetlink.LinkByName(iface)
 	if err != nil {
 		return false
 	}
@@ -26,7 +28,7 @@ func LinkHasMacAddr(link netlink.Link) bool {
 
 // ReplaceMacAddressWithLinkName replaces the MAC address of the given link
 func ReplaceMacAddressWithLinkName(ifName, macAddress string) error {
-	l, err := netlink.LinkByName(ifName)
+	l, err := safenetlink.LinkByName(ifName)
 	if err != nil {
 		if errors.As(err, &netlink.LinkNotFoundError{}) {
 			return nil
diff --git a/vendor/github.com/cilium/cilium/pkg/option/config.go b/vendor/github.com/cilium/cilium/pkg/option/config.go
index 3f83a2a1e..630dad159 100644
--- a/vendor/github.com/cilium/cilium/pkg/option/config.go
+++ b/vendor/github.com/cilium/cilium/pkg/option/config.go
@@ -3199,7 +3199,7 @@ func (c *DaemonConfig) Populate(vp *viper.Viper) {
 	encryptionStrictModeEnabled := vp.GetBool(EnableEncryptionStrictMode)
 	if encryptionStrictModeEnabled {
 		if c.EnableIPv6 {
-			log.Warnf("WireGuard encryption strict mode only support IPv4. IPv6 traffic is not protected and can be leaked.")
+			log.Info("WireGuard encryption strict mode only supports IPv4. IPv6 traffic is not protected and can be leaked.")
 		}
 
 		strictCIDR := vp.GetString(EncryptionStrictModeCIDR)
@@ -3229,11 +3229,6 @@ func (c *DaemonConfig) Populate(vp *viper.Viper) {
 		}
 	}
 
-	if c.EnableIPv4 && ipv4NativeRoutingCIDR == "" && c.EnableAutoDirectRouting {
-		log.Warnf("If %s is enabled, then you are recommended to also configure %s. If %s is not configured, this may lead to pod to pod traffic being masqueraded, "+
-			"which can cause problems with performance, observability and policy", EnableAutoDirectRoutingName, IPv4NativeRoutingCIDR, IPv4NativeRoutingCIDR)
-	}
-
 	ipv6NativeRoutingCIDR := vp.GetString(IPv6NativeRoutingCIDR)
 
 	if ipv6NativeRoutingCIDR != "" {
@@ -3247,11 +3242,6 @@ func (c *DaemonConfig) Populate(vp *viper.Viper) {
 		}
 	}
 
-	if c.EnableIPv6 && ipv6NativeRoutingCIDR == "" && c.EnableAutoDirectRouting {
-		log.Warnf("If %s is enabled, then you are recommended to also configure %s. If %s is not configured, this may lead to pod to pod traffic being masqueraded, "+
-			"which can cause problems with performance, observability and policy", EnableAutoDirectRoutingName, IPv6NativeRoutingCIDR, IPv6NativeRoutingCIDR)
-	}
-
 	if c.DirectRoutingSkipUnreachable && !c.EnableAutoDirectRouting {
 		log.Fatalf("Flag %s cannot be enabled when %s is not enabled. As if %s is then enabled, it may lead to unexpected behaviour causing network connectivity issues.", DirectRoutingSkipUnreachableName, EnableAutoDirectRoutingName, EnableAutoDirectRoutingName)
 	}
diff --git a/vendor/github.com/cilium/cilium/pkg/resiliency/error.go b/vendor/github.com/cilium/cilium/pkg/resiliency/error.go
new file mode 100644
index 000000000..cd348fc00
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/resiliency/error.go
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package resiliency
+
+// retryableErr tracks errors that could be retried.
+type retryableErr struct {
+	error
+}
+
+// Retryable returns a new instance.
+func Retryable(e error) retryableErr {
+	return retryableErr{error: e}
+}
diff --git a/vendor/github.com/cilium/cilium/pkg/resiliency/errorset.go b/vendor/github.com/cilium/cilium/pkg/resiliency/errorset.go
new file mode 100644
index 000000000..9ac59e72d
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/resiliency/errorset.go
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package resiliency
+
+import (
+	"errors"
+	"fmt"
+)
+
+type tuple struct {
+	index int
+	err   error
+}
+
+// ErrorSet tracks a collection of unique errors.
+type ErrorSet struct {
+	total, failed int
+	msg           string
+	errs          map[string]tuple
+}
+
+// NewErrorSet returns a new instance.
+func NewErrorSet(msg string, c int) *ErrorSet {
+	return &ErrorSet{
+		msg:   msg,
+		total: c,
+		errs:  make(map[string]tuple),
+	}
+}
+
+// Add adds one or more errors to the set.
+func (e *ErrorSet) Add(errs ...error) {
+	for _, err := range errs {
+		if err == nil {
+			continue
+		}
+		if _, ok := e.errs[err.Error()]; ok {
+			continue
+		}
+		e.errs[err.Error()] = tuple{index: e.failed, err: err}
+		e.failed++
+	}
+}
+
+// Error returns a list of unique errors or nil.
+func (e *ErrorSet) Errors() []error {
+	if len(e.errs) == 0 {
+		return nil
+	}
+	errs := make([]error, len(e.errs)+1)
+	errs[0] = fmt.Errorf("%s (%d/%d) failed", e.msg, e.failed, e.total)
+	for _, t := range e.errs {
+		errs[t.index+1] = t.err
+	}
+
+	return errs
+}
+
+// Error returns a new composite error or nil.
+func (e *ErrorSet) Error() error {
+	return errors.Join(e.Errors()...)
+}
diff --git a/vendor/github.com/cilium/cilium/pkg/resiliency/helpers.go b/vendor/github.com/cilium/cilium/pkg/resiliency/helpers.go
new file mode 100644
index 000000000..0cd5d9cb8
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/resiliency/helpers.go
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package resiliency
+
+import (
+	"context"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/wait"
+)
+
+// RetryFunc tracks resiliency retry calls.
+type RetryFunc func(ctx context.Context, retries int) (bool, error)
+
+// Retry retries the provided call using exponential retries given an initial duration for up to max retries count.
+func Retry(ctx context.Context, duration time.Duration, maxRetries int, fn RetryFunc) error {
+	bo := wait.Backoff{
+		Duration: duration,
+		Factor:   1,
+		Jitter:   0.1,
+		Steps:    maxRetries,
+	}
+
+	var retries int
+	f := func(ctx context.Context) (bool, error) {
+		retries++
+		return fn(ctx, retries)
+	}
+
+	return wait.ExponentialBackoffWithContext(ctx, bo, f)
+}
diff --git a/vendor/github.com/cilium/cilium/pkg/resiliency/retry.go b/vendor/github.com/cilium/cilium/pkg/resiliency/retry.go
new file mode 100644
index 000000000..a6f1bc634
--- /dev/null
+++ b/vendor/github.com/cilium/cilium/pkg/resiliency/retry.go
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package resiliency
+
+import (
+	"errors"
+)
+
+// IsRetryable checks if an error can be retried.
+func IsRetryable(e error) bool {
+	return errors.As(e, new(retryableErr))
+}
diff --git a/vendor/github.com/vishvananda/netlink/.gitignore b/vendor/github.com/vishvananda/netlink/.gitignore
index 9f11b755a..66f8fb502 100644
--- a/vendor/github.com/vishvananda/netlink/.gitignore
+++ b/vendor/github.com/vishvananda/netlink/.gitignore
@@ -1 +1,2 @@
 .idea/
+.vscode/
diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go
index 218ab2379..9b49baf97 100644
--- a/vendor/github.com/vishvananda/netlink/addr_linux.go
+++ b/vendor/github.com/vishvananda/netlink/addr_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"strings"
@@ -169,6 +170,9 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
 // AddrList gets a list of IP addresses in the system.
 // Equivalent to: `ip addr show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func AddrList(link Link, family int) ([]Addr, error) {
 	return pkgHandle.AddrList(link, family)
 }
@@ -176,14 +180,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
 // AddrList gets a list of IP addresses in the system.
 // Equivalent to: `ip addr show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
 	msg := nl.NewIfAddrmsg(family)
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	indexFilter := 0
@@ -212,7 +219,7 @@ func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
 		res = append(res, addr)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func parseAddr(m []byte) (addr Addr, family int, err error) {
diff --git a/vendor/github.com/vishvananda/netlink/bridge_linux.go b/vendor/github.com/vishvananda/netlink/bridge_linux.go
index 6c340b0ce..fa5766b80 100644
--- a/vendor/github.com/vishvananda/netlink/bridge_linux.go
+++ b/vendor/github.com/vishvananda/netlink/bridge_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 
 	"github.com/vishvananda/netlink/nl"
@@ -9,21 +10,27 @@ import (
 
 // BridgeVlanList gets a map of device id to bridge vlan infos.
 // Equivalent to: `bridge vlan show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
 	return pkgHandle.BridgeVlanList()
 }
 
 // BridgeVlanList gets a map of device id to bridge vlan infos.
 // Equivalent to: `bridge vlan show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
 	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
 	req.AddData(msg)
 	req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	ret := make(map[int32][]*nl.BridgeVlanInfo)
 	for _, m := range msgs {
@@ -51,7 +58,7 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
 			}
 		}
 	}
-	return ret, nil
+	return ret, executeErr
 }
 
 // BridgeVlanAdd adds a new vlan filter entry
diff --git a/vendor/github.com/vishvananda/netlink/chain_linux.go b/vendor/github.com/vishvananda/netlink/chain_linux.go
index d9f441613..5008e7101 100644
--- a/vendor/github.com/vishvananda/netlink/chain_linux.go
+++ b/vendor/github.com/vishvananda/netlink/chain_linux.go
@@ -1,6 +1,8 @@
 package netlink
 
 import (
+	"errors"
+
 	"github.com/vishvananda/netlink/nl"
 	"golang.org/x/sys/unix"
 )
@@ -56,6 +58,9 @@ func (h *Handle) chainModify(cmd, flags int, link Link, chain Chain) error {
 // ChainList gets a list of chains in the system.
 // Equivalent to: `tc chain list`.
 // The list can be filtered by link.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func ChainList(link Link, parent uint32) ([]Chain, error) {
 	return pkgHandle.ChainList(link, parent)
 }
@@ -63,6 +68,9 @@ func ChainList(link Link, parent uint32) ([]Chain, error) {
 // ChainList gets a list of chains in the system.
 // Equivalent to: `tc chain list`.
 // The list can be filtered by link.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETCHAIN, unix.NLM_F_DUMP)
 	index := int32(0)
@@ -78,9 +86,9 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
 	}
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWCHAIN)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Chain
@@ -108,5 +116,5 @@ func (h *Handle) ChainList(link Link, parent uint32) ([]Chain, error) {
 		res = append(res, chain)
 	}
 
-	return res, nil
+	return res, executeErr
 }
diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go
index a82eb09de..08fb16c2b 100644
--- a/vendor/github.com/vishvananda/netlink/class_linux.go
+++ b/vendor/github.com/vishvananda/netlink/class_linux.go
@@ -201,14 +201,20 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 
 // ClassList gets a list of classes in the system.
 // Equivalent to: `tc class show`.
+//
 // Generally returns nothing if link and parent are not specified.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func ClassList(link Link, parent uint32) ([]Class, error) {
 	return pkgHandle.ClassList(link, parent)
 }
 
 // ClassList gets a list of classes in the system.
 // Equivalent to: `tc class show`.
+//
 // Generally returns nothing if link and parent are not specified.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETTCLASS, unix.NLM_F_DUMP)
 	msg := &nl.TcMsg{
@@ -222,9 +228,9 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 	}
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTCLASS)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Class
@@ -295,7 +301,7 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
 		res = append(res, class)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
diff --git a/vendor/github.com/vishvananda/netlink/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
index eaa77e9c8..69c5eca03 100644
--- a/vendor/github.com/vishvananda/netlink/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
@@ -6,6 +6,7 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"strings"
 	"time"
 
 	"github.com/vishvananda/netlink/nl"
@@ -44,6 +45,9 @@ type InetFamily uint8
 
 // ConntrackTableList returns the flow list of a table of a specific family
 // conntrack -L [table] [options]          List conntrack or expectation table
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
 	return pkgHandle.ConntrackTableList(table, family)
 }
@@ -55,18 +59,41 @@ func ConntrackTableFlush(table ConntrackTableType) error {
 	return pkgHandle.ConntrackTableFlush(table)
 }
 
+// ConntrackCreate creates a new conntrack flow in the desired table
+// conntrack -I [table]		Create a conntrack or expectation
+func ConntrackCreate(table ConntrackTableType, family InetFamily, flow *ConntrackFlow) error {
+	return pkgHandle.ConntrackCreate(table, family, flow)
+}
+
+// ConntrackUpdate updates an existing conntrack flow in the desired table using the handle
+// conntrack -U [table]		Update a conntrack
+func ConntrackUpdate(table ConntrackTableType, family InetFamily, flow *ConntrackFlow) error {
+	return pkgHandle.ConntrackUpdate(table, family, flow)
+}
+
 // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
 // conntrack -D [table] parameters         Delete conntrack or expectation
+//
+// Deprecated: use [ConntrackDeleteFilters] instead.
 func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter CustomConntrackFilter) (uint, error) {
-	return pkgHandle.ConntrackDeleteFilter(table, family, filter)
+	return pkgHandle.ConntrackDeleteFilters(table, family, filter)
+}
+
+// ConntrackDeleteFilters deletes entries on the specified table matching any of the specified filters
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters ...CustomConntrackFilter) (uint, error) {
+	return pkgHandle.ConntrackDeleteFilters(table, family, filters...)
 }
 
 // ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
 // conntrack -L [table] [options]          List conntrack or expectation table
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
-	res, err := h.dumpConntrackTable(table, family)
-	if err != nil {
-		return nil, err
+	res, executeErr := h.dumpConntrackTable(table, family)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	// Deserialize all the flows
@@ -75,7 +102,7 @@ func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily)
 		result = append(result, parseRawData(dataRaw))
 	}
 
-	return result, nil
+	return result, executeErr
 }
 
 // ConntrackTableFlush flushes all the flows of a specified table using the netlink handle passed
@@ -87,26 +114,77 @@ func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
 	return err
 }
 
+// ConntrackCreate creates a new conntrack flow in the desired table using the handle
+// conntrack -I [table]		Create a conntrack or expectation
+func (h *Handle) ConntrackCreate(table ConntrackTableType, family InetFamily, flow *ConntrackFlow) error {
+	req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_NEW, unix.NLM_F_ACK|unix.NLM_F_CREATE)
+	attr, err := flow.toNlData()
+	if err != nil {
+		return err
+	}
+
+	for _, a := range attr {
+		req.AddData(a)
+	}
+
+	_, err = req.Execute(unix.NETLINK_NETFILTER, 0)
+	return err
+}
+
+// ConntrackUpdate updates an existing conntrack flow in the desired table using the handle
+// conntrack -U [table]		Update a conntrack
+func (h *Handle) ConntrackUpdate(table ConntrackTableType, family InetFamily, flow *ConntrackFlow) error {
+	req := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_NEW, unix.NLM_F_ACK|unix.NLM_F_REPLACE)
+	attr, err := flow.toNlData()
+	if err != nil {
+		return err
+	}
+
+	for _, a := range attr {
+		req.AddData(a)
+	}
+
+	_, err = req.Execute(unix.NETLINK_NETFILTER, 0)
+	return err
+}
+
 // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
 // conntrack -D [table] parameters         Delete conntrack or expectation
+//
+// Deprecated: use [Handle.ConntrackDeleteFilters] instead.
 func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter CustomConntrackFilter) (uint, error) {
+	return h.ConntrackDeleteFilters(table, family, filter)
+}
+
+// ConntrackDeleteFilters deletes entries on the specified table matching any of the specified filters using the netlink handle passed
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func (h *Handle) ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters ...CustomConntrackFilter) (uint, error) {
 	res, err := h.dumpConntrackTable(table, family)
 	if err != nil {
 		return 0, err
 	}
 
 	var matched uint
+	var errMsgs []string
 	for _, dataRaw := range res {
 		flow := parseRawData(dataRaw)
-		if match := filter.MatchConntrackFlow(flow); match {
-			req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
-			// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
-			req2.AddRawData(dataRaw[4:])
-			req2.Execute(unix.NETLINK_NETFILTER, 0)
-			matched++
+		for _, filter := range filters {
+			if match := filter.MatchConntrackFlow(flow); match {
+				req2 := h.newConntrackRequest(table, family, nl.IPCTNL_MSG_CT_DELETE, unix.NLM_F_ACK)
+				// skip the first 4 byte that are the netfilter header, the newConntrackRequest is adding it already
+				req2.AddRawData(dataRaw[4:])
+				if _, err = req2.Execute(unix.NETLINK_NETFILTER, 0); err == nil {
+					matched++
+					// flow is already deleted, no need to match on other filters and continue to the next flow.
+					break
+				}
+				errMsgs = append(errMsgs, fmt.Sprintf("failed to delete conntrack flow '%s': %s", flow.String(), err.Error()))
+			}
 		}
 	}
-
+	if len(errMsgs) > 0 {
+		return matched, fmt.Errorf(strings.Join(errMsgs, "; "))
+	}
 	return matched, nil
 }
 
@@ -128,10 +206,44 @@ func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily)
 	return req.Execute(unix.NETLINK_NETFILTER, 0)
 }
 
+// ProtoInfo wraps an L4-protocol structure - roughly corresponds to the
+// __nfct_protoinfo union found in libnetfilter_conntrack/include/internal/object.h.
+// Currently, only protocol names, and TCP state is supported.
+type ProtoInfo interface {
+	Protocol() string
+}
+
+// ProtoInfoTCP corresponds to the `tcp` struct of the __nfct_protoinfo union.
+// Only TCP state is currently supported.
+type ProtoInfoTCP struct {
+	State uint8
+}
+// Protocol returns "tcp".
+func (*ProtoInfoTCP) Protocol() string {return "tcp"}
+func (p *ProtoInfoTCP) toNlData() ([]*nl.RtAttr, error) {
+	ctProtoInfo := nl.NewRtAttr(unix.NLA_F_NESTED | nl.CTA_PROTOINFO, []byte{})
+	ctProtoInfoTCP := nl.NewRtAttr(unix.NLA_F_NESTED|nl.CTA_PROTOINFO_TCP, []byte{})
+	ctProtoInfoTCPState := nl.NewRtAttr(nl.CTA_PROTOINFO_TCP_STATE, nl.Uint8Attr(p.State))
+	ctProtoInfoTCP.AddChild(ctProtoInfoTCPState)
+	ctProtoInfo.AddChild(ctProtoInfoTCP)
+
+	return []*nl.RtAttr{ctProtoInfo}, nil
+}
+
+// ProtoInfoSCTP only supports the protocol name.
+type ProtoInfoSCTP struct {}
+// Protocol returns "sctp".
+func (*ProtoInfoSCTP) Protocol() string {return "sctp"}
+
+// ProtoInfoDCCP only supports the protocol name.
+type ProtoInfoDCCP struct {}
+// Protocol returns "dccp".
+func (*ProtoInfoDCCP) Protocol() string {return "dccp"}
+
 // The full conntrack flow structure is very complicated and can be found in the file:
 // http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
 // For the time being, the structure below allows to parse and extract the base information of a flow
-type ipTuple struct {
+type IPTuple struct {
 	Bytes    uint64
 	DstIP    net.IP
 	DstPort  uint16
@@ -141,16 +253,49 @@ type ipTuple struct {
 	SrcPort  uint16
 }
 
+// toNlData generates the inner fields of a nested tuple netlink datastructure
+// does not generate the "nested"-flagged outer message.
+func (t *IPTuple) toNlData(family uint8) ([]*nl.RtAttr, error) {
+
+	var srcIPsFlag, dstIPsFlag int
+	if family == nl.FAMILY_V4 {
+		srcIPsFlag = nl.CTA_IP_V4_SRC
+		dstIPsFlag = nl.CTA_IP_V4_DST
+	} else if family == nl.FAMILY_V6 {
+		srcIPsFlag = nl.CTA_IP_V6_SRC
+		dstIPsFlag = nl.CTA_IP_V6_DST
+	} else {
+		return []*nl.RtAttr{}, fmt.Errorf("couldn't generate netlink message for tuple due to unrecognized FamilyType '%d'", family)
+	}
+
+	ctTupleIP := nl.NewRtAttr(unix.NLA_F_NESTED|nl.CTA_TUPLE_IP, nil)
+	ctTupleIPSrc := nl.NewRtAttr(srcIPsFlag, t.SrcIP)
+	ctTupleIP.AddChild(ctTupleIPSrc)
+	ctTupleIPDst := nl.NewRtAttr(dstIPsFlag, t.DstIP)
+	ctTupleIP.AddChild(ctTupleIPDst)
+
+	ctTupleProto := nl.NewRtAttr(unix.NLA_F_NESTED|nl.CTA_TUPLE_PROTO, nil)
+	ctTupleProtoNum := nl.NewRtAttr(nl.CTA_PROTO_NUM, []byte{t.Protocol})
+	ctTupleProto.AddChild(ctTupleProtoNum)
+	ctTupleProtoSrcPort := nl.NewRtAttr(nl.CTA_PROTO_SRC_PORT, nl.BEUint16Attr(t.SrcPort))
+	ctTupleProto.AddChild(ctTupleProtoSrcPort)
+	ctTupleProtoDstPort := nl.NewRtAttr(nl.CTA_PROTO_DST_PORT, nl.BEUint16Attr(t.DstPort))
+	ctTupleProto.AddChild(ctTupleProtoDstPort, )
+
+	return []*nl.RtAttr{ctTupleIP, ctTupleProto}, nil
+}
+
 type ConntrackFlow struct {
 	FamilyType uint8
-	Forward    ipTuple
-	Reverse    ipTuple
+	Forward    IPTuple
+	Reverse    IPTuple
 	Mark       uint32
 	Zone       uint16
 	TimeStart  uint64
 	TimeStop   uint64
 	TimeOut    uint32
 	Labels     []byte
+	ProtoInfo  ProtoInfo
 }
 
 func (s *ConntrackFlow) String() string {
@@ -175,6 +320,85 @@ func (s *ConntrackFlow) String() string {
 	return res
 }
 
+// toNlData generates netlink messages representing the flow.
+func (s *ConntrackFlow) toNlData() ([]*nl.RtAttr, error) {
+	var payload []*nl.RtAttr
+	// The message structure is built as follows:
+	//	<len, NLA_F_NESTED|CTA_TUPLE_ORIG>
+	//		<len, NLA_F_NESTED|CTA_TUPLE_IP>
+	//			<len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC]>
+	//			<IP>
+	//			<len, [CTA_IP_V4_DST|CTA_IP_V6_DST]>
+	//			<IP>
+	//		<len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO>
+	//			<len, CTA_PROTO_NUM>
+	//			<uint8>
+	//			<len, CTA_PROTO_SRC_PORT>
+	//			<BEuint16>
+	//			<len, CTA_PROTO_DST_PORT>
+	//			<BEuint16>
+	// 	<len, NLA_F_NESTED|CTA_TUPLE_REPLY>
+	//		<len, NLA_F_NESTED|CTA_TUPLE_IP>
+	//			<len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC]>
+	//			<IP>
+	//			<len, [CTA_IP_V4_DST|CTA_IP_V6_DST]>
+	//			<IP>
+	//		<len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO>
+	//			<len, CTA_PROTO_NUM>
+	//			<uint8>
+	//			<len, CTA_PROTO_SRC_PORT>
+	//			<BEuint16>
+	//			<len, CTA_PROTO_DST_PORT>
+	//			<BEuint16>
+	//	<len, CTA_STATUS>
+	//	<uint64>
+	//	<len, CTA_MARK>
+	//	<BEuint64>
+	//	<len, CTA_TIMEOUT>
+	//	<BEuint64>
+	//	<len, NLA_F_NESTED|CTA_PROTOINFO>
+ 
+	// CTA_TUPLE_ORIG
+	ctTupleOrig := nl.NewRtAttr(unix.NLA_F_NESTED|nl.CTA_TUPLE_ORIG, nil)
+	forwardFlowAttrs, err := s.Forward.toNlData(s.FamilyType)
+	if err != nil {
+		return nil, fmt.Errorf("couldn't generate netlink data for conntrack forward flow: %w", err)
+	}
+	for _, a := range forwardFlowAttrs {
+		ctTupleOrig.AddChild(a)
+	}
+
+	// CTA_TUPLE_REPLY
+	ctTupleReply := nl.NewRtAttr(unix.NLA_F_NESTED|nl.CTA_TUPLE_REPLY, nil)
+	reverseFlowAttrs, err := s.Reverse.toNlData(s.FamilyType)
+	if err != nil {
+		return nil, fmt.Errorf("couldn't generate netlink data for conntrack reverse flow: %w", err)
+	}
+	for _, a := range reverseFlowAttrs {
+		ctTupleReply.AddChild(a)
+	}
+
+	ctMark := nl.NewRtAttr(nl.CTA_MARK, nl.BEUint32Attr(s.Mark))
+	ctTimeout := nl.NewRtAttr(nl.CTA_TIMEOUT, nl.BEUint32Attr(s.TimeOut))
+
+	payload = append(payload, ctTupleOrig, ctTupleReply, ctMark, ctTimeout)
+
+	if s.ProtoInfo != nil {
+		switch p := s.ProtoInfo.(type) {
+		case *ProtoInfoTCP:
+			attrs, err := p.toNlData()
+			if err != nil {
+				return nil, fmt.Errorf("couldn't generate netlink data for conntrack flow's TCP protoinfo: %w", err)
+			}
+			payload = append(payload, attrs...)
+		default:
+			return nil, errors.New("couldn't generate netlink data for conntrack: field 'ProtoInfo' only supports TCP or nil")
+		}
+	}
+
+	return payload, nil
+}
+
 // This method parse the ip tuple structure
 // The message structure is the following:
 // <len, [CTA_IP_V4_SRC|CTA_IP_V6_SRC], 16 bytes for the IP>
@@ -182,7 +406,7 @@ func (s *ConntrackFlow) String() string {
 // <len, NLA_F_NESTED|nl.CTA_TUPLE_PROTO, 1 byte for the protocol, 3 bytes of padding>
 // <len, CTA_PROTO_SRC_PORT, 2 bytes for the source port, 2 bytes of padding>
 // <len, CTA_PROTO_DST_PORT, 2 bytes for the source port, 2 bytes of padding>
-func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
+func parseIpTuple(reader *bytes.Reader, tpl *IPTuple) uint8 {
 	for i := 0; i < 2; i++ {
 		_, t, _, v := parseNfAttrTLV(reader)
 		switch t {
@@ -201,7 +425,7 @@ func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
 		tpl.Protocol = uint8(v[0])
 	}
 	// We only parse TCP & UDP headers. Skip the others.
-	if tpl.Protocol != 6 && tpl.Protocol != 17 {
+	if tpl.Protocol != unix.IPPROTO_TCP && tpl.Protocol != unix.IPPROTO_UDP {
 		// skip the rest
 		bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
 		reader.Seek(int64(bytesRemaining), seekCurrent)
@@ -250,9 +474,13 @@ func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
 	return isNested, attrType, len
 }
 
-func skipNfAttrValue(r *bytes.Reader, len uint16) {
+// skipNfAttrValue seeks `r` past attr of length `len`.
+// Maintains buffer alignment.
+// Returns length of the seek performed.
+func skipNfAttrValue(r *bytes.Reader, len uint16) uint16 {
 	len = (len + nl.NLA_ALIGNTO - 1) & ^(nl.NLA_ALIGNTO - 1)
 	r.Seek(int64(len), seekCurrent)
+	return len
 }
 
 func parseBERaw16(r *bytes.Reader, v *uint16) {
@@ -267,6 +495,10 @@ func parseBERaw64(r *bytes.Reader, v *uint64) {
 	binary.Read(r, binary.BigEndian, v)
 }
 
+func parseRaw32(r *bytes.Reader, v *uint32) {
+	binary.Read(r, nl.NativeEndian(), v)
+}
+
 func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
 	for i := 0; i < 2; i++ {
 		switch _, t, _ := parseNfAttrTL(r); t {
@@ -306,6 +538,60 @@ func parseTimeStamp(r *bytes.Reader, readSize uint16) (tstart, tstop uint64) {
 
 }
 
+func parseProtoInfoTCPState(r *bytes.Reader) (s uint8) {
+	binary.Read(r, binary.BigEndian, &s)
+	r.Seek(nl.SizeofNfattr - 1, seekCurrent)
+	return s
+}
+
+// parseProtoInfoTCP reads the entire nested protoinfo structure, but only parses the state attr.
+func parseProtoInfoTCP(r *bytes.Reader, attrLen uint16) (*ProtoInfoTCP) {
+	p := new(ProtoInfoTCP)
+	bytesRead := 0
+	for bytesRead < int(attrLen) {
+		_, t, l := parseNfAttrTL(r)
+		bytesRead += nl.SizeofNfattr
+
+		switch t {
+		case nl.CTA_PROTOINFO_TCP_STATE:
+			p.State = parseProtoInfoTCPState(r)
+			bytesRead += nl.SizeofNfattr
+		default:
+			bytesRead += int(skipNfAttrValue(r, l))
+		}
+	}
+
+	return p
+}
+
+func parseProtoInfo(r *bytes.Reader, attrLen uint16) (p ProtoInfo) {
+	bytesRead := 0
+	for bytesRead < int(attrLen) {
+		_, t, l := parseNfAttrTL(r)
+		bytesRead += nl.SizeofNfattr
+
+		switch t {
+		case nl.CTA_PROTOINFO_TCP:
+			p = parseProtoInfoTCP(r, l)
+			bytesRead += int(l)
+		// No inner fields of DCCP / SCTP currently supported.
+		case nl.CTA_PROTOINFO_DCCP:
+			p = new(ProtoInfoDCCP)
+			skipped := skipNfAttrValue(r, l)
+			bytesRead += int(skipped)
+		case nl.CTA_PROTOINFO_SCTP:
+			p = new(ProtoInfoSCTP)
+			skipped := skipNfAttrValue(r, l)
+			bytesRead += int(skipped)
+		default:
+			skipped := skipNfAttrValue(r, l)
+			bytesRead += int(skipped)
+		}
+	}
+
+	return p
+}
+
 func parseTimeOut(r *bytes.Reader) (ttimeout uint32) {
 	parseBERaw32(r, &ttimeout)
 	return
@@ -365,7 +651,7 @@ func parseRawData(data []byte) *ConntrackFlow {
 			case nl.CTA_TIMESTAMP:
 				s.TimeStart, s.TimeStop = parseTimeStamp(reader, l)
 			case nl.CTA_PROTOINFO:
-				skipNfAttrValue(reader, l)
+				s.ProtoInfo = parseProtoInfo(reader, l)
 			default:
 				skipNfAttrValue(reader, l)
 			}
@@ -373,11 +659,11 @@ func parseRawData(data []byte) *ConntrackFlow {
 			switch t {
 			case nl.CTA_MARK:
 				s.Mark = parseConnectionMark(reader)
-			case nl.CTA_LABELS:
+				case nl.CTA_LABELS:
 				s.Labels = parseConnectionLabels(reader)
 			case nl.CTA_TIMEOUT:
 				s.TimeOut = parseTimeOut(reader)
-			case nl.CTA_STATUS, nl.CTA_USE, nl.CTA_ID:
+			case nl.CTA_ID, nl.CTA_STATUS, nl.CTA_USE:
 				skipNfAttrValue(reader, l)
 			case nl.CTA_ZONE:
 				s.Zone = parseConnectionZone(reader)
diff --git a/vendor/github.com/vishvananda/netlink/conntrack_unspecified.go b/vendor/github.com/vishvananda/netlink/conntrack_unspecified.go
index af7af799e..0049048dc 100644
--- a/vendor/github.com/vishvananda/netlink/conntrack_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/conntrack_unspecified.go
@@ -11,6 +11,9 @@ type InetFamily uint8
 // ConntrackFlow placeholder
 type ConntrackFlow struct{}
 
+// CustomConntrackFilter placeholder
+type CustomConntrackFilter struct{}
+
 // ConntrackFilter placeholder
 type ConntrackFilter struct{}
 
@@ -29,10 +32,18 @@ func ConntrackTableFlush(table ConntrackTableType) error {
 
 // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter
 // conntrack -D [table] parameters         Delete conntrack or expectation
+//
+// Deprecated: use [ConntrackDeleteFilters] instead.
 func ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
 	return 0, ErrNotImplemented
 }
 
+// ConntrackDeleteFilters deletes entries on the specified table matching any of the specified filters
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters ...CustomConntrackFilter) (uint, error) {
+	return 0, ErrNotImplemented
+}
+
 // ConntrackTableList returns the flow list of a table of a specific family using the netlink handle passed
 // conntrack -L [table] [options]          List conntrack or expectation table
 func (h *Handle) ConntrackTableList(table ConntrackTableType, family InetFamily) ([]*ConntrackFlow, error) {
@@ -48,6 +59,14 @@ func (h *Handle) ConntrackTableFlush(table ConntrackTableType) error {
 
 // ConntrackDeleteFilter deletes entries on the specified table on the base of the filter using the netlink handle passed
 // conntrack -D [table] parameters         Delete conntrack or expectation
+//
+// Deprecated: use [Handle.ConntrackDeleteFilters] instead.
 func (h *Handle) ConntrackDeleteFilter(table ConntrackTableType, family InetFamily, filter *ConntrackFilter) (uint, error) {
 	return 0, ErrNotImplemented
 }
+
+// ConntrackDeleteFilters deletes entries on the specified table matching any of the specified filters using the netlink handle passed
+// conntrack -D [table] parameters         Delete conntrack or expectation
+func (h *Handle) ConntrackDeleteFilters(table ConntrackTableType, family InetFamily, filters ...CustomConntrackFilter) (uint, error) {
+	return 0, ErrNotImplemented
+}
diff --git a/vendor/github.com/vishvananda/netlink/devlink_linux.go b/vendor/github.com/vishvananda/netlink/devlink_linux.go
index d98801dbb..45d8ee4b6 100644
--- a/vendor/github.com/vishvananda/netlink/devlink_linux.go
+++ b/vendor/github.com/vishvananda/netlink/devlink_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"strings"
@@ -466,6 +467,8 @@ func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
 
 // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
 // otherwise returns an error code.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
 	if err != nil {
@@ -478,9 +481,9 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 	req := h.newNetlinkRequest(int(f.ID),
 		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
 	req.AddData(msg)
-	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	devices, err := parseDevLinkDeviceList(msgs)
 	if err != nil {
@@ -489,11 +492,14 @@ func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 	for _, d := range devices {
 		h.getEswitchAttrs(f, d)
 	}
-	return devices, nil
+	return devices, executeErr
 }
 
 // DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
 // otherwise returns an error code.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
 	return pkgHandle.DevLinkGetDeviceList()
 }
@@ -646,6 +652,8 @@ func parseDevLinkAllPortList(msgs [][]byte) ([]*DevlinkPort, error) {
 
 // DevLinkGetPortList provides a pointer to devlink ports and nil error,
 // otherwise returns an error code.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
 	f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
 	if err != nil {
@@ -658,19 +666,21 @@ func (h *Handle) DevLinkGetAllPortList() ([]*DevlinkPort, error) {
 	req := h.newNetlinkRequest(int(f.ID),
 		unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
 	req.AddData(msg)
-	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	ports, err := parseDevLinkAllPortList(msgs)
 	if err != nil {
 		return nil, err
 	}
-	return ports, nil
+	return ports, executeErr
 }
 
 // DevLinkGetPortList provides a pointer to devlink ports and nil error,
 // otherwise returns an error code.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func DevLinkGetAllPortList() ([]*DevlinkPort, error) {
 	return pkgHandle.DevLinkGetAllPortList()
 }
@@ -738,15 +748,18 @@ func (h *Handle) DevlinkGetDeviceResources(bus string, device string) (*DevlinkR
 
 // DevlinkGetDeviceParams returns parameters for devlink device
 // Equivalent to: `devlink dev param show <bus>/<device>`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
 	_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PARAM_GET, bus, device)
 	if err != nil {
 		return nil, err
 	}
 	req.Flags |= unix.NLM_F_DUMP
-	respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return nil, err
+	respmsg, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	var params []*DevlinkParam
 	for _, m := range respmsg {
@@ -761,11 +774,14 @@ func (h *Handle) DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkPa
 		params = append(params, p)
 	}
 
-	return params, nil
+	return params, executeErr
 }
 
 // DevlinkGetDeviceParams returns parameters for devlink device
 // Equivalent to: `devlink dev param show <bus>/<device>`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func DevlinkGetDeviceParams(bus string, device string) ([]*DevlinkParam, error) {
 	return pkgHandle.DevlinkGetDeviceParams(bus, device)
 }
diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go
index 87cd18f8e..19306612e 100644
--- a/vendor/github.com/vishvananda/netlink/filter_linux.go
+++ b/vendor/github.com/vishvananda/netlink/filter_linux.go
@@ -405,14 +405,20 @@ func (h *Handle) filterModify(filter Filter, proto, flags int) error {
 
 // FilterList gets a list of filters in the system.
 // Equivalent to: `tc filter show`.
+//
 // Generally returns nothing if link and parent are not specified.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func FilterList(link Link, parent uint32) ([]Filter, error) {
 	return pkgHandle.FilterList(link, parent)
 }
 
 // FilterList gets a list of filters in the system.
 // Equivalent to: `tc filter show`.
+//
 // Generally returns nothing if link and parent are not specified.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
 	msg := &nl.TcMsg{
@@ -426,9 +432,9 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
 	}
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Filter
@@ -516,7 +522,7 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
 		}
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func toTcGen(attrs *ActionAttrs, tcgen *nl.TcGen) {
@@ -920,9 +926,11 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
 				actionnStatistic = (*ActionStatistic)(s)
 			}
 		}
-		action.Attrs().Statistics = actionnStatistic
-		action.Attrs().Timestamp = actionTimestamp
-		actions = append(actions, action)
+		if action != nil {
+			action.Attrs().Statistics = actionnStatistic
+			action.Attrs().Timestamp = actionTimestamp
+			actions = append(actions, action)
+		}
 	}
 	return actions, nil
 }
diff --git a/vendor/github.com/vishvananda/netlink/fou.go b/vendor/github.com/vishvananda/netlink/fou.go
index 71e73c37a..ea9f6cf67 100644
--- a/vendor/github.com/vishvananda/netlink/fou.go
+++ b/vendor/github.com/vishvananda/netlink/fou.go
@@ -1,16 +1,7 @@
 package netlink
 
 import (
-	"errors"
-)
-
-var (
-	// ErrAttrHeaderTruncated is returned when a netlink attribute's header is
-	// truncated.
-	ErrAttrHeaderTruncated = errors.New("attribute header truncated")
-	// ErrAttrBodyTruncated is returned when a netlink attribute's body is
-	// truncated.
-	ErrAttrBodyTruncated = errors.New("attribute body truncated")
+	"net"
 )
 
 type Fou struct {
@@ -18,4 +9,8 @@ type Fou struct {
 	Port      int
 	Protocol  int
 	EncapType int
+	Local     net.IP
+	Peer      net.IP
+	PeerPort  int
+	IfIndex   int
 }
diff --git a/vendor/github.com/vishvananda/netlink/fou_linux.go b/vendor/github.com/vishvananda/netlink/fou_linux.go
index ed55b2b79..7645a5a5c 100644
--- a/vendor/github.com/vishvananda/netlink/fou_linux.go
+++ b/vendor/github.com/vishvananda/netlink/fou_linux.go
@@ -1,3 +1,4 @@
+//go:build linux
 // +build linux
 
 package netlink
@@ -5,6 +6,8 @@ package netlink
 import (
 	"encoding/binary"
 	"errors"
+	"log"
+	"net"
 
 	"github.com/vishvananda/netlink/nl"
 	"golang.org/x/sys/unix"
@@ -29,6 +32,12 @@ const (
 	FOU_ATTR_IPPROTO
 	FOU_ATTR_TYPE
 	FOU_ATTR_REMCSUM_NOPARTIAL
+	FOU_ATTR_LOCAL_V4
+	FOU_ATTR_LOCAL_V6
+	FOU_ATTR_PEER_V4
+	FOU_ATTR_PEER_V6
+	FOU_ATTR_PEER_PORT
+	FOU_ATTR_IFINDEX
 	FOU_ATTR_MAX = FOU_ATTR_REMCSUM_NOPARTIAL
 )
 
@@ -128,10 +137,14 @@ func (h *Handle) FouDel(f Fou) error {
 	return nil
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func FouList(fam int) ([]Fou, error) {
 	return pkgHandle.FouList(fam)
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) FouList(fam int) ([]Fou, error) {
 	fam_id, err := FouFamilyId()
 	if err != nil {
@@ -150,9 +163,9 @@ func (h *Handle) FouList(fam int) ([]Fou, error) {
 
 	req.AddRawData(raw)
 
-	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	fous := make([]Fou, 0, len(msgs))
@@ -165,45 +178,32 @@ func (h *Handle) FouList(fam int) ([]Fou, error) {
 		fous = append(fous, f)
 	}
 
-	return fous, nil
+	return fous, executeErr
 }
 
 func deserializeFouMsg(msg []byte) (Fou, error) {
-	// we'll skip to byte 4 to first attribute
-	msg = msg[3:]
-	var shift int
 	fou := Fou{}
 
-	for {
-		// attribute header is at least 16 bits
-		if len(msg) < 4 {
-			return fou, ErrAttrHeaderTruncated
-		}
-
-		lgt := int(binary.BigEndian.Uint16(msg[0:2]))
-		if len(msg) < lgt+4 {
-			return fou, ErrAttrBodyTruncated
-		}
-		attr := binary.BigEndian.Uint16(msg[2:4])
-
-		shift = lgt + 3
-		switch attr {
+	for attr := range nl.ParseAttributes(msg[4:]) {
+		switch attr.Type {
 		case FOU_ATTR_AF:
-			fou.Family = int(msg[5])
+			fou.Family = int(attr.Value[0])
 		case FOU_ATTR_PORT:
-			fou.Port = int(binary.BigEndian.Uint16(msg[5:7]))
-			// port is 2 bytes
-			shift = lgt + 2
+			fou.Port = int(networkOrder.Uint16(attr.Value))
 		case FOU_ATTR_IPPROTO:
-			fou.Protocol = int(msg[5])
+			fou.Protocol = int(attr.Value[0])
 		case FOU_ATTR_TYPE:
-			fou.EncapType = int(msg[5])
-		}
-
-		msg = msg[shift:]
-
-		if len(msg) < 4 {
-			break
+			fou.EncapType = int(attr.Value[0])
+		case FOU_ATTR_LOCAL_V4, FOU_ATTR_LOCAL_V6:
+			fou.Local = net.IP(attr.Value)
+		case FOU_ATTR_PEER_V4, FOU_ATTR_PEER_V6:
+			fou.Peer = net.IP(attr.Value)
+		case FOU_ATTR_PEER_PORT:
+			fou.PeerPort = int(networkOrder.Uint16(attr.Value))
+		case FOU_ATTR_IFINDEX:
+			fou.IfIndex = int(native.Uint16(attr.Value))
+		default:
+			log.Printf("unknown fou attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
 		}
 	}
 
diff --git a/vendor/github.com/vishvananda/netlink/fou_unspecified.go b/vendor/github.com/vishvananda/netlink/fou_unspecified.go
index 3a8365bfe..7e550151a 100644
--- a/vendor/github.com/vishvananda/netlink/fou_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/fou_unspecified.go
@@ -1,3 +1,4 @@
+//go:build !linux
 // +build !linux
 
 package netlink
diff --git a/vendor/github.com/vishvananda/netlink/genetlink_linux.go b/vendor/github.com/vishvananda/netlink/genetlink_linux.go
index 772e5834a..7bdaad97b 100644
--- a/vendor/github.com/vishvananda/netlink/genetlink_linux.go
+++ b/vendor/github.com/vishvananda/netlink/genetlink_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"syscall"
 
@@ -126,6 +127,8 @@ func parseFamilies(msgs [][]byte) ([]*GenlFamily, error) {
 	return families, nil
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
 	msg := &nl.Genlmsg{
 		Command: nl.GENL_CTRL_CMD_GETFAMILY,
@@ -133,13 +136,19 @@ func (h *Handle) GenlFamilyList() ([]*GenlFamily, error) {
 	}
 	req := h.newNetlinkRequest(nl.GENL_ID_CTRL, unix.NLM_F_DUMP)
 	req.AddData(msg)
-	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
+	}
+	families, err := parseFamilies(msgs)
 	if err != nil {
 		return nil, err
 	}
-	return parseFamilies(msgs)
+	return families, executeErr
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func GenlFamilyList() ([]*GenlFamily, error) {
 	return pkgHandle.GenlFamilyList()
 }
diff --git a/vendor/github.com/vishvananda/netlink/gtp_linux.go b/vendor/github.com/vishvananda/netlink/gtp_linux.go
index f5e160ba5..377dcae5c 100644
--- a/vendor/github.com/vishvananda/netlink/gtp_linux.go
+++ b/vendor/github.com/vishvananda/netlink/gtp_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"strings"
@@ -74,6 +75,8 @@ func parsePDP(msgs [][]byte) ([]*PDP, error) {
 	return pdps, nil
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) GTPPDPList() ([]*PDP, error) {
 	f, err := h.GenlFamilyGet(nl.GENL_GTP_NAME)
 	if err != nil {
@@ -85,13 +88,19 @@ func (h *Handle) GTPPDPList() ([]*PDP, error) {
 	}
 	req := h.newNetlinkRequest(int(f.ID), unix.NLM_F_DUMP)
 	req.AddData(msg)
-	msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+	msgs, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(err, ErrDumpInterrupted) {
+		return nil, executeErr
+	}
+	pdps, err := parsePDP(msgs)
 	if err != nil {
 		return nil, err
 	}
-	return parsePDP(msgs)
+	return pdps, executeErr
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func GTPPDPList() ([]*PDP, error) {
 	return pkgHandle.GTPPDPList()
 }
diff --git a/vendor/github.com/vishvananda/netlink/inet_diag.go b/vendor/github.com/vishvananda/netlink/inet_diag.go
index a483ee1a1..2904d9642 100644
--- a/vendor/github.com/vishvananda/netlink/inet_diag.go
+++ b/vendor/github.com/vishvananda/netlink/inet_diag.go
@@ -21,6 +21,10 @@ const (
 	INET_DIAG_BBRINFO
 	INET_DIAG_CLASS_ID
 	INET_DIAG_MD5SIG
+	INET_DIAG_ULP_INFO
+	INET_DIAG_SK_BPF_STORAGES
+	INET_DIAG_CGROUP_ID
+	INET_DIAG_SOCKOPT
 	INET_DIAG_MAX
 )
 
diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go
index 28780d118..e09a6cfe5 100644
--- a/vendor/github.com/vishvananda/netlink/link.go
+++ b/vendor/github.com/vishvananda/netlink/link.go
@@ -274,6 +274,7 @@ type Bridge struct {
 	HelloTime         *uint32
 	VlanFiltering     *bool
 	VlanDefaultPVID   *uint16
+	GroupFwdMask      *uint16
 }
 
 func (bridge *Bridge) Attrs() *LinkAttrs {
@@ -317,6 +318,9 @@ type Macvlan struct {
 
 	// MACAddrs is only populated for Macvlan SOURCE links
 	MACAddrs []net.HardwareAddr
+
+	BCQueueLen     uint32
+	UsedBCQueueLen uint32
 }
 
 func (macvlan *Macvlan) Attrs() *LinkAttrs {
@@ -373,6 +377,13 @@ const (
 	NETKIT_POLICY_BLACKHOLE NetkitPolicy = 2
 )
 
+type NetkitScrub int
+
+const (
+	NETKIT_SCRUB_NONE    NetkitScrub = 0
+	NETKIT_SCRUB_DEFAULT NetkitScrub = 1
+)
+
 func (n *Netkit) IsPrimary() bool {
 	return n.isPrimary
 }
@@ -387,6 +398,9 @@ type Netkit struct {
 	Mode          NetkitMode
 	Policy        NetkitPolicy
 	PeerPolicy    NetkitPolicy
+	Scrub         NetkitScrub
+	PeerScrub     NetkitScrub
+	supportsScrub bool
 	isPrimary     bool
 	peerLinkAttrs LinkAttrs
 }
@@ -399,6 +413,10 @@ func (n *Netkit) Type() string {
 	return "netkit"
 }
 
+func (n *Netkit) SupportsScrub() bool {
+	return n.supportsScrub
+}
+
 // Veth devices must specify PeerName on create
 type Veth struct {
 	LinkAttrs
@@ -752,22 +770,25 @@ const (
 	BOND_XMIT_HASH_POLICY_LAYER2_3
 	BOND_XMIT_HASH_POLICY_ENCAP2_3
 	BOND_XMIT_HASH_POLICY_ENCAP3_4
+	BOND_XMIT_HASH_POLICY_VLAN_SRCMAC
 	BOND_XMIT_HASH_POLICY_UNKNOWN
 )
 
 var bondXmitHashPolicyToString = map[BondXmitHashPolicy]string{
-	BOND_XMIT_HASH_POLICY_LAYER2:   "layer2",
-	BOND_XMIT_HASH_POLICY_LAYER3_4: "layer3+4",
-	BOND_XMIT_HASH_POLICY_LAYER2_3: "layer2+3",
-	BOND_XMIT_HASH_POLICY_ENCAP2_3: "encap2+3",
-	BOND_XMIT_HASH_POLICY_ENCAP3_4: "encap3+4",
+	BOND_XMIT_HASH_POLICY_LAYER2:      "layer2",
+	BOND_XMIT_HASH_POLICY_LAYER3_4:    "layer3+4",
+	BOND_XMIT_HASH_POLICY_LAYER2_3:    "layer2+3",
+	BOND_XMIT_HASH_POLICY_ENCAP2_3:    "encap2+3",
+	BOND_XMIT_HASH_POLICY_ENCAP3_4:    "encap3+4",
+	BOND_XMIT_HASH_POLICY_VLAN_SRCMAC: "vlan+srcmac",
 }
 var StringToBondXmitHashPolicyMap = map[string]BondXmitHashPolicy{
-	"layer2":   BOND_XMIT_HASH_POLICY_LAYER2,
-	"layer3+4": BOND_XMIT_HASH_POLICY_LAYER3_4,
-	"layer2+3": BOND_XMIT_HASH_POLICY_LAYER2_3,
-	"encap2+3": BOND_XMIT_HASH_POLICY_ENCAP2_3,
-	"encap3+4": BOND_XMIT_HASH_POLICY_ENCAP3_4,
+	"layer2":      BOND_XMIT_HASH_POLICY_LAYER2,
+	"layer3+4":    BOND_XMIT_HASH_POLICY_LAYER3_4,
+	"layer2+3":    BOND_XMIT_HASH_POLICY_LAYER2_3,
+	"encap2+3":    BOND_XMIT_HASH_POLICY_ENCAP2_3,
+	"encap3+4":    BOND_XMIT_HASH_POLICY_ENCAP3_4,
+	"vlan+srcmac": BOND_XMIT_HASH_POLICY_VLAN_SRCMAC,
 }
 
 // BondLacpRate type
diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go
index 505d92d69..52491c580 100644
--- a/vendor/github.com/vishvananda/netlink/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/link_linux.go
@@ -3,6 +3,7 @@ package netlink
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"net"
@@ -1733,15 +1734,9 @@ func (h *Handle) linkModify(link Link, flags int) error {
 		data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
 		data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
 	case *Macvlan:
-		if link.Mode != MACVLAN_MODE_DEFAULT {
-			data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
-			data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
-		}
+		addMacvlanAttrs(link, linkInfo)
 	case *Macvtap:
-		if link.Mode != MACVLAN_MODE_DEFAULT {
-			data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
-			data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
-		}
+		addMacvtapAttrs(link, linkInfo)
 	case *Geneve:
 		addGeneveAttrs(link, linkInfo)
 	case *Gretap:
@@ -1813,20 +1808,20 @@ func (h *Handle) LinkDel(link Link) error {
 }
 
 func (h *Handle) linkByNameDump(name string) (Link, error) {
-	links, err := h.LinkList()
-	if err != nil {
-		return nil, err
+	links, executeErr := h.LinkList()
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	for _, link := range links {
 		if link.Attrs().Name == name {
-			return link, nil
+			return link, executeErr
 		}
 
 		// support finding interfaces also via altnames
 		for _, altName := range link.Attrs().AltNames {
 			if altName == name {
-				return link, nil
+				return link, executeErr
 			}
 		}
 	}
@@ -1834,25 +1829,33 @@ func (h *Handle) linkByNameDump(name string) (Link, error) {
 }
 
 func (h *Handle) linkByAliasDump(alias string) (Link, error) {
-	links, err := h.LinkList()
-	if err != nil {
-		return nil, err
+	links, executeErr := h.LinkList()
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	for _, link := range links {
 		if link.Attrs().Alias == alias {
-			return link, nil
+			return link, executeErr
 		}
 	}
 	return nil, LinkNotFoundError{fmt.Errorf("Link alias %s not found", alias)}
 }
 
 // LinkByName finds a link by name and returns a pointer to the object.
+//
+// If the kernel doesn't support IFLA_IFNAME, this method will fall back to
+// filtering a dump of all link names. In this case, if the returned error is
+// [ErrDumpInterrupted] the result may be missing or outdated.
 func LinkByName(name string) (Link, error) {
 	return pkgHandle.LinkByName(name)
 }
 
 // LinkByName finds a link by name and returns a pointer to the object.
+//
+// If the kernel doesn't support IFLA_IFNAME, this method will fall back to
+// filtering a dump of all link names. In this case, if the returned error is
+// [ErrDumpInterrupted] the result may be missing or outdated.
 func (h *Handle) LinkByName(name string) (Link, error) {
 	if h.lookupByDump {
 		return h.linkByNameDump(name)
@@ -1885,12 +1888,20 @@ func (h *Handle) LinkByName(name string) (Link, error) {
 
 // LinkByAlias finds a link by its alias and returns a pointer to the object.
 // If there are multiple links with the alias it returns the first one
+//
+// If the kernel doesn't support IFLA_IFALIAS, this method will fall back to
+// filtering a dump of all link names. In this case, if the returned error is
+// [ErrDumpInterrupted] the result may be missing or outdated.
 func LinkByAlias(alias string) (Link, error) {
 	return pkgHandle.LinkByAlias(alias)
 }
 
 // LinkByAlias finds a link by its alias and returns a pointer to the object.
 // If there are multiple links with the alias it returns the first one
+//
+// If the kernel doesn't support IFLA_IFALIAS, this method will fall back to
+// filtering a dump of all link names. In this case, if the returned error is
+// [ErrDumpInterrupted] the result may be missing or outdated.
 func (h *Handle) LinkByAlias(alias string) (Link, error) {
 	if h.lookupByDump {
 		return h.linkByAliasDump(alias)
@@ -1975,9 +1986,6 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
 	base.Flags = linkFlags(msg.Flags)
 	base.EncapType = msg.EncapType()
 	base.NetNsID = -1
-	if msg.Flags&unix.IFF_PROMISC != 0 {
-		base.Promisc = 1
-	}
 	if msg.Flags&unix.IFF_ALLMULTI != 0 {
 		base.Allmulti = 1
 	}
@@ -2164,6 +2172,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
 			base.Name = string(attr.Value[:len(attr.Value)-1])
 		case unix.IFLA_MTU:
 			base.MTU = int(native.Uint32(attr.Value[0:4]))
+		case unix.IFLA_PROMISCUITY:
+			base.Promisc = int(native.Uint32(attr.Value[0:4]))
 		case unix.IFLA_LINK:
 			base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
 		case unix.IFLA_MASTER:
@@ -2328,6 +2338,9 @@ func LinkList() ([]Link, error) {
 
 // LinkList gets a list of link devices.
 // Equivalent to: `ip link show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) LinkList() ([]Link, error) {
 	// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
 	//             to get the message ourselves to parse link type.
@@ -2338,9 +2351,9 @@ func (h *Handle) LinkList() ([]Link, error) {
 	attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
 	req.AddData(attr)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Link
@@ -2352,7 +2365,7 @@ func (h *Handle) LinkList() ([]Link, error) {
 		res = append(res, link)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 // LinkUpdate is used to pass information back from LinkSubscribe()
@@ -2388,6 +2401,10 @@ type LinkSubscribeOptions struct {
 // LinkSubscribeWithOptions work like LinkSubscribe but enable to
 // provide additional options to modify the behavior. Currently, the
 // namespace can be provided as well as an error callback.
+//
+// When options.ListExisting is true, options.ErrorCallback may be
+// called with [ErrDumpInterrupted] to indicate that results from
+// the initial dump of links may be inconsistent or incomplete.
 func LinkSubscribeWithOptions(ch chan<- LinkUpdate, done <-chan struct{}, options LinkSubscribeOptions) error {
 	if options.Namespace == nil {
 		none := netns.None()
@@ -2447,6 +2464,9 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
 				continue
 			}
 			for _, m := range msgs {
+				if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
+					cberr(ErrDumpInterrupted)
+				}
 				if m.Header.Type == unix.NLMSG_DONE {
 					continue
 				}
@@ -2494,6 +2514,16 @@ func (h *Handle) LinkSetGuard(link Link, mode bool) error {
 	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
 }
 
+// LinkSetBRSlaveGroupFwdMask set the group_fwd_mask of a bridge slave interface
+func LinkSetBRSlaveGroupFwdMask(link Link, mask uint16) error {
+	return pkgHandle.LinkSetBRSlaveGroupFwdMask(link, mask)
+}
+
+// LinkSetBRSlaveGroupFwdMask set the group_fwd_mask of a bridge slave interface
+func (h *Handle) LinkSetBRSlaveGroupFwdMask(link Link, mask uint16) error {
+	return h.setProtinfoAttrRawVal(link, nl.Uint16Attr(mask), nl.IFLA_BRPORT_GROUP_FWD_MASK)
+}
+
 func LinkSetFastLeave(link Link, mode bool) error {
 	return pkgHandle.LinkSetFastLeave(link, mode)
 }
@@ -2558,7 +2588,7 @@ func (h *Handle) LinkSetBrNeighSuppress(link Link, mode bool) error {
 	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_NEIGH_SUPPRESS)
 }
 
-func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
+func (h *Handle) setProtinfoAttrRawVal(link Link, val []byte, attr int) error {
 	base := link.Attrs()
 	h.ensureIndex(base)
 	req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
@@ -2568,7 +2598,7 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
 	req.AddData(msg)
 
 	br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil)
-	br.AddRtAttr(attr, boolToByte(mode))
+	br.AddRtAttr(attr, val)
 	req.AddData(br)
 	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
 	if err != nil {
@@ -2576,6 +2606,9 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
 	}
 	return nil
 }
+func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
+	return h.setProtinfoAttrRawVal(link, boolToByte(mode), attr)
+}
 
 // LinkSetTxQLen sets the transaction queue length for the link.
 // Equivalent to: `ip link set $link txqlen $qlen`
@@ -2643,6 +2676,8 @@ func addNetkitAttrs(nk *Netkit, linkInfo *nl.RtAttr, flag int) error {
 	data.AddRtAttr(nl.IFLA_NETKIT_MODE, nl.Uint32Attr(uint32(nk.Mode)))
 	data.AddRtAttr(nl.IFLA_NETKIT_POLICY, nl.Uint32Attr(uint32(nk.Policy)))
 	data.AddRtAttr(nl.IFLA_NETKIT_PEER_POLICY, nl.Uint32Attr(uint32(nk.PeerPolicy)))
+	data.AddRtAttr(nl.IFLA_NETKIT_SCRUB, nl.Uint32Attr(uint32(nk.Scrub)))
+	data.AddRtAttr(nl.IFLA_NETKIT_PEER_SCRUB, nl.Uint32Attr(uint32(nk.PeerScrub)))
 
 	if (flag & unix.NLM_F_EXCL) == 0 {
 		// Modifying peer link attributes will not take effect
@@ -2703,6 +2738,12 @@ func parseNetkitData(link Link, data []syscall.NetlinkRouteAttr) {
 			netkit.Policy = NetkitPolicy(native.Uint32(datum.Value[0:4]))
 		case nl.IFLA_NETKIT_PEER_POLICY:
 			netkit.PeerPolicy = NetkitPolicy(native.Uint32(datum.Value[0:4]))
+		case nl.IFLA_NETKIT_SCRUB:
+			netkit.supportsScrub = true
+			netkit.Scrub = NetkitScrub(native.Uint32(datum.Value[0:4]))
+		case nl.IFLA_NETKIT_PEER_SCRUB:
+			netkit.supportsScrub = true
+			netkit.PeerScrub = NetkitScrub(native.Uint32(datum.Value[0:4]))
 		}
 	}
 }
@@ -2941,11 +2982,30 @@ func parseIPVtapData(link Link, data []syscall.NetlinkRouteAttr) {
 	}
 }
 
+func addMacvtapAttrs(macvtap *Macvtap, linkInfo *nl.RtAttr) {
+	addMacvlanAttrs(&macvtap.Macvlan, linkInfo)
+}
+
 func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
 	macv := link.(*Macvtap)
 	parseMacvlanData(&macv.Macvlan, data)
 }
 
+func addMacvlanAttrs(macvlan *Macvlan, linkInfo *nl.RtAttr) {
+	var data *nl.RtAttr
+
+	if macvlan.Mode != MACVLAN_MODE_DEFAULT || macvlan.BCQueueLen > 0 {
+		data = linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+	}
+
+	if macvlan.Mode != MACVLAN_MODE_DEFAULT {
+		data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macvlan.Mode]))
+	}
+	if macvlan.BCQueueLen > 0 {
+		data.AddRtAttr(nl.IFLA_MACVLAN_BC_QUEUE_LEN, nl.Uint32Attr(macvlan.BCQueueLen))
+	}
+}
+
 func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
 	macv := link.(*Macvlan)
 	for _, datum := range data {
@@ -2973,6 +3033,10 @@ func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
 			for _, macDatum := range macs {
 				macv.MACAddrs = append(macv.MACAddrs, net.HardwareAddr(macDatum.Value[0:6]))
 			}
+		case nl.IFLA_MACVLAN_BC_QUEUE_LEN:
+			macv.BCQueueLen = native.Uint32(datum.Value[0:4])
+		case nl.IFLA_MACVLAN_BC_QUEUE_LEN_USED:
+			macv.UsedBCQueueLen = native.Uint32(datum.Value[0:4])
 		}
 	}
 }
@@ -3541,6 +3605,9 @@ func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) {
 	if bridge.VlanDefaultPVID != nil {
 		data.AddRtAttr(nl.IFLA_BR_VLAN_DEFAULT_PVID, nl.Uint16Attr(*bridge.VlanDefaultPVID))
 	}
+	if bridge.GroupFwdMask != nil {
+		data.AddRtAttr(nl.IFLA_BR_GROUP_FWD_MASK, nl.Uint16Attr(*bridge.GroupFwdMask))
+	}
 }
 
 func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
@@ -3562,6 +3629,9 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
 		case nl.IFLA_BR_VLAN_DEFAULT_PVID:
 			vlanDefaultPVID := native.Uint16(datum.Value[0:2])
 			br.VlanDefaultPVID = &vlanDefaultPVID
+		case nl.IFLA_BR_GROUP_FWD_MASK:
+			mask := native.Uint16(datum.Value[0:2])
+			br.GroupFwdMask = &mask
 		}
 	}
 }
@@ -3686,8 +3756,7 @@ func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) {
 	}
 }
 
-// LinkSetBondSlave add slave to bond link via ioctl interface.
-func LinkSetBondSlave(link Link, master *Bond) error {
+func ioctlBondSlave(cmd uintptr, link Link, master *Bond) error {
 	fd, err := getSocketUDP()
 	if err != nil {
 		return err
@@ -3695,10 +3764,38 @@ func LinkSetBondSlave(link Link, master *Bond) error {
 	defer syscall.Close(fd)
 
 	ifreq := newIocltSlaveReq(link.Attrs().Name, master.Attrs().Name)
-
-	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), unix.SIOCBONDENSLAVE, uintptr(unsafe.Pointer(ifreq)))
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(ifreq)))
 	if errno != 0 {
-		return fmt.Errorf("Failed to enslave %q to %q, errno=%v", link.Attrs().Name, master.Attrs().Name, errno)
+		return fmt.Errorf("errno=%v", errno)
+	}
+	return nil
+}
+
+// LinkSetBondSlaveActive sets specified slave to ACTIVE in an `active-backup` bond link via ioctl interface.
+//
+//	Multiple calls keeps the status unchanged(shown in the unit test).
+func LinkSetBondSlaveActive(link Link, master *Bond) error {
+	err := ioctlBondSlave(unix.SIOCBONDCHANGEACTIVE, link, master)
+	if err != nil {
+		return fmt.Errorf("Failed to set slave %q active in %q, %v", link.Attrs().Name, master.Attrs().Name, err)
+	}
+	return nil
+}
+
+// LinkSetBondSlave add slave to bond link via ioctl interface.
+func LinkSetBondSlave(link Link, master *Bond) error {
+	err := ioctlBondSlave(unix.SIOCBONDENSLAVE, link, master)
+	if err != nil {
+		return fmt.Errorf("Failed to enslave %q to %q, %v", link.Attrs().Name, master.Attrs().Name, err)
+	}
+	return nil
+}
+
+// LinkSetBondSlave removes specified slave from bond link via ioctl interface.
+func LinkDelBondSlave(link Link, master *Bond) error {
+	err := ioctlBondSlave(unix.SIOCBONDRELEASE, link, master)
+	if err != nil {
+		return fmt.Errorf("Failed to del slave %q from %q, %v", link.Attrs().Name, master.Attrs().Name, err)
 	}
 	return nil
 }
diff --git a/vendor/github.com/vishvananda/netlink/neigh_linux.go b/vendor/github.com/vishvananda/netlink/neigh_linux.go
index 2d93044a6..1c6f2958a 100644
--- a/vendor/github.com/vishvananda/netlink/neigh_linux.go
+++ b/vendor/github.com/vishvananda/netlink/neigh_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"syscall"
@@ -206,6 +207,9 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
 // NeighList returns a list of IP-MAC mappings in the system (ARP table).
 // Equivalent to: `ip neighbor show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func NeighList(linkIndex, family int) ([]Neigh, error) {
 	return pkgHandle.NeighList(linkIndex, family)
 }
@@ -213,6 +217,9 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
 // NeighProxyList returns a list of neighbor proxies in the system.
 // Equivalent to: `ip neighbor show proxy`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 	return pkgHandle.NeighProxyList(linkIndex, family)
 }
@@ -220,6 +227,9 @@ func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 // NeighList returns a list of IP-MAC mappings in the system (ARP table).
 // Equivalent to: `ip neighbor show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
 	return h.NeighListExecute(Ndmsg{
 		Family: uint8(family),
@@ -230,6 +240,9 @@ func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
 // NeighProxyList returns a list of neighbor proxies in the system.
 // Equivalent to: `ip neighbor show proxy`.
 // The list can be filtered by link, ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 	return h.NeighListExecute(Ndmsg{
 		Family: uint8(family),
@@ -239,18 +252,24 @@ func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
 }
 
 // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 	return pkgHandle.NeighListExecute(msg)
 }
 
 // NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
 	req.AddData(&msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Neigh
@@ -281,7 +300,7 @@ func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
 		res = append(res, *neigh)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func NeighDeserialize(m []byte) (*Neigh, error) {
@@ -364,6 +383,10 @@ type NeighSubscribeOptions struct {
 // NeighSubscribeWithOptions work like NeighSubscribe but enable to
 // provide additional options to modify the behavior. Currently, the
 // namespace can be provided as well as an error callback.
+//
+// When options.ListExisting is true, options.ErrorCallback may be
+// called with [ErrDumpInterrupted] to indicate that results from
+// the initial dump of links may be inconsistent or incomplete.
 func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
 	if options.Namespace == nil {
 		none := netns.None()
@@ -428,6 +451,9 @@ func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <
 				continue
 			}
 			for _, m := range msgs {
+				if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
+					cberr(ErrDumpInterrupted)
+				}
 				if m.Header.Type == unix.NLMSG_DONE {
 					if listExisting {
 						// This will be called after handling AF_UNSPEC
diff --git a/vendor/github.com/vishvananda/netlink/netlink_linux.go b/vendor/github.com/vishvananda/netlink/netlink_linux.go
index a20d293d8..7416e3051 100644
--- a/vendor/github.com/vishvananda/netlink/netlink_linux.go
+++ b/vendor/github.com/vishvananda/netlink/netlink_linux.go
@@ -9,3 +9,6 @@ const (
 	FAMILY_V6   = nl.FAMILY_V6
 	FAMILY_MPLS = nl.FAMILY_MPLS
 )
+
+// ErrDumpInterrupted is an alias for [nl.ErrDumpInterrupted].
+var ErrDumpInterrupted = nl.ErrDumpInterrupted
diff --git a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
index eb3e1c16f..6989d1edc 100644
--- a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
@@ -15,6 +15,38 @@ var L4ProtoMap = map[uint8]string{
 	17: "udp",
 }
 
+// From https://git.netfilter.org/libnetfilter_conntrack/tree/include/libnetfilter_conntrack/libnetfilter_conntrack_tcp.h
+//	 enum tcp_state {
+//		TCP_CONNTRACK_NONE,
+//		TCP_CONNTRACK_SYN_SENT,
+//		TCP_CONNTRACK_SYN_RECV,
+//		TCP_CONNTRACK_ESTABLISHED,
+//		TCP_CONNTRACK_FIN_WAIT,
+//		TCP_CONNTRACK_CLOSE_WAIT,
+//		TCP_CONNTRACK_LAST_ACK,
+//		TCP_CONNTRACK_TIME_WAIT,
+//		TCP_CONNTRACK_CLOSE,
+//		TCP_CONNTRACK_LISTEN,		/* obsolete */
+//	#define TCP_CONNTRACK_SYN_SENT2		TCP_CONNTRACK_LISTEN
+//		TCP_CONNTRACK_MAX,
+//		TCP_CONNTRACK_IGNORE
+//	 };
+const (
+		TCP_CONNTRACK_NONE = 0
+		TCP_CONNTRACK_SYN_SENT = 1
+		TCP_CONNTRACK_SYN_RECV = 2
+		TCP_CONNTRACK_ESTABLISHED = 3
+		TCP_CONNTRACK_FIN_WAIT = 4
+		TCP_CONNTRACK_CLOSE_WAIT = 5
+		TCP_CONNTRACK_LAST_ACK = 6
+		TCP_CONNTRACK_TIME_WAIT = 7
+		TCP_CONNTRACK_CLOSE = 8
+		TCP_CONNTRACK_LISTEN = 9
+		TCP_CONNTRACK_SYN_SENT2 = 9
+		TCP_CONNTRACK_MAX = 10
+		TCP_CONNTRACK_IGNORE = 11
+)
+
 // All the following constants are coming from:
 // https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink_conntrack.h
 
@@ -31,6 +63,7 @@ var L4ProtoMap = map[uint8]string{
 // 	IPCTNL_MSG_MAX
 // };
 const (
+	IPCTNL_MSG_CT_NEW = 0
 	IPCTNL_MSG_CT_GET    = 1
 	IPCTNL_MSG_CT_DELETE = 2
 )
@@ -91,6 +124,7 @@ const (
 	CTA_ZONE           = 18
 	CTA_TIMESTAMP      = 20
 	CTA_LABELS         = 22
+	CTA_LABELS_MASK    = 23
 )
 
 // enum ctattr_tuple {
@@ -151,7 +185,10 @@ const (
 // };
 // #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
 const (
+	CTA_PROTOINFO_UNSPEC = 0
 	CTA_PROTOINFO_TCP = 1
+	CTA_PROTOINFO_DCCP = 2
+	CTA_PROTOINFO_SCTP = 3
 )
 
 // enum ctattr_protoinfo_tcp {
diff --git a/vendor/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
index 9492c5c73..6dfa16cc2 100644
--- a/vendor/github.com/vishvananda/netlink/nl/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
@@ -38,6 +38,8 @@ const (
 	IFLA_NETKIT_POLICY
 	IFLA_NETKIT_PEER_POLICY
 	IFLA_NETKIT_MODE
+	IFLA_NETKIT_SCRUB
+	IFLA_NETKIT_PEER_SCRUB
 	IFLA_NETKIT_MAX = IFLA_NETKIT_MODE
 )
 
@@ -144,7 +146,9 @@ const (
 	IFLA_MACVLAN_MACADDR
 	IFLA_MACVLAN_MACADDR_DATA
 	IFLA_MACVLAN_MACADDR_COUNT
-	IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
+	IFLA_MACVLAN_BC_QUEUE_LEN
+	IFLA_MACVLAN_BC_QUEUE_LEN_USED
+	IFLA_MACVLAN_MAX = IFLA_MACVLAN_BC_QUEUE_LEN_USED
 )
 
 const (
@@ -321,7 +325,7 @@ const (
 const (
 	SizeofVfMac        = 0x24
 	SizeofVfVlan       = 0x0c
-	SizeofVfVlanInfo   = 0x0e
+	SizeofVfVlanInfo   = 0x10
 	SizeofVfTxRate     = 0x08
 	SizeofVfRate       = 0x0c
 	SizeofVfSpoofchk   = 0x08
diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
index c0cef5a19..4d2732a9e 100644
--- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
@@ -4,12 +4,15 @@ package nl
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"net"
+	"os"
 	"runtime"
 	"sync"
 	"sync/atomic"
 	"syscall"
+	"time"
 	"unsafe"
 
 	"github.com/vishvananda/netns"
@@ -42,6 +45,26 @@ var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0}
 // ErrorMessageReporting is the default error message reporting configuration for the new netlink sockets
 var EnableErrorMessageReporting bool = false
 
+// ErrDumpInterrupted is an instance of errDumpInterrupted, used to report that
+// a netlink function has set the NLM_F_DUMP_INTR flag in a response message,
+// indicating that the results may be incomplete or inconsistent.
+var ErrDumpInterrupted = errDumpInterrupted{}
+
+// errDumpInterrupted is an error type, used to report that NLM_F_DUMP_INTR was
+// set in a netlink response.
+type errDumpInterrupted struct{}
+
+func (errDumpInterrupted) Error() string {
+	return "results may be incomplete or inconsistent"
+}
+
+// Before errDumpInterrupted was introduced, EINTR was returned when a netlink
+// response had NLM_F_DUMP_INTR. Retain backward compatibility with code that
+// may be checking for EINTR using Is.
+func (e errDumpInterrupted) Is(target error) bool {
+	return target == unix.EINTR
+}
+
 // GetIPFamily returns the family type of a net.IP.
 func GetIPFamily(ip net.IP) int {
 	if len(ip) <= net.IPv4len {
@@ -488,10 +511,34 @@ func (req *NetlinkRequest) AddRawData(data []byte) {
 	req.RawData = append(req.RawData, data...)
 }
 
-// Execute the request against a the given sockType.
+// Execute the request against the given sockType.
 // Returns a list of netlink messages in serialized format, optionally filtered
 // by resType.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
+	var res [][]byte
+	err := req.ExecuteIter(sockType, resType, func(msg []byte) bool {
+		res = append(res, msg)
+		return true
+	})
+	if err != nil && !errors.Is(err, ErrDumpInterrupted) {
+		return nil, err
+	}
+	return res, err
+}
+
+// ExecuteIter executes the request against the given sockType.
+// Calls the provided callback func once for each netlink message.
+// If the callback returns false, it is not called again, but
+// the remaining messages are consumed/discarded.
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+//
+// Thread safety: ExecuteIter holds a lock on the socket until
+// it finishes iteration so the callback must not call back into
+// the netlink API.
+func (req *NetlinkRequest) ExecuteIter(sockType int, resType uint16, f func(msg []byte) bool) error {
 	var (
 		s   *NetlinkSocket
 		err error
@@ -508,18 +555,18 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
 	if s == nil {
 		s, err = getNetlinkSocket(sockType)
 		if err != nil {
-			return nil, err
+			return err
 		}
 
 		if err := s.SetSendTimeout(&SocketTimeoutTv); err != nil {
-			return nil, err
+			return err
 		}
 		if err := s.SetReceiveTimeout(&SocketTimeoutTv); err != nil {
-			return nil, err
+			return err
 		}
 		if EnableErrorMessageReporting {
 			if err := s.SetExtAck(true); err != nil {
-				return nil, err
+				return err
 			}
 		}
 
@@ -530,38 +577,38 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
 	}
 
 	if err := s.Send(req); err != nil {
-		return nil, err
+		return err
 	}
 
 	pid, err := s.GetPid()
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	var res [][]byte
+	dumpIntr := false
 
 done:
 	for {
 		msgs, from, err := s.Receive()
 		if err != nil {
-			return nil, err
+			return err
 		}
 		if from.Pid != PidKernel {
-			return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, PidKernel)
+			return fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, PidKernel)
 		}
 		for _, m := range msgs {
 			if m.Header.Seq != req.Seq {
 				if sharedSocket {
 					continue
 				}
-				return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
+				return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
 			}
 			if m.Header.Pid != pid {
 				continue
 			}
 
 			if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 {
-				return nil, syscall.Errno(unix.EINTR)
+				dumpIntr = true
 			}
 
 			if m.Header.Type == unix.NLMSG_DONE || m.Header.Type == unix.NLMSG_ERROR {
@@ -600,18 +647,29 @@ done:
 					}
 				}
 
-				return nil, err
+				return err
 			}
 			if resType != 0 && m.Header.Type != resType {
 				continue
 			}
-			res = append(res, m.Data)
+			if cont := f(m.Data); !cont {
+				// Drain the rest of the messages from the kernel but don't
+				// pass them to the iterator func.
+				f = dummyMsgIterFunc
+			}
 			if m.Header.Flags&unix.NLM_F_MULTI == 0 {
 				break done
 			}
 		}
 	}
-	return res, nil
+	if dumpIntr {
+		return ErrDumpInterrupted
+	}
+	return nil
+}
+
+func dummyMsgIterFunc(msg []byte) bool {
+	return true
 }
 
 // Create a new netlink request from proto and flags
@@ -629,8 +687,11 @@ func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
 }
 
 type NetlinkSocket struct {
-	fd  int32
-	lsa unix.SockaddrNetlink
+	fd             int32
+	file           *os.File
+	lsa            unix.SockaddrNetlink
+	sendTimeout    int64 // Access using atomic.Load/StoreInt64
+	receiveTimeout int64 // Access using atomic.Load/StoreInt64
 	sync.Mutex
 }
 
@@ -639,8 +700,13 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
 	if err != nil {
 		return nil, err
 	}
+	err = unix.SetNonblock(fd, true)
+	if err != nil {
+		return nil, err
+	}
 	s := &NetlinkSocket{
-		fd: int32(fd),
+		fd:   int32(fd),
+		file: os.NewFile(uintptr(fd), "netlink"),
 	}
 	s.lsa.Family = unix.AF_NETLINK
 	if err := unix.Bind(fd, &s.lsa); err != nil {
@@ -727,8 +793,13 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
 	if err != nil {
 		return nil, err
 	}
+	err = unix.SetNonblock(fd, true)
+	if err != nil {
+		return nil, err
+	}
 	s := &NetlinkSocket{
-		fd: int32(fd),
+		fd:   int32(fd),
+		file: os.NewFile(uintptr(fd), "netlink"),
 	}
 	s.lsa.Family = unix.AF_NETLINK
 
@@ -757,34 +828,86 @@ func SubscribeAt(newNs, curNs netns.NsHandle, protocol int, groups ...uint) (*Ne
 }
 
 func (s *NetlinkSocket) Close() {
-	fd := int(atomic.SwapInt32(&s.fd, -1))
-	unix.Close(fd)
+	s.file.Close()
 }
 
 func (s *NetlinkSocket) GetFd() int {
-	return int(atomic.LoadInt32(&s.fd))
+	return int(s.fd)
+}
+
+func (s *NetlinkSocket) GetTimeouts() (send, receive time.Duration) {
+	return time.Duration(atomic.LoadInt64(&s.sendTimeout)),
+		time.Duration(atomic.LoadInt64(&s.receiveTimeout))
 }
 
 func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
-	fd := int(atomic.LoadInt32(&s.fd))
-	if fd < 0 {
-		return fmt.Errorf("Send called on a closed socket")
+	rawConn, err := s.file.SyscallConn()
+	if err != nil {
+		return err
+	}
+	var (
+		deadline time.Time
+		innerErr error
+	)
+	sendTimeout := atomic.LoadInt64(&s.sendTimeout)
+	if sendTimeout != 0 {
+		deadline = time.Now().Add(time.Duration(sendTimeout))
 	}
-	if err := unix.Sendto(fd, request.Serialize(), 0, &s.lsa); err != nil {
+	if err := s.file.SetWriteDeadline(deadline); err != nil {
+		return err
+	}
+	serializedReq := request.Serialize()
+	err = rawConn.Write(func(fd uintptr) (done bool) {
+		innerErr = unix.Sendto(int(s.fd), serializedReq, 0, &s.lsa)
+		return innerErr != unix.EWOULDBLOCK
+	})
+	if innerErr != nil {
+		return innerErr
+	}
+	if err != nil {
+		// The timeout was previously implemented using SO_SNDTIMEO on a blocking
+		// socket. So, continue to return EAGAIN when the timeout is reached.
+		if errors.Is(err, os.ErrDeadlineExceeded) {
+			return unix.EAGAIN
+		}
 		return err
 	}
 	return nil
 }
 
 func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetlink, error) {
-	fd := int(atomic.LoadInt32(&s.fd))
-	if fd < 0 {
-		return nil, nil, fmt.Errorf("Receive called on a closed socket")
+	rawConn, err := s.file.SyscallConn()
+	if err != nil {
+		return nil, nil, err
+	}
+	var (
+		deadline time.Time
+		fromAddr *unix.SockaddrNetlink
+		rb       [RECEIVE_BUFFER_SIZE]byte
+		nr       int
+		from     unix.Sockaddr
+		innerErr error
+	)
+	receiveTimeout := atomic.LoadInt64(&s.receiveTimeout)
+	if receiveTimeout != 0 {
+		deadline = time.Now().Add(time.Duration(receiveTimeout))
+	}
+	if err := s.file.SetReadDeadline(deadline); err != nil {
+		return nil, nil, err
+	}
+	err = rawConn.Read(func(fd uintptr) (done bool) {
+		nr, from, innerErr = unix.Recvfrom(int(fd), rb[:], 0)
+		return innerErr != unix.EWOULDBLOCK
+	})
+	if innerErr != nil {
+		return nil, nil, innerErr
 	}
-	var fromAddr *unix.SockaddrNetlink
-	var rb [RECEIVE_BUFFER_SIZE]byte
-	nr, from, err := unix.Recvfrom(fd, rb[:], 0)
 	if err != nil {
+		// The timeout was previously implemented using SO_RCVTIMEO on a blocking
+		// socket. So, continue to return EAGAIN when the timeout is reached.
+		if errors.Is(err, os.ErrDeadlineExceeded) {
+			return nil, nil, unix.EAGAIN
+		}
 		return nil, nil, err
 	}
 	fromAddr, ok := from.(*unix.SockaddrNetlink)
@@ -806,16 +929,14 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetli
 
 // SetSendTimeout allows to set a send timeout on the socket
 func (s *NetlinkSocket) SetSendTimeout(timeout *unix.Timeval) error {
-	// Set a send timeout of SOCKET_SEND_TIMEOUT, this will allow the Send to periodically unblock and avoid that a routine
-	// remains stuck on a send on a closed fd
-	return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_SNDTIMEO, timeout)
+	atomic.StoreInt64(&s.sendTimeout, timeout.Nano())
+	return nil
 }
 
 // SetReceiveTimeout allows to set a receive timeout on the socket
 func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
-	// Set a read timeout of SOCKET_READ_TIMEOUT, this will allow the Read to periodically unblock and avoid that a routine
-	// remains stuck on a recvmsg on a closed fd
-	return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
+	atomic.StoreInt64(&s.receiveTimeout, timeout.Nano())
+	return nil
 }
 
 // SetReceiveBufferSize allows to set a receive buffer size on the socket
@@ -838,8 +959,7 @@ func (s *NetlinkSocket) SetExtAck(enable bool) error {
 }
 
 func (s *NetlinkSocket) GetPid() (uint32, error) {
-	fd := int(atomic.LoadInt32(&s.fd))
-	lsa, err := unix.Getsockname(fd)
+	lsa, err := unix.Getsockname(int(s.fd))
 	if err != nil {
 		return 0, err
 	}
@@ -883,6 +1003,12 @@ func Uint16Attr(v uint16) []byte {
 	return bytes
 }
 
+func BEUint16Attr(v uint16) []byte {
+	bytes := make([]byte, 2)
+	binary.BigEndian.PutUint16(bytes, v)
+	return bytes
+}
+
 func Uint32Attr(v uint32) []byte {
 	native := NativeEndian()
 	bytes := make([]byte, 4)
@@ -890,6 +1016,12 @@ func Uint32Attr(v uint32) []byte {
 	return bytes
 }
 
+func BEUint32Attr(v uint32) []byte {
+	bytes := make([]byte, 4)
+	binary.BigEndian.PutUint32(bytes, v)
+	return bytes
+}
+
 func Uint64Attr(v uint64) []byte {
 	native := NativeEndian()
 	bytes := make([]byte, 8)
@@ -897,6 +1029,12 @@ func Uint64Attr(v uint64) []byte {
 	return bytes
 }
 
+func BEUint64Attr(v uint64) []byte {
+	bytes := make([]byte, 8)
+	binary.BigEndian.PutUint64(bytes, v)
+	return bytes
+}
+
 func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
 	var attrs []syscall.NetlinkRouteAttr
 	for len(b) >= unix.SizeofRtAttr {
diff --git a/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
index 150017726..8172b8471 100644
--- a/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
@@ -12,6 +12,7 @@ const (
 	SEG6_LOCAL_NH6
 	SEG6_LOCAL_IIF
 	SEG6_LOCAL_OIF
+	SEG6_LOCAL_BPF
 	__SEG6_LOCAL_MAX
 )
 const (
@@ -34,6 +35,7 @@ const (
 	SEG6_LOCAL_ACTION_END_S                    // 12
 	SEG6_LOCAL_ACTION_END_AS                   // 13
 	SEG6_LOCAL_ACTION_END_AM                   // 14
+	SEG6_LOCAL_ACTION_END_BPF                  // 15
 	__SEG6_LOCAL_ACTION_MAX
 )
 const (
@@ -71,6 +73,8 @@ func SEG6LocalActionString(action int) string {
 		return "End.AS"
 	case SEG6_LOCAL_ACTION_END_AM:
 		return "End.AM"
+	case SEG6_LOCAL_ACTION_END_BPF:
+		return "End.BPF"
 	}
 	return "unknown"
 }
diff --git a/vendor/github.com/vishvananda/netlink/protinfo_linux.go b/vendor/github.com/vishvananda/netlink/protinfo_linux.go
index 1ba25d3cd..aa51e3b47 100644
--- a/vendor/github.com/vishvananda/netlink/protinfo_linux.go
+++ b/vendor/github.com/vishvananda/netlink/protinfo_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"syscall"
 
@@ -8,10 +9,14 @@ import (
 	"golang.org/x/sys/unix"
 )
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func LinkGetProtinfo(link Link) (Protinfo, error) {
 	return pkgHandle.LinkGetProtinfo(link)
 }
 
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 	base := link.Attrs()
 	h.ensureIndex(base)
@@ -19,9 +24,9 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
 	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
 	req.AddData(msg)
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, 0)
-	if err != nil {
-		return pi, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return pi, executeErr
 	}
 
 	for _, m := range msgs {
@@ -43,7 +48,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 			}
 			pi = parseProtinfo(infos)
 
-			return pi, nil
+			return pi, executeErr
 		}
 	}
 	return pi, fmt.Errorf("Device with index %d not found", base.Index)
diff --git a/vendor/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/vishvananda/netlink/qdisc.go
index 6f5d6df43..067743d39 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc.go
@@ -123,6 +123,7 @@ type Htb struct {
 	Defcls       uint32
 	Debug        uint32
 	DirectPkts   uint32
+	DirectQlen   *uint32
 }
 
 func NewHtb(attrs QdiscAttrs) *Htb {
@@ -133,6 +134,7 @@ func NewHtb(attrs QdiscAttrs) *Htb {
 		Rate2Quantum: 10,
 		Debug:        0,
 		DirectPkts:   0,
+		DirectQlen:   nil,
 	}
 }
 
diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
index 3c3780d3d..22cf0e582 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
@@ -1,10 +1,12 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"strconv"
 	"strings"
+	"sync"
 	"syscall"
 
 	"github.com/vishvananda/netlink/nl"
@@ -200,7 +202,9 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 		opt.Debug = qdisc.Debug
 		opt.DirectPkts = qdisc.DirectPkts
 		options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
-		// options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
+		if qdisc.DirectQlen != nil {
+			options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, nl.Uint32Attr(*qdisc.DirectQlen))
+		}
 	case *Hfsc:
 		opt := nl.TcHfscOpt{}
 		opt.Defcls = qdisc.Defcls
@@ -335,6 +339,9 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 // QdiscList gets a list of qdiscs in the system.
 // Equivalent to: `tc qdisc show`.
 // The list can be filtered by link.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func QdiscList(link Link) ([]Qdisc, error) {
 	return pkgHandle.QdiscList(link)
 }
@@ -342,6 +349,9 @@ func QdiscList(link Link) ([]Qdisc, error) {
 // QdiscList gets a list of qdiscs in the system.
 // Equivalent to: `tc qdisc show`.
 // The list can be filtered by link.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETQDISC, unix.NLM_F_DUMP)
 	index := int32(0)
@@ -356,9 +366,9 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
 	}
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWQDISC)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []Qdisc
@@ -494,7 +504,7 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
 		res = append(res, qdisc)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func parsePfifoFastData(qdisc Qdisc, value []byte) error {
@@ -525,8 +535,8 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
 			htb.Debug = opt.Debug
 			htb.DirectPkts = opt.DirectPkts
 		case nl.TCA_HTB_DIRECT_QLEN:
-			// TODO
-			//htb.DirectQlen = native.uint32(datum.Value)
+			directQlen := native.Uint32(datum.Value)
+			htb.DirectQlen = &directQlen
 		}
 	}
 	return nil
@@ -688,6 +698,9 @@ var (
 	tickInUsec  float64
 	clockFactor float64
 	hz          float64
+
+	// Without this, the go race detector may report races.
+	initClockMutex sync.Mutex
 )
 
 func initClock() {
@@ -722,6 +735,8 @@ func initClock() {
 }
 
 func TickInUsec() float64 {
+	initClockMutex.Lock()
+	defer initClockMutex.Unlock()
 	if tickInUsec == 0.0 {
 		initClock()
 	}
@@ -729,6 +744,8 @@ func TickInUsec() float64 {
 }
 
 func ClockFactor() float64 {
+	initClockMutex.Lock()
+	defer initClockMutex.Unlock()
 	if clockFactor == 0.0 {
 		initClock()
 	}
@@ -736,6 +753,8 @@ func ClockFactor() float64 {
 }
 
 func Hz() float64 {
+	initClockMutex.Lock()
+	defer initClockMutex.Unlock()
 	if hz == 0.0 {
 		initClock()
 	}
diff --git a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
index 036399db6..9bb750732 100644
--- a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
@@ -3,6 +3,7 @@ package netlink
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"net"
 
@@ -85,19 +86,25 @@ func execRdmaSetLink(req *nl.NetlinkRequest) error {
 
 // RdmaLinkList gets a list of RDMA link devices.
 // Equivalent to: `rdma dev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func RdmaLinkList() ([]*RdmaLink, error) {
 	return pkgHandle.RdmaLinkList()
 }
 
 // RdmaLinkList gets a list of RDMA link devices.
 // Equivalent to: `rdma dev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
 	proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
 	req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
 
-	msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_RDMA, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []*RdmaLink
@@ -109,17 +116,23 @@ func (h *Handle) RdmaLinkList() ([]*RdmaLink, error) {
 		res = append(res, link)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 // RdmaLinkByName finds a link by name and returns a pointer to the object if
 // found and nil error, otherwise returns error code.
+//
+// If the returned error is [ErrDumpInterrupted], the result may be missing or
+// outdated and the caller should retry.
 func RdmaLinkByName(name string) (*RdmaLink, error) {
 	return pkgHandle.RdmaLinkByName(name)
 }
 
 // RdmaLinkByName finds a link by name and returns a pointer to the object if
 // found and nil error, otherwise returns error code.
+//
+// If the returned error is [ErrDumpInterrupted], the result may be missing or
+// outdated and the caller should retry.
 func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
 	links, err := h.RdmaLinkList()
 	if err != nil {
@@ -288,6 +301,8 @@ func RdmaLinkDel(name string) error {
 }
 
 // RdmaLinkDel deletes an rdma link.
+//
+// If the returned error is [ErrDumpInterrupted], the caller should retry.
 func (h *Handle) RdmaLinkDel(name string) error {
 	link, err := h.RdmaLinkByName(name)
 	if err != nil {
@@ -307,6 +322,7 @@ func (h *Handle) RdmaLinkDel(name string) error {
 
 // RdmaLinkAdd adds an rdma link for the specified type to the network device.
 // Similar to: rdma link add NAME type TYPE netdev NETDEV
+//
 //	NAME - specifies the new name of the rdma link to add
 //	TYPE - specifies which rdma type to use.  Link types:
 //		rxe - Soft RoCE driver
diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go
index 929738e11..28a132a2f 100644
--- a/vendor/github.com/vishvananda/netlink/route_linux.go
+++ b/vendor/github.com/vishvananda/netlink/route_linux.go
@@ -3,6 +3,7 @@ package netlink
 import (
 	"bytes"
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"net"
 	"strconv"
@@ -273,6 +274,16 @@ type SEG6LocalEncap struct {
 	In6Addr  net.IP
 	Iif      int
 	Oif      int
+	bpf      bpfObj
+}
+
+func (e *SEG6LocalEncap) SetProg(progFd int, progName string) error {
+	if progFd <= 0 {
+		return fmt.Errorf("seg6local bpf SetProg: invalid fd")
+	}
+	e.bpf.progFd = progFd
+	e.bpf.progName = progName
+	return nil
 }
 
 func (e *SEG6LocalEncap) Type() int {
@@ -306,6 +317,22 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
 		case nl.SEG6_LOCAL_OIF:
 			e.Oif = int(native.Uint32(attr.Value[0:4]))
 			e.Flags[nl.SEG6_LOCAL_OIF] = true
+		case nl.SEG6_LOCAL_BPF:
+			var bpfAttrs []syscall.NetlinkRouteAttr
+			bpfAttrs, err = nl.ParseRouteAttr(attr.Value)
+			bpfobj := bpfObj{}
+			for _, bpfAttr := range bpfAttrs {
+				switch bpfAttr.Attr.Type {
+				case nl.LWT_BPF_PROG_FD:
+					bpfobj.progFd = int(native.Uint32(bpfAttr.Value))
+				case nl.LWT_BPF_PROG_NAME:
+					bpfobj.progName = string(bpfAttr.Value)
+				default:
+					err = fmt.Errorf("seg6local bpf decode: unknown attribute: Type %d", bpfAttr.Attr)
+				}
+			}
+			e.bpf = bpfobj
+			e.Flags[nl.SEG6_LOCAL_BPF] = true
 		}
 	}
 	return err
@@ -367,6 +394,16 @@ func (e *SEG6LocalEncap) Encode() ([]byte, error) {
 		native.PutUint32(attr[4:], uint32(e.Oif))
 		res = append(res, attr...)
 	}
+	if e.Flags[nl.SEG6_LOCAL_BPF] {
+		attr := nl.NewRtAttr(nl.SEG6_LOCAL_BPF, []byte{})
+		if e.bpf.progFd != 0 {
+			attr.AddRtAttr(nl.LWT_BPF_PROG_FD, nl.Uint32Attr(uint32(e.bpf.progFd)))
+		}
+		if e.bpf.progName != "" {
+			attr.AddRtAttr(nl.LWT_BPF_PROG_NAME, nl.ZeroTerminated(e.bpf.progName))
+		}
+		res = append(res, attr.Serialize()...)
+	}
 	return res, err
 }
 func (e *SEG6LocalEncap) String() string {
@@ -400,12 +437,15 @@ func (e *SEG6LocalEncap) String() string {
 	}
 	if e.Flags[nl.SEG6_LOCAL_SRH] {
 		segs := make([]string, 0, len(e.Segments))
-		//append segment backwards (from n to 0) since seg#0 is the last segment.
+		// append segment backwards (from n to 0) since seg#0 is the last segment.
 		for i := len(e.Segments); i > 0; i-- {
 			segs = append(segs, e.Segments[i-1].String())
 		}
 		strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
 	}
+	if e.Flags[nl.SEG6_LOCAL_BPF] {
+		strs = append(strs, fmt.Sprintf("bpf %s[%d]", e.bpf.progName, e.bpf.progFd))
+	}
 	return strings.Join(strs, " ")
 }
 func (e *SEG6LocalEncap) Equal(x Encap) bool {
@@ -437,7 +477,7 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
 	if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) {
 		return false
 	}
-	if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif {
+	if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif || e.bpf != o.bpf {
 		return false
 	}
 	return true
@@ -835,8 +875,22 @@ func (h *Handle) RouteDel(route *Route) error {
 }
 
 func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) ([][]byte, error) {
+	if err := h.prepareRouteReq(route, req, msg); err != nil {
+		return nil, err
+	}
+	return req.Execute(unix.NETLINK_ROUTE, 0)
+}
+
+func (h *Handle) routeHandleIter(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg, f func(msg []byte) bool) error {
+	if err := h.prepareRouteReq(route, req, msg); err != nil {
+		return err
+	}
+	return req.ExecuteIter(unix.NETLINK_ROUTE, 0, f)
+}
+
+func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
 	if req.NlMsghdr.Type != unix.RTM_GETROUTE && (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil && route.MPLSDst == nil {
-		return nil, fmt.Errorf("Either Dst.IP, Src.IP or Gw must be set")
+		return fmt.Errorf("either Dst.IP, Src.IP or Gw must be set")
 	}
 
 	family := -1
@@ -863,11 +917,11 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 
 	if route.NewDst != nil {
 		if family != -1 && family != route.NewDst.Family() {
-			return nil, fmt.Errorf("new destination and destination are not the same address family")
+			return fmt.Errorf("new destination and destination are not the same address family")
 		}
 		buf, err := route.NewDst.Encode()
 		if err != nil {
-			return nil, err
+			return err
 		}
 		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_NEWDST, buf))
 	}
@@ -878,7 +932,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
 		buf, err := route.Encap.Encode()
 		if err != nil {
-			return nil, err
+			return err
 		}
 		switch route.Encap.Type() {
 		case nl.LWTUNNEL_ENCAP_BPF:
@@ -892,7 +946,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 	if route.Src != nil {
 		srcFamily := nl.GetIPFamily(route.Src)
 		if family != -1 && family != srcFamily {
-			return nil, fmt.Errorf("source and destination ip are not the same IP family")
+			return fmt.Errorf("source and destination ip are not the same IP family")
 		}
 		family = srcFamily
 		var srcData []byte
@@ -908,7 +962,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 	if route.Gw != nil {
 		gwFamily := nl.GetIPFamily(route.Gw)
 		if family != -1 && family != gwFamily {
-			return nil, fmt.Errorf("gateway, source, and destination ip are not the same IP family")
+			return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
 		}
 		family = gwFamily
 		var gwData []byte
@@ -923,7 +977,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 	if route.Via != nil {
 		buf, err := route.Via.Encode()
 		if err != nil {
-			return nil, fmt.Errorf("failed to encode RTA_VIA: %v", err)
+			return fmt.Errorf("failed to encode RTA_VIA: %v", err)
 		}
 		rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf))
 	}
@@ -942,7 +996,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 			if nh.Gw != nil {
 				gwFamily := nl.GetIPFamily(nh.Gw)
 				if family != -1 && family != gwFamily {
-					return nil, fmt.Errorf("gateway, source, and destination ip are not the same IP family")
+					return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
 				}
 				if gwFamily == FAMILY_V4 {
 					children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4())))
@@ -952,11 +1006,11 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 			}
 			if nh.NewDst != nil {
 				if family != -1 && family != nh.NewDst.Family() {
-					return nil, fmt.Errorf("new destination and destination are not the same address family")
+					return fmt.Errorf("new destination and destination are not the same address family")
 				}
 				buf, err := nh.NewDst.Encode()
 				if err != nil {
-					return nil, err
+					return err
 				}
 				children = append(children, nl.NewRtAttr(unix.RTA_NEWDST, buf))
 			}
@@ -966,14 +1020,14 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 				children = append(children, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
 				buf, err := nh.Encap.Encode()
 				if err != nil {
-					return nil, err
+					return err
 				}
 				children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
 			}
 			if nh.Via != nil {
 				buf, err := nh.Via.Encode()
 				if err != nil {
-					return nil, err
+					return err
 				}
 				children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf))
 			}
@@ -1104,13 +1158,15 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
 		native.PutUint32(b, uint32(route.LinkIndex))
 		req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
 	}
-
-	return req.Execute(unix.NETLINK_ROUTE, 0)
+	return nil
 }
 
 // RouteList gets a list of routes in the system.
 // Equivalent to: `ip route show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func RouteList(link Link, family int) ([]Route, error) {
 	return pkgHandle.RouteList(link, family)
 }
@@ -1118,6 +1174,9 @@ func RouteList(link Link, family int) ([]Route, error) {
 // RouteList gets a list of routes in the system.
 // Equivalent to: `ip route show`.
 // The list can be filtered by link and ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) RouteList(link Link, family int) ([]Route, error) {
 	routeFilter := &Route{}
 	if link != nil {
@@ -1136,74 +1195,103 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
 
 // RouteListFiltered gets a list of routes in the system filtered with specified rules.
 // All rules must be defined in RouteFilter struct
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
-	req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
-	rtmsg := &nl.RtMsg{}
-	rtmsg.Family = uint8(family)
-	msgs, err := h.routeHandle(filter, req, rtmsg)
+	var res []Route
+	err := h.RouteListFilteredIter(family, filter, filterMask, func(route Route) (cont bool) {
+		res = append(res, route)
+		return true
+	})
 	if err != nil {
 		return nil, err
 	}
+	return res, nil
+}
 
-	var res []Route
-	for _, m := range msgs {
+// RouteListFilteredIter passes each route that matches the filter to the given iterator func.  Iteration continues
+// until all routes are loaded or the func returns false.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error {
+	return pkgHandle.RouteListFilteredIter(family, filter, filterMask, f)
+}
+
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error {
+	req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
+	rtmsg := &nl.RtMsg{}
+	rtmsg.Family = uint8(family)
+
+	var parseErr error
+	executeErr := h.routeHandleIter(filter, req, rtmsg, func(m []byte) bool {
 		msg := nl.DeserializeRtMsg(m)
 		if family != FAMILY_ALL && msg.Family != uint8(family) {
 			// Ignore routes not matching requested family
-			continue
+			return true
 		}
 		if msg.Flags&unix.RTM_F_CLONED != 0 {
 			// Ignore cloned routes
-			continue
+			return true
 		}
 		if msg.Table != unix.RT_TABLE_MAIN {
 			if filter == nil || filterMask&RT_FILTER_TABLE == 0 {
 				// Ignore non-main tables
-				continue
+				return true
 			}
 		}
 		route, err := deserializeRoute(m)
 		if err != nil {
-			return nil, err
+			parseErr = err
+			return false
 		}
 		if filter != nil {
 			switch {
 			case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table:
-				continue
+				return true
 			case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol:
-				continue
+				return true
 			case filterMask&RT_FILTER_SCOPE != 0 && route.Scope != filter.Scope:
-				continue
+				return true
 			case filterMask&RT_FILTER_TYPE != 0 && route.Type != filter.Type:
-				continue
+				return true
 			case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos:
-				continue
+				return true
 			case filterMask&RT_FILTER_REALM != 0 && route.Realm != filter.Realm:
-				continue
+				return true
 			case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex:
-				continue
+				return true
 			case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex:
-				continue
+				return true
 			case filterMask&RT_FILTER_GW != 0 && !route.Gw.Equal(filter.Gw):
-				continue
+				return true
 			case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src):
-				continue
+				return true
 			case filterMask&RT_FILTER_DST != 0:
 				if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) {
 					if filter.Dst == nil {
 						filter.Dst = genZeroIPNet(family)
 					}
 					if !ipNetEqual(route.Dst, filter.Dst) {
-						continue
+						return true
 					}
 				}
 			case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit:
-				continue
+				return true
 			}
 		}
-		res = append(res, route)
+		return f(route)
+	})
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return executeErr
 	}
-	return res, nil
+	if parseErr != nil {
+		return parseErr
+	}
+	return executeErr
 }
 
 // deserializeRoute decodes a binary netlink message into a Route struct
@@ -1448,7 +1536,7 @@ type RouteGetOptions struct {
 	VrfName  string
 	SrcAddr  net.IP
 	UID      *uint32
-	Mark     int
+	Mark     uint32
 	FIBMatch bool
 }
 
@@ -1557,7 +1645,7 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
 
 		if options.Mark > 0 {
 			b := make([]byte, 4)
-			native.PutUint32(b, uint32(options.Mark))
+			native.PutUint32(b, options.Mark)
 
 			req.AddData(nl.NewRtAttr(unix.RTA_MARK, b))
 		}
@@ -1611,6 +1699,10 @@ type RouteSubscribeOptions struct {
 // RouteSubscribeWithOptions work like RouteSubscribe but enable to
 // provide additional options to modify the behavior. Currently, the
 // namespace can be provided as well as an error callback.
+//
+// When options.ListExisting is true, options.ErrorCallback may be
+// called with [ErrDumpInterrupted] to indicate that results from
+// the initial dump of links may be inconsistent or incomplete.
 func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error {
 	if options.Namespace == nil {
 		none := netns.None()
@@ -1670,6 +1762,9 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
 				continue
 			}
 			for _, m := range msgs {
+				if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil {
+					cberr(ErrDumpInterrupted)
+				}
 				if m.Header.Type == unix.NLMSG_DONE {
 					continue
 				}
@@ -1723,7 +1818,7 @@ func (p RouteProtocol) String() string {
 		return "gated"
 	case unix.RTPROT_ISIS:
 		return "isis"
-	//case unix.RTPROT_KEEPALIVED:
+	// case unix.RTPROT_KEEPALIVED:
 	//	return "keepalived"
 	case unix.RTPROT_KERNEL:
 		return "kernel"
diff --git a/vendor/github.com/vishvananda/netlink/rule.go b/vendor/github.com/vishvananda/netlink/rule.go
index 9a6b57dac..9d74c7cd8 100644
--- a/vendor/github.com/vishvananda/netlink/rule.go
+++ b/vendor/github.com/vishvananda/netlink/rule.go
@@ -10,8 +10,8 @@ type Rule struct {
 	Priority          int
 	Family            int
 	Table             int
-	Mark              int
-	Mask              int
+	Mark              uint32
+	Mask              *uint32
 	Tos               uint
 	TunID             uint
 	Goto              int
@@ -28,6 +28,7 @@ type Rule struct {
 	IPProto           int
 	UIDRange          *RuleUIDRange
 	Protocol          uint8
+	Type              uint8
 }
 
 func (r Rule) String() string {
@@ -41,8 +42,8 @@ func (r Rule) String() string {
 		to = r.Dst.String()
 	}
 
-	return fmt.Sprintf("ip rule %d: from %s to %s table %d",
-		r.Priority, from, to, r.Table)
+	return fmt.Sprintf("ip rule %d: from %s to %s table %d %s",
+		r.Priority, from, to, r.Table, r.typeString())
 }
 
 // NewRule return empty rules.
@@ -51,8 +52,8 @@ func NewRule() *Rule {
 		SuppressIfgroup:   -1,
 		SuppressPrefixlen: -1,
 		Priority:          -1,
-		Mark:              -1,
-		Mask:              -1,
+		Mark:              0,
+		Mask:              nil,
 		Goto:              -1,
 		Flow:              -1,
 	}
diff --git a/vendor/github.com/vishvananda/netlink/rule_linux.go b/vendor/github.com/vishvananda/netlink/rule_linux.go
index e91989251..dba99147b 100644
--- a/vendor/github.com/vishvananda/netlink/rule_linux.go
+++ b/vendor/github.com/vishvananda/netlink/rule_linux.go
@@ -2,6 +2,7 @@ package netlink
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"net"
 
@@ -43,8 +44,8 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
 	msg.Protocol = unix.RTPROT_BOOT
 	msg.Scope = unix.RT_SCOPE_UNIVERSE
 	msg.Table = unix.RT_TABLE_UNSPEC
-	msg.Type = unix.RTN_UNSPEC
-	if req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
+	msg.Type = rule.Type // usually 0, same as unix.RTN_UNSPEC
+	if msg.Type == 0 && req.NlMsghdr.Flags&unix.NLM_F_CREATE > 0 {
 		msg.Type = unix.RTN_UNICAST
 	}
 	if rule.Invert {
@@ -102,14 +103,14 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
 		native.PutUint32(b, uint32(rule.Priority))
 		req.AddData(nl.NewRtAttr(nl.FRA_PRIORITY, b))
 	}
-	if rule.Mark >= 0 {
+	if rule.Mark != 0 || rule.Mask != nil {
 		b := make([]byte, 4)
-		native.PutUint32(b, uint32(rule.Mark))
+		native.PutUint32(b, rule.Mark)
 		req.AddData(nl.NewRtAttr(nl.FRA_FWMARK, b))
 	}
-	if rule.Mask >= 0 {
+	if rule.Mask != nil {
 		b := make([]byte, 4)
-		native.PutUint32(b, uint32(rule.Mask))
+		native.PutUint32(b, *rule.Mask)
 		req.AddData(nl.NewRtAttr(nl.FRA_FWMASK, b))
 	}
 	if rule.Flow >= 0 {
@@ -183,12 +184,18 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
 
 // RuleList lists rules in the system.
 // Equivalent to: ip rule list
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func RuleList(family int) ([]Rule, error) {
 	return pkgHandle.RuleList(family)
 }
 
 // RuleList lists rules in the system.
 // Equivalent to: ip rule list
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) RuleList(family int) ([]Rule, error) {
 	return h.RuleListFiltered(family, nil, 0)
 }
@@ -196,20 +203,26 @@ func (h *Handle) RuleList(family int) ([]Rule, error) {
 // RuleListFiltered gets a list of rules in the system filtered by the
 // specified rule template `filter`.
 // Equivalent to: ip rule list
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
 	return pkgHandle.RuleListFiltered(family, filter, filterMask)
 }
 
 // RuleListFiltered lists rules in the system.
 // Equivalent to: ip rule list
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) ([]Rule, error) {
 	req := h.newNetlinkRequest(unix.RTM_GETRULE, unix.NLM_F_DUMP|unix.NLM_F_REQUEST)
 	msg := nl.NewIfInfomsg(family)
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWRULE)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res = make([]Rule, 0)
@@ -242,9 +255,10 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
 					Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attrs[j].Value)),
 				}
 			case nl.FRA_FWMARK:
-				rule.Mark = int(native.Uint32(attrs[j].Value[0:4]))
+				rule.Mark = native.Uint32(attrs[j].Value[0:4])
 			case nl.FRA_FWMASK:
-				rule.Mask = int(native.Uint32(attrs[j].Value[0:4]))
+				mask := native.Uint32(attrs[j].Value[0:4])
+				rule.Mask = &mask
 			case nl.FRA_TUN_ID:
 				rule.TunID = uint(native.Uint64(attrs[j].Value[0:8]))
 			case nl.FRA_IIFNAME:
@@ -297,7 +311,7 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
 				continue
 			case filterMask&RT_FILTER_MARK != 0 && rule.Mark != filter.Mark:
 				continue
-			case filterMask&RT_FILTER_MASK != 0 && rule.Mask != filter.Mask:
+			case filterMask&RT_FILTER_MASK != 0 && !ptrEqual(rule.Mask, filter.Mask):
 				continue
 			}
 		}
@@ -305,7 +319,7 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
 		res = append(res, *rule)
 	}
 
-	return res, nil
+	return res, executeErr
 }
 
 func (pr *RulePortRange) toRtAttrData() []byte {
@@ -321,3 +335,44 @@ func (pr *RuleUIDRange) toRtAttrData() []byte {
 	native.PutUint32(b[1], pr.End)
 	return bytes.Join(b, []byte{})
 }
+
+func ptrEqual(a, b *uint32) bool {
+	if a == b {
+		return true
+	}
+	if (a == nil) || (b == nil) {
+		return false
+	}
+	return *a == *b
+}
+
+func (r Rule) typeString() string {
+	switch r.Type {
+	case unix.RTN_UNSPEC: // zero
+		return ""
+	case unix.RTN_UNICAST:
+		return ""
+	case unix.RTN_LOCAL:
+		return "local"
+	case unix.RTN_BROADCAST:
+		return "broadcast"
+	case unix.RTN_ANYCAST:
+		return "anycast"
+	case unix.RTN_MULTICAST:
+		return "multicast"
+	case unix.RTN_BLACKHOLE:
+		return "blackhole"
+	case unix.RTN_UNREACHABLE:
+		return "unreachable"
+	case unix.RTN_PROHIBIT:
+		return "prohibit"
+	case unix.RTN_THROW:
+		return "throw"
+	case unix.RTN_NAT:
+		return "nat"
+	case unix.RTN_XRESOLVE:
+		return "xresolve"
+	default:
+		return fmt.Sprintf("type(0x%x)", r.Type)
+	}
+}
diff --git a/vendor/github.com/vishvananda/netlink/rule_nonlinux.go b/vendor/github.com/vishvananda/netlink/rule_nonlinux.go
new file mode 100644
index 000000000..2b19aa64c
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/rule_nonlinux.go
@@ -0,0 +1,8 @@
+//go:build !linux
+// +build !linux
+
+package netlink
+
+func (r Rule) typeString() string {
+	return ""
+}
diff --git a/vendor/github.com/vishvananda/netlink/socket.go b/vendor/github.com/vishvananda/netlink/socket.go
index ebcf8423b..e65efb130 100644
--- a/vendor/github.com/vishvananda/netlink/socket.go
+++ b/vendor/github.com/vishvananda/netlink/socket.go
@@ -35,3 +35,70 @@ type UnixSocket struct {
 	INode  uint32
 	Cookie [2]uint32
 }
+
+// XDPSocket represents an XDP socket (and the common diagnosis part in
+// particular). Please note that in contrast to [UnixSocket] the XDPSocket type
+// does not feature “State” information.
+type XDPSocket struct {
+	// xdp_diag_msg
+	// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L21
+	Family uint8
+	Type   uint8
+	pad    uint16
+	Ino    uint32
+	Cookie [2]uint32
+}
+
+type XDPInfo struct {
+	// XDP_DIAG_INFO/xdp_diag_info
+	// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L51
+	Ifindex uint32
+	QueueID uint32
+
+	// XDP_DIAG_UID
+	UID uint32
+
+	// XDP_RX_RING
+	// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L56
+	RxRingEntries             uint32
+	TxRingEntries             uint32
+	UmemFillRingEntries       uint32
+	UmemCompletionRingEntries uint32
+
+	// XDR_DIAG_UMEM
+	Umem *XDPDiagUmem
+
+	// XDR_DIAG_STATS
+	Stats *XDPDiagStats
+}
+
+const (
+	XDP_DU_F_ZEROCOPY = 1 << iota
+)
+
+// XDPDiagUmem describes the umem attached to an XDP socket.
+//
+// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L62
+type XDPDiagUmem struct {
+	Size      uint64
+	ID        uint32
+	NumPages  uint32
+	ChunkSize uint32
+	Headroom  uint32
+	Ifindex   uint32
+	QueueID   uint32
+	Flags     uint32
+	Refs      uint32
+}
+
+// XDPDiagStats contains ring statistics for an XDP socket.
+//
+// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L74
+type XDPDiagStats struct {
+	RxDropped     uint64
+	RxInvalid     uint64
+	RxFull        uint64
+	FillRingEmpty uint64
+	TxInvalid     uint64
+	TxRingEmpty   uint64
+}
diff --git a/vendor/github.com/vishvananda/netlink/socket_linux.go b/vendor/github.com/vishvananda/netlink/socket_linux.go
index e4b6fa73e..82891bc2e 100644
--- a/vendor/github.com/vishvananda/netlink/socket_linux.go
+++ b/vendor/github.com/vishvananda/netlink/socket_linux.go
@@ -157,7 +157,10 @@ func (u *UnixSocket) deserialize(b []byte) error {
 }
 
 // SocketGet returns the Socket identified by its local and remote addresses.
-func SocketGet(local, remote net.Addr) (*Socket, error) {
+//
+// If the returned error is [ErrDumpInterrupted], the search for a result may
+// be incomplete and the caller should retry.
+func (h *Handle) SocketGet(local, remote net.Addr) (*Socket, error) {
 	var protocol uint8
 	var localIP, remoteIP net.IP
 	var localPort, remotePort uint16
@@ -199,12 +202,7 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
 		return nil, ErrNotImplemented
 	}
 
-	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
-	if err != nil {
-		return nil, err
-	}
-	defer s.Close()
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&socketRequest{
 		Family:   family,
 		Protocol: protocol,
@@ -218,32 +216,34 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
 		},
 	})
 
-	if err := s.Send(req); err != nil {
-		return nil, err
-	}
-
-	msgs, from, err := s.Receive()
+	msgs, err := req.Execute(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY)
 	if err != nil {
 		return nil, err
 	}
-	if from.Pid != nl.PidKernel {
-		return nil, fmt.Errorf("wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
-	}
 	if len(msgs) == 0 {
 		return nil, errors.New("no message nor error from netlink")
 	}
 	if len(msgs) > 2 {
 		return nil, fmt.Errorf("multiple (%d) matching sockets", len(msgs))
 	}
+
 	sock := &Socket{}
-	if err := sock.deserialize(msgs[0].Data); err != nil {
+	if err := sock.deserialize(msgs[0]); err != nil {
 		return nil, err
 	}
 	return sock, nil
 }
 
+// SocketGet returns the Socket identified by its local and remote addresses.
+//
+// If the returned error is [ErrDumpInterrupted], the search for a result may
+// be incomplete and the caller should retry.
+func SocketGet(local, remote net.Addr) (*Socket, error) {
+	return pkgHandle.SocketGet(local, remote)
+}
+
 // SocketDestroy kills the Socket identified by its local and remote addresses.
-func SocketDestroy(local, remote net.Addr) error {
+func (h *Handle) SocketDestroy(local, remote net.Addr) error {
 	localTCP, ok := local.(*net.TCPAddr)
 	if !ok {
 		return ErrNotImplemented
@@ -266,7 +266,7 @@ func SocketDestroy(local, remote net.Addr) error {
 		return err
 	}
 	defer s.Close()
-	req := nl.NewNetlinkRequest(nl.SOCK_DESTROY, unix.NLM_F_ACK)
+	req := h.newNetlinkRequest(nl.SOCK_DESTROY, unix.NLM_F_ACK)
 	req.AddData(&socketRequest{
 		Family:   unix.AF_INET,
 		Protocol: unix.IPPROTO_TCP,
@@ -278,13 +278,23 @@ func SocketDestroy(local, remote net.Addr) error {
 			Cookie:          [2]uint32{nl.TCPDIAG_NOCOOKIE, nl.TCPDIAG_NOCOOKIE},
 		},
 	})
-	return s.Send(req)
+
+	_, err = req.Execute(unix.NETLINK_INET_DIAG, 0)
+	return err
+}
+
+// SocketDestroy kills the Socket identified by its local and remote addresses.
+func SocketDestroy(local, remote net.Addr) error {
+	return pkgHandle.SocketDestroy(local, remote)
 }
 
 // SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
-func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
 	// Construct the request
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&socketRequest{
 		Family:   family,
 		Protocol: unix.IPPROTO_TCP,
@@ -294,34 +304,47 @@ func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
 
 	// Do the query and parse the result
 	var result []*InetDiagTCPInfoResp
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &Socket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		var err error
+		if err = sockInfo.deserialize(msg); err != nil {
+			return false
 		}
-		attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
-		if err != nil {
-			return err
+		var attrs []syscall.NetlinkRouteAttr
+		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
+			return false
 		}
 
-		res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo)
-		if err != nil {
-			return err
+		var res *InetDiagTCPInfoResp
+		if res, err = attrsToInetDiagTCPInfoResp(attrs, sockInfo); err != nil {
+			return false
 		}
 
 		result = append(result, res)
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
+}
+
+// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
+	return pkgHandle.SocketDiagTCPInfo(family)
 }
 
 // SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
-func SocketDiagTCP(family uint8) ([]*Socket, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) SocketDiagTCP(family uint8) ([]*Socket, error) {
 	// Construct the request
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&socketRequest{
 		Family:   family,
 		Protocol: unix.IPPROTO_TCP,
@@ -331,29 +354,40 @@ func SocketDiagTCP(family uint8) ([]*Socket, error) {
 
 	// Do the query and parse the result
 	var result []*Socket
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &Socket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		if err := sockInfo.deserialize(msg); err != nil {
+			return false
 		}
 		result = append(result, sockInfo)
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
+}
+
+// SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func SocketDiagTCP(family uint8) ([]*Socket, error) {
+	return pkgHandle.SocketDiagTCP(family)
 }
 
 // SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
-func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
 	// Construct the request
 	var extensions uint8
 	extensions = 1 << (INET_DIAG_VEGASINFO - 1)
 	extensions |= 1 << (INET_DIAG_INFO - 1)
 	extensions |= 1 << (INET_DIAG_MEMINFO - 1)
 
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&socketRequest{
 		Family:   family,
 		Protocol: unix.IPPROTO_UDP,
@@ -363,34 +397,47 @@ func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
 
 	// Do the query and parse the result
 	var result []*InetDiagUDPInfoResp
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &Socket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		if err := sockInfo.deserialize(msg); err != nil {
+			return false
 		}
-		attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
-		if err != nil {
-			return err
+
+		var attrs []syscall.NetlinkRouteAttr
+		var err error
+		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
+			return false
 		}
 
-		res, err := attrsToInetDiagUDPInfoResp(attrs, sockInfo)
-		if err != nil {
-			return err
+		var res *InetDiagUDPInfoResp
+		if res, err = attrsToInetDiagUDPInfoResp(attrs, sockInfo); err != nil {
+			return false
 		}
 
 		result = append(result, res)
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
+}
+
+// SocketDiagUDPInfo requests INET_DIAG_INFO for UDP protocol for specified family type and return with extension info.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func SocketDiagUDPInfo(family uint8) ([]*InetDiagUDPInfoResp, error) {
+	return pkgHandle.SocketDiagUDPInfo(family)
 }
 
 // SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
-func SocketDiagUDP(family uint8) ([]*Socket, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) SocketDiagUDP(family uint8) ([]*Socket, error) {
 	// Construct the request
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&socketRequest{
 		Family:   family,
 		Protocol: unix.IPPROTO_UDP,
@@ -400,28 +447,39 @@ func SocketDiagUDP(family uint8) ([]*Socket, error) {
 
 	// Do the query and parse the result
 	var result []*Socket
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &Socket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		if err := sockInfo.deserialize(msg); err != nil {
+			return false
 		}
 		result = append(result, sockInfo)
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
+}
+
+// SocketDiagUDP requests INET_DIAG_INFO for UDP protocol for specified family type and return related socket.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func SocketDiagUDP(family uint8) ([]*Socket, error) {
+	return pkgHandle.SocketDiagUDP(family)
 }
 
 // UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
-func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
 	// Construct the request
 	var extensions uint8
 	extensions = 1 << UNIX_DIAG_NAME
 	extensions |= 1 << UNIX_DIAG_PEER
 	extensions |= 1 << UNIX_DIAG_RQLEN
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&unixSocketRequest{
 		Family: unix.AF_UNIX,
 		States: ^uint32(0), // all states
@@ -429,99 +487,81 @@ func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
 	})
 
 	var result []*UnixDiagInfoResp
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &UnixSocket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		if err := sockInfo.deserialize(msg); err != nil {
+			return false
 		}
 
 		// Diagnosis also delivers sockets with AF_INET family, filter those
 		if sockInfo.Family != unix.AF_UNIX {
-			return nil
+			return false
 		}
 
-		attrs, err := nl.ParseRouteAttr(m.Data[sizeofUnixSocket:])
-		if err != nil {
-			return err
+		var attrs []syscall.NetlinkRouteAttr
+		var err error
+		if attrs, err = nl.ParseRouteAttr(msg[sizeofSocket:]); err != nil {
+			return false
 		}
 
-		res, err := attrsToUnixDiagInfoResp(attrs, sockInfo)
-		if err != nil {
-			return err
+		var res *UnixDiagInfoResp
+		if res, err = attrsToUnixDiagInfoResp(attrs, sockInfo); err != nil {
+			return false
 		}
 		result = append(result, res)
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
+}
+
+// UnixSocketDiagInfo requests UNIX_DIAG_INFO for unix sockets and return with extension info.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func UnixSocketDiagInfo() ([]*UnixDiagInfoResp, error) {
+	return pkgHandle.UnixSocketDiagInfo()
 }
 
 // UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
-func UnixSocketDiag() ([]*UnixSocket, error) {
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func (h *Handle) UnixSocketDiag() ([]*UnixSocket, error) {
 	// Construct the request
-	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req := h.newNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
 	req.AddData(&unixSocketRequest{
 		Family: unix.AF_UNIX,
 		States: ^uint32(0), // all states
 	})
 
 	var result []*UnixSocket
-	err := socketDiagExecutor(req, func(m syscall.NetlinkMessage) error {
+	executeErr := req.ExecuteIter(unix.NETLINK_INET_DIAG, nl.SOCK_DIAG_BY_FAMILY, func(msg []byte) bool {
 		sockInfo := &UnixSocket{}
-		if err := sockInfo.deserialize(m.Data); err != nil {
-			return err
+		if err := sockInfo.deserialize(msg); err != nil {
+			return false
 		}
 
 		// Diagnosis also delivers sockets with AF_INET family, filter those
 		if sockInfo.Family == unix.AF_UNIX {
 			result = append(result, sockInfo)
 		}
-		return nil
+		return true
 	})
-	if err != nil {
-		return nil, err
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
-	return result, nil
+	return result, executeErr
 }
 
-// socketDiagExecutor requests diagnoses info from the NETLINK_INET_DIAG socket for the specified request.
-func socketDiagExecutor(req *nl.NetlinkRequest, receiver func(syscall.NetlinkMessage) error) error {
-	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
-	if err != nil {
-		return err
-	}
-	defer s.Close()
-	s.Send(req)
-
-loop:
-	for {
-		msgs, from, err := s.Receive()
-		if err != nil {
-			return err
-		}
-		if from.Pid != nl.PidKernel {
-			return fmt.Errorf("wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
-		}
-		if len(msgs) == 0 {
-			return errors.New("no message nor error from netlink")
-		}
-
-		for _, m := range msgs {
-			switch m.Header.Type {
-			case unix.NLMSG_DONE:
-				break loop
-			case unix.NLMSG_ERROR:
-				error := int32(native.Uint32(m.Data[0:4]))
-				return syscall.Errno(-error)
-			}
-			if err := receiver(m); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
+// UnixSocketDiag requests UNIX_DIAG_INFO for unix sockets.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func UnixSocketDiag() ([]*UnixSocket, error) {
+	return pkgHandle.UnixSocketDiag()
 }
 
 func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {
diff --git a/vendor/github.com/vishvananda/netlink/socket_xdp_linux.go b/vendor/github.com/vishvananda/netlink/socket_xdp_linux.go
new file mode 100644
index 000000000..c1dd00a86
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/socket_xdp_linux.go
@@ -0,0 +1,207 @@
+package netlink
+
+import (
+	"errors"
+	"fmt"
+	"syscall"
+
+	"github.com/vishvananda/netlink/nl"
+	"golang.org/x/sys/unix"
+)
+
+const (
+	sizeofXDPSocketRequest = 1 + 1 + 2 + 4 + 4 + 2*4
+	sizeofXDPSocket        = 0x10
+)
+
+// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L12
+type xdpSocketRequest struct {
+	Family   uint8
+	Protocol uint8
+	pad      uint16
+	Ino      uint32
+	Show     uint32
+	Cookie   [2]uint32
+}
+
+func (r *xdpSocketRequest) Serialize() []byte {
+	b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
+	b.Write(r.Family)
+	b.Write(r.Protocol)
+	native.PutUint16(b.Next(2), r.pad)
+	native.PutUint32(b.Next(4), r.Ino)
+	native.PutUint32(b.Next(4), r.Show)
+	native.PutUint32(b.Next(4), r.Cookie[0])
+	native.PutUint32(b.Next(4), r.Cookie[1])
+	return b.Bytes
+}
+
+func (r *xdpSocketRequest) Len() int { return sizeofXDPSocketRequest }
+
+func (s *XDPSocket) deserialize(b []byte) error {
+	if len(b) < sizeofXDPSocket {
+		return fmt.Errorf("XDP socket data short read (%d); want %d", len(b), sizeofXDPSocket)
+	}
+	rb := readBuffer{Bytes: b}
+	s.Family = rb.Read()
+	s.Type = rb.Read()
+	s.pad = native.Uint16(rb.Next(2))
+	s.Ino = native.Uint32(rb.Next(4))
+	s.Cookie[0] = native.Uint32(rb.Next(4))
+	s.Cookie[1] = native.Uint32(rb.Next(4))
+	return nil
+}
+
+// SocketXDPGetInfo returns the XDP socket identified by its inode number and/or
+// socket cookie. Specify the cookie as SOCK_ANY_COOKIE if
+//
+// If the returned error is [ErrDumpInterrupted], the caller should retry.
+func SocketXDPGetInfo(ino uint32, cookie uint64) (*XDPDiagInfoResp, error) {
+	// We have a problem here: dumping AF_XDP sockets currently does not support
+	// filtering. We thus need to dump all XSKs and then only filter afterwards
+	// :(
+	xsks, err := SocketDiagXDP()
+	if err != nil {
+		return nil, err
+	}
+	checkCookie := cookie != SOCK_ANY_COOKIE && cookie != 0
+	crumblingCookie := [2]uint32{uint32(cookie), uint32(cookie >> 32)}
+	checkIno := ino != 0
+	var xskinfo *XDPDiagInfoResp
+	for _, xsk := range xsks {
+		if checkIno && xsk.XDPDiagMsg.Ino != ino {
+			continue
+		}
+		if checkCookie && xsk.XDPDiagMsg.Cookie != crumblingCookie {
+			continue
+		}
+		if xskinfo != nil {
+			return nil, errors.New("multiple matching XDP sockets")
+		}
+		xskinfo = xsk
+	}
+	if xskinfo == nil {
+		return nil, errors.New("no matching XDP socket")
+	}
+	return xskinfo, nil
+}
+
+// SocketDiagXDP requests XDP_DIAG_INFO for XDP family sockets.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
+func SocketDiagXDP() ([]*XDPDiagInfoResp, error) {
+	var result []*XDPDiagInfoResp
+	err := socketDiagXDPExecutor(func(m syscall.NetlinkMessage) error {
+		sockInfo := &XDPSocket{}
+		if err := sockInfo.deserialize(m.Data); err != nil {
+			return err
+		}
+		attrs, err := nl.ParseRouteAttr(m.Data[sizeofXDPSocket:])
+		if err != nil {
+			return err
+		}
+
+		res, err := attrsToXDPDiagInfoResp(attrs, sockInfo)
+		if err != nil {
+			return err
+		}
+
+		result = append(result, res)
+		return nil
+	})
+	if err != nil && !errors.Is(err, ErrDumpInterrupted) {
+		return nil, err
+	}
+	return result, err
+}
+
+// socketDiagXDPExecutor requests XDP_DIAG_INFO for XDP family sockets.
+func socketDiagXDPExecutor(receiver func(syscall.NetlinkMessage) error) error {
+	s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
+	req.AddData(&xdpSocketRequest{
+		Family: unix.AF_XDP,
+		Show:   XDP_SHOW_INFO | XDP_SHOW_RING_CFG | XDP_SHOW_UMEM | XDP_SHOW_STATS,
+	})
+	if err := s.Send(req); err != nil {
+		return err
+	}
+
+	dumpIntr := false
+loop:
+	for {
+		msgs, from, err := s.Receive()
+		if err != nil {
+			return err
+		}
+		if from.Pid != nl.PidKernel {
+			return fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+		}
+		if len(msgs) == 0 {
+			return errors.New("no message nor error from netlink")
+		}
+
+		for _, m := range msgs {
+			if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 {
+				dumpIntr = true
+			}
+			switch m.Header.Type {
+			case unix.NLMSG_DONE:
+				break loop
+			case unix.NLMSG_ERROR:
+				error := int32(native.Uint32(m.Data[0:4]))
+				return syscall.Errno(-error)
+			}
+			if err := receiver(m); err != nil {
+				return err
+			}
+		}
+	}
+	if dumpIntr {
+		return ErrDumpInterrupted
+	}
+	return nil
+}
+
+func attrsToXDPDiagInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *XDPSocket) (*XDPDiagInfoResp, error) {
+	resp := &XDPDiagInfoResp{
+		XDPDiagMsg: sockInfo,
+		XDPInfo:    &XDPInfo{},
+	}
+	for _, a := range attrs {
+		switch a.Attr.Type {
+		case XDP_DIAG_INFO:
+			resp.XDPInfo.Ifindex = native.Uint32(a.Value[0:4])
+			resp.XDPInfo.QueueID = native.Uint32(a.Value[4:8])
+		case XDP_DIAG_UID:
+			resp.XDPInfo.UID = native.Uint32(a.Value[0:4])
+		case XDP_DIAG_RX_RING:
+			resp.XDPInfo.RxRingEntries = native.Uint32(a.Value[0:4])
+		case XDP_DIAG_TX_RING:
+			resp.XDPInfo.TxRingEntries = native.Uint32(a.Value[0:4])
+		case XDP_DIAG_UMEM_FILL_RING:
+			resp.XDPInfo.UmemFillRingEntries = native.Uint32(a.Value[0:4])
+		case XDP_DIAG_UMEM_COMPLETION_RING:
+			resp.XDPInfo.UmemCompletionRingEntries = native.Uint32(a.Value[0:4])
+		case XDP_DIAG_UMEM:
+			umem := &XDPDiagUmem{}
+			if err := umem.deserialize(a.Value); err != nil {
+				return nil, err
+			}
+			resp.XDPInfo.Umem = umem
+		case XDP_DIAG_STATS:
+			stats := &XDPDiagStats{}
+			if err := stats.deserialize(a.Value); err != nil {
+				return nil, err
+			}
+			resp.XDPInfo.Stats = stats
+		}
+	}
+	return resp, nil
+}
diff --git a/vendor/github.com/vishvananda/netlink/vdpa_linux.go b/vendor/github.com/vishvananda/netlink/vdpa_linux.go
index 7c15986d0..c14877a29 100644
--- a/vendor/github.com/vishvananda/netlink/vdpa_linux.go
+++ b/vendor/github.com/vishvananda/netlink/vdpa_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"syscall"
@@ -118,6 +119,9 @@ func VDPADelDev(name string) error {
 
 // VDPAGetDevList returns list of VDPA devices
 // Equivalent to: `vdpa dev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func VDPAGetDevList() ([]*VDPADev, error) {
 	return pkgHandle.VDPAGetDevList()
 }
@@ -130,6 +134,9 @@ func VDPAGetDevByName(name string) (*VDPADev, error) {
 
 // VDPAGetDevConfigList returns list of VDPA devices configurations
 // Equivalent to: `vdpa dev config show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
 	return pkgHandle.VDPAGetDevConfigList()
 }
@@ -148,6 +155,9 @@ func VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStats, error) {
 
 // VDPAGetMGMTDevList returns list of mgmt devices
 // Equivalent to: `vdpa mgmtdev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
 	return pkgHandle.VDPAGetMGMTDevList()
 }
@@ -261,9 +271,9 @@ func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr)
 		req.AddData(a)
 	}
 
-	resp, err := req.Execute(unix.NETLINK_GENERIC, 0)
-	if err != nil {
-		return nil, err
+	resp, executeErr := req.Execute(unix.NETLINK_GENERIC, 0)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	messages := make([]vdpaNetlinkMessage, 0, len(resp))
 	for _, m := range resp {
@@ -273,10 +283,13 @@ func (h *Handle) vdpaRequest(command uint8, extraFlags int, attrs []*nl.RtAttr)
 		}
 		messages = append(messages, attrs)
 	}
-	return messages, nil
+	return messages, executeErr
 }
 
 // dump all devices if dev is nil
+//
+// If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
 	var extraFlags int
 	var attrs []*nl.RtAttr
@@ -285,9 +298,9 @@ func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
 	} else {
 		extraFlags = extraFlags | unix.NLM_F_DUMP
 	}
-	messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
-	if err != nil {
-		return nil, err
+	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_GET, extraFlags, attrs)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	devs := make([]*VDPADev, 0, len(messages))
 	for _, m := range messages {
@@ -295,10 +308,13 @@ func (h *Handle) vdpaDevGet(dev *string) ([]*VDPADev, error) {
 		d.parseAttributes(m)
 		devs = append(devs, d)
 	}
-	return devs, nil
+	return devs, executeErr
 }
 
 // dump all devices if dev is nil
+//
+// If dev is nil, and the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
 	var extraFlags int
 	var attrs []*nl.RtAttr
@@ -307,9 +323,9 @@ func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
 	} else {
 		extraFlags = extraFlags | unix.NLM_F_DUMP
 	}
-	messages, err := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
-	if err != nil {
-		return nil, err
+	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_DEV_CONFIG_GET, extraFlags, attrs)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	cfgs := make([]*VDPADevConfig, 0, len(messages))
 	for _, m := range messages {
@@ -317,10 +333,13 @@ func (h *Handle) vdpaDevConfigGet(dev *string) ([]*VDPADevConfig, error) {
 		cfg.parseAttributes(m)
 		cfgs = append(cfgs, cfg)
 	}
-	return cfgs, nil
+	return cfgs, executeErr
 }
 
 // dump all devices if dev is nil
+//
+// If dev is nil and the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
 	var extraFlags int
 	var attrs []*nl.RtAttr
@@ -336,9 +355,9 @@ func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
 	} else {
 		extraFlags = extraFlags | unix.NLM_F_DUMP
 	}
-	messages, err := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
-	if err != nil {
-		return nil, err
+	messages, executeErr := h.vdpaRequest(nl.VDPA_CMD_MGMTDEV_GET, extraFlags, attrs)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 	cfgs := make([]*VDPAMGMTDev, 0, len(messages))
 	for _, m := range messages {
@@ -346,7 +365,7 @@ func (h *Handle) vdpaMGMTDevGet(bus, dev *string) ([]*VDPAMGMTDev, error) {
 		cfg.parseAttributes(m)
 		cfgs = append(cfgs, cfg)
 	}
-	return cfgs, nil
+	return cfgs, executeErr
 }
 
 // VDPANewDev adds new VDPA device
@@ -385,6 +404,9 @@ func (h *Handle) VDPADelDev(name string) error {
 
 // VDPAGetDevList returns list of VDPA devices
 // Equivalent to: `vdpa dev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) VDPAGetDevList() ([]*VDPADev, error) {
 	return h.vdpaDevGet(nil)
 }
@@ -404,6 +426,9 @@ func (h *Handle) VDPAGetDevByName(name string) (*VDPADev, error) {
 
 // VDPAGetDevConfigList returns list of VDPA devices configurations
 // Equivalent to: `vdpa dev config show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) VDPAGetDevConfigList() ([]*VDPADevConfig, error) {
 	return h.vdpaDevConfigGet(nil)
 }
@@ -441,6 +466,9 @@ func (h *Handle) VDPAGetDevVStats(name string, queueIndex uint32) (*VDPADevVStat
 
 // VDPAGetMGMTDevList returns list of mgmt devices
 // Equivalent to: `vdpa mgmtdev show`
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) VDPAGetMGMTDevList() ([]*VDPAMGMTDev, error) {
 	return h.vdpaMGMTDevGet(nil, nil)
 }
diff --git a/vendor/github.com/vishvananda/netlink/xdp_diag.go b/vendor/github.com/vishvananda/netlink/xdp_diag.go
new file mode 100644
index 000000000..e88825bf5
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/xdp_diag.go
@@ -0,0 +1,34 @@
+package netlink
+
+import "github.com/vishvananda/netlink/nl"
+
+const SOCK_ANY_COOKIE = uint64(nl.TCPDIAG_NOCOOKIE)<<32 + uint64(nl.TCPDIAG_NOCOOKIE)
+
+// XDP diagnosis show flag constants to request particular information elements.
+const (
+	XDP_SHOW_INFO = 1 << iota
+	XDP_SHOW_RING_CFG
+	XDP_SHOW_UMEM
+	XDP_SHOW_MEMINFO
+	XDP_SHOW_STATS
+)
+
+// XDP diag element constants
+const (
+	XDP_DIAG_NONE                 = iota
+	XDP_DIAG_INFO                 // when using XDP_SHOW_INFO
+	XDP_DIAG_UID                  // when using XDP_SHOW_INFO
+	XDP_DIAG_RX_RING              // when using XDP_SHOW_RING_CFG
+	XDP_DIAG_TX_RING              // when using XDP_SHOW_RING_CFG
+	XDP_DIAG_UMEM                 // when using XDP_SHOW_UMEM
+	XDP_DIAG_UMEM_FILL_RING       // when using XDP_SHOW_UMEM
+	XDP_DIAG_UMEM_COMPLETION_RING // when using XDP_SHOW_UMEM
+	XDP_DIAG_MEMINFO              // when using XDP_SHOW_MEMINFO
+	XDP_DIAG_STATS                // when using XDP_SHOW_STATS
+)
+
+// https://elixir.bootlin.com/linux/v6.2/source/include/uapi/linux/xdp_diag.h#L21
+type XDPDiagInfoResp struct {
+	XDPDiagMsg *XDPSocket
+	XDPInfo    *XDPInfo
+}
diff --git a/vendor/github.com/vishvananda/netlink/xdp_linux.go b/vendor/github.com/vishvananda/netlink/xdp_linux.go
new file mode 100644
index 000000000..896a406de
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/xdp_linux.go
@@ -0,0 +1,46 @@
+package netlink
+
+import (
+	"bytes"
+	"fmt"
+)
+
+const (
+	xdrDiagUmemLen  = 8 + 8*4
+	xdrDiagStatsLen = 6 * 8
+)
+
+func (x *XDPDiagUmem) deserialize(b []byte) error {
+	if len(b) < xdrDiagUmemLen {
+		return fmt.Errorf("XDP umem diagnosis data short read (%d); want %d", len(b), xdrDiagUmemLen)
+	}
+
+	rb := bytes.NewBuffer(b)
+	x.Size = native.Uint64(rb.Next(8))
+	x.ID = native.Uint32(rb.Next(4))
+	x.NumPages = native.Uint32(rb.Next(4))
+	x.ChunkSize = native.Uint32(rb.Next(4))
+	x.Headroom = native.Uint32(rb.Next(4))
+	x.Ifindex = native.Uint32(rb.Next(4))
+	x.QueueID = native.Uint32(rb.Next(4))
+	x.Flags = native.Uint32(rb.Next(4))
+	x.Refs = native.Uint32(rb.Next(4))
+
+	return nil
+}
+
+func (x *XDPDiagStats) deserialize(b []byte) error {
+	if len(b) < xdrDiagStatsLen {
+		return fmt.Errorf("XDP diagnosis statistics short read (%d); want %d", len(b), xdrDiagStatsLen)
+	}
+
+	rb := bytes.NewBuffer(b)
+	x.RxDropped = native.Uint64(rb.Next(8))
+	x.RxInvalid = native.Uint64(rb.Next(8))
+	x.RxFull = native.Uint64(rb.Next(8))
+	x.FillRingEmpty = native.Uint64(rb.Next(8))
+	x.TxInvalid = native.Uint64(rb.Next(8))
+	x.TxRingEmpty = native.Uint64(rb.Next(8))
+
+	return nil
+}
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
index d526739ce..bf143a1b1 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 
@@ -215,6 +216,9 @@ func (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error {
 // XfrmPolicyList gets a list of xfrm policies in the system.
 // Equivalent to: `ip xfrm policy show`.
 // The list can be filtered by ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 	return pkgHandle.XfrmPolicyList(family)
 }
@@ -222,15 +226,18 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 // XfrmPolicyList gets a list of xfrm policies in the system.
 // Equivalent to: `ip xfrm policy show`.
 // The list can be filtered by ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 	req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP)
 
 	msg := nl.NewIfInfomsg(family)
 	req.AddData(msg)
 
-	msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []XfrmPolicy
@@ -243,7 +250,7 @@ func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 			return nil, err
 		}
 	}
-	return res, nil
+	return res, executeErr
 }
 
 // XfrmPolicyGet gets a the policy described by the index or selector, if found.
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
index 554f2498c..2f4614651 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"time"
@@ -382,6 +383,9 @@ func (h *Handle) XfrmStateDel(state *XfrmState) error {
 // XfrmStateList gets a list of xfrm states in the system.
 // Equivalent to: `ip [-4|-6] xfrm state show`.
 // The list can be filtered by ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func XfrmStateList(family int) ([]XfrmState, error) {
 	return pkgHandle.XfrmStateList(family)
 }
@@ -389,12 +393,15 @@ func XfrmStateList(family int) ([]XfrmState, error) {
 // XfrmStateList gets a list of xfrm states in the system.
 // Equivalent to: `ip xfrm state show`.
 // The list can be filtered by ip family.
+//
+// If the returned error is [ErrDumpInterrupted], results may be inconsistent
+// or incomplete.
 func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
 	req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, unix.NLM_F_DUMP)
 
-	msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
-	if err != nil {
-		return nil, err
+	msgs, executeErr := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
+	if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
+		return nil, executeErr
 	}
 
 	var res []XfrmState
@@ -407,7 +414,7 @@ func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
 			return nil, err
 		}
 	}
-	return res, nil
+	return res, executeErr
 }
 
 // XfrmStateGet gets the xfrm state described by the ID, if found.
diff --git a/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
new file mode 100644
index 000000000..3674914f7
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/runtime/runtime.go
@@ -0,0 +1,177 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package runtime
+
+import (
+	"fmt"
+	"net/http"
+	"runtime"
+	"sync"
+	"time"
+
+	"k8s.io/klog/v2"
+)
+
+var (
+	// ReallyCrash controls the behavior of HandleCrash and defaults to
+	// true. It's exposed so components can optionally set to false
+	// to restore prior behavior. This flag is mostly used for tests to validate
+	// crash conditions.
+	ReallyCrash = true
+)
+
+// PanicHandlers is a list of functions which will be invoked when a panic happens.
+var PanicHandlers = []func(interface{}){logPanic}
+
+// HandleCrash simply catches a crash and logs an error. Meant to be called via
+// defer.  Additional context-specific handlers can be provided, and will be
+// called in case of panic.  HandleCrash actually crashes, after calling the
+// handlers and logging the panic message.
+//
+// E.g., you can provide one or more additional handlers for something like shutting down go routines gracefully.
+func HandleCrash(additionalHandlers ...func(interface{})) {
+	if r := recover(); r != nil {
+		for _, fn := range PanicHandlers {
+			fn(r)
+		}
+		for _, fn := range additionalHandlers {
+			fn(r)
+		}
+		if ReallyCrash {
+			// Actually proceed to panic.
+			panic(r)
+		}
+	}
+}
+
+// logPanic logs the caller tree when a panic occurs (except in the special case of http.ErrAbortHandler).
+func logPanic(r interface{}) {
+	if r == http.ErrAbortHandler {
+		// honor the http.ErrAbortHandler sentinel panic value:
+		//   ErrAbortHandler is a sentinel panic value to abort a handler.
+		//   While any panic from ServeHTTP aborts the response to the client,
+		//   panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log.
+		return
+	}
+
+	// Same as stdlib http server code. Manually allocate stack trace buffer size
+	// to prevent excessively large logs
+	const size = 64 << 10
+	stacktrace := make([]byte, size)
+	stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
+	if _, ok := r.(string); ok {
+		klog.Errorf("Observed a panic: %s\n%s", r, stacktrace)
+	} else {
+		klog.Errorf("Observed a panic: %#v (%v)\n%s", r, r, stacktrace)
+	}
+}
+
+// ErrorHandlers is a list of functions which will be invoked when a nonreturnable
+// error occurs.
+// TODO(lavalamp): for testability, this and the below HandleError function
+// should be packaged up into a testable and reusable object.
+var ErrorHandlers = []func(error){
+	logError,
+	(&rudimentaryErrorBackoff{
+		lastErrorTime: time.Now(),
+		// 1ms was the number folks were able to stomach as a global rate limit.
+		// If you need to log errors more than 1000 times a second you
+		// should probably consider fixing your code instead. :)
+		minPeriod: time.Millisecond,
+	}).OnError,
+}
+
+// HandlerError is a method to invoke when a non-user facing piece of code cannot
+// return an error and needs to indicate it has been ignored. Invoking this method
+// is preferable to logging the error - the default behavior is to log but the
+// errors may be sent to a remote server for analysis.
+func HandleError(err error) {
+	// this is sometimes called with a nil error.  We probably shouldn't fail and should do nothing instead
+	if err == nil {
+		return
+	}
+
+	for _, fn := range ErrorHandlers {
+		fn(err)
+	}
+}
+
+// logError prints an error with the call stack of the location it was reported
+func logError(err error) {
+	klog.ErrorDepth(2, err)
+}
+
+type rudimentaryErrorBackoff struct {
+	minPeriod time.Duration // immutable
+	// TODO(lavalamp): use the clock for testability. Need to move that
+	// package for that to be accessible here.
+	lastErrorTimeLock sync.Mutex
+	lastErrorTime     time.Time
+}
+
+// OnError will block if it is called more often than the embedded period time.
+// This will prevent overly tight hot error loops.
+func (r *rudimentaryErrorBackoff) OnError(error) {
+	now := time.Now() // start the timer before acquiring the lock
+	r.lastErrorTimeLock.Lock()
+	d := now.Sub(r.lastErrorTime)
+	r.lastErrorTime = time.Now()
+	r.lastErrorTimeLock.Unlock()
+
+	// Do not sleep with the lock held because that causes all callers of HandleError to block.
+	// We only want the current goroutine to block.
+	// A negative or zero duration causes time.Sleep to return immediately.
+	// If the time moves backwards for any reason, do nothing.
+	time.Sleep(r.minPeriod - d)
+}
+
+// GetCaller returns the caller of the function that calls it.
+func GetCaller() string {
+	var pc [1]uintptr
+	runtime.Callers(3, pc[:])
+	f := runtime.FuncForPC(pc[0])
+	if f == nil {
+		return "Unable to find caller"
+	}
+	return f.Name()
+}
+
+// RecoverFromPanic replaces the specified error with an error containing the
+// original error, and  the call tree when a panic occurs. This enables error
+// handlers to handle errors and panics the same way.
+func RecoverFromPanic(err *error) {
+	if r := recover(); r != nil {
+		// Same as stdlib http server code. Manually allocate stack trace buffer size
+		// to prevent excessively large logs
+		const size = 64 << 10
+		stacktrace := make([]byte, size)
+		stacktrace = stacktrace[:runtime.Stack(stacktrace, false)]
+
+		*err = fmt.Errorf(
+			"recovered from panic %q. (err=%v) Call stack:\n%s",
+			r,
+			*err,
+			stacktrace)
+	}
+}
+
+// Must panics on non-nil errors. Useful to handling programmer level errors.
+func Must(err error) {
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go b/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go
new file mode 100644
index 000000000..418761925
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go
@@ -0,0 +1,502 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"math"
+	"sync"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/runtime"
+	"k8s.io/utils/clock"
+)
+
+// Backoff holds parameters applied to a Backoff function.
+type Backoff struct {
+	// The initial duration.
+	Duration time.Duration
+	// Duration is multiplied by factor each iteration, if factor is not zero
+	// and the limits imposed by Steps and Cap have not been reached.
+	// Should not be negative.
+	// The jitter does not contribute to the updates to the duration parameter.
+	Factor float64
+	// The sleep at each iteration is the duration plus an additional
+	// amount chosen uniformly at random from the interval between
+	// zero and `jitter*duration`.
+	Jitter float64
+	// The remaining number of iterations in which the duration
+	// parameter may change (but progress can be stopped earlier by
+	// hitting the cap). If not positive, the duration is not
+	// changed. Used for exponential backoff in combination with
+	// Factor and Cap.
+	Steps int
+	// A limit on revised values of the duration parameter. If a
+	// multiplication by the factor parameter would make the duration
+	// exceed the cap then the duration is set to the cap and the
+	// steps parameter is set to zero.
+	Cap time.Duration
+}
+
+// Step returns an amount of time to sleep determined by the original
+// Duration and Jitter. The backoff is mutated to update its Steps and
+// Duration. A nil Backoff always has a zero-duration step.
+func (b *Backoff) Step() time.Duration {
+	if b == nil {
+		return 0
+	}
+	var nextDuration time.Duration
+	nextDuration, b.Duration, b.Steps = delay(b.Steps, b.Duration, b.Cap, b.Factor, b.Jitter)
+	return nextDuration
+}
+
+// DelayFunc returns a function that will compute the next interval to
+// wait given the arguments in b. It does not mutate the original backoff
+// but the function is safe to use only from a single goroutine.
+func (b Backoff) DelayFunc() DelayFunc {
+	steps := b.Steps
+	duration := b.Duration
+	cap := b.Cap
+	factor := b.Factor
+	jitter := b.Jitter
+
+	return func() time.Duration {
+		var nextDuration time.Duration
+		// jitter is applied per step and is not cumulative over multiple steps
+		nextDuration, duration, steps = delay(steps, duration, cap, factor, jitter)
+		return nextDuration
+	}
+}
+
+// Timer returns a timer implementation appropriate to this backoff's parameters
+// for use with wait functions.
+func (b Backoff) Timer() Timer {
+	if b.Steps > 1 || b.Jitter != 0 {
+		return &variableTimer{new: internalClock.NewTimer, fn: b.DelayFunc()}
+	}
+	if b.Duration > 0 {
+		return &fixedTimer{new: internalClock.NewTicker, interval: b.Duration}
+	}
+	return newNoopTimer()
+}
+
+// delay implements the core delay algorithm used in this package.
+func delay(steps int, duration, cap time.Duration, factor, jitter float64) (_ time.Duration, next time.Duration, nextSteps int) {
+	// when steps is non-positive, do not alter the base duration
+	if steps < 1 {
+		if jitter > 0 {
+			return Jitter(duration, jitter), duration, 0
+		}
+		return duration, duration, 0
+	}
+	steps--
+
+	// calculate the next step's interval
+	if factor != 0 {
+		next = time.Duration(float64(duration) * factor)
+		if cap > 0 && next > cap {
+			next = cap
+			steps = 0
+		}
+	} else {
+		next = duration
+	}
+
+	// add jitter for this step
+	if jitter > 0 {
+		duration = Jitter(duration, jitter)
+	}
+
+	return duration, next, steps
+
+}
+
+// DelayWithReset returns a DelayFunc that will return the appropriate next interval to
+// wait. Every resetInterval the backoff parameters are reset to their initial state.
+// This method is safe to invoke from multiple goroutines, but all calls will advance
+// the backoff state when Factor is set. If Factor is zero, this method is the same as
+// invoking b.DelayFunc() since Steps has no impact without Factor. If resetInterval is
+// zero no backoff will be performed as the same calling DelayFunc with a zero factor
+// and steps.
+func (b Backoff) DelayWithReset(c clock.Clock, resetInterval time.Duration) DelayFunc {
+	if b.Factor <= 0 {
+		return b.DelayFunc()
+	}
+	if resetInterval <= 0 {
+		b.Steps = 0
+		b.Factor = 0
+		return b.DelayFunc()
+	}
+	return (&backoffManager{
+		backoff:        b,
+		initialBackoff: b,
+		resetInterval:  resetInterval,
+
+		clock:     c,
+		lastStart: c.Now(),
+		timer:     nil,
+	}).Step
+}
+
+// Until loops until stop channel is closed, running f every period.
+//
+// Until is syntactic sugar on top of JitterUntil with zero jitter factor and
+// with sliding = true (which means the timer for period starts after the f
+// completes).
+func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
+	JitterUntil(f, period, 0.0, true, stopCh)
+}
+
+// UntilWithContext loops until context is done, running f every period.
+//
+// UntilWithContext is syntactic sugar on top of JitterUntilWithContext
+// with zero jitter factor and with sliding = true (which means the timer
+// for period starts after the f completes).
+func UntilWithContext(ctx context.Context, f func(context.Context), period time.Duration) {
+	JitterUntilWithContext(ctx, f, period, 0.0, true)
+}
+
+// NonSlidingUntil loops until stop channel is closed, running f every
+// period.
+//
+// NonSlidingUntil is syntactic sugar on top of JitterUntil with zero jitter
+// factor, with sliding = false (meaning the timer for period starts at the same
+// time as the function starts).
+func NonSlidingUntil(f func(), period time.Duration, stopCh <-chan struct{}) {
+	JitterUntil(f, period, 0.0, false, stopCh)
+}
+
+// NonSlidingUntilWithContext loops until context is done, running f every
+// period.
+//
+// NonSlidingUntilWithContext is syntactic sugar on top of JitterUntilWithContext
+// with zero jitter factor, with sliding = false (meaning the timer for period
+// starts at the same time as the function starts).
+func NonSlidingUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration) {
+	JitterUntilWithContext(ctx, f, period, 0.0, false)
+}
+
+// JitterUntil loops until stop channel is closed, running f every period.
+//
+// If jitterFactor is positive, the period is jittered before every run of f.
+// If jitterFactor is not positive, the period is unchanged and not jittered.
+//
+// If sliding is true, the period is computed after f runs. If it is false then
+// period includes the runtime for f.
+//
+// Close stopCh to stop. f may not be invoked if stop channel is already
+// closed. Pass NeverStop to if you don't want it stop.
+func JitterUntil(f func(), period time.Duration, jitterFactor float64, sliding bool, stopCh <-chan struct{}) {
+	BackoffUntil(f, NewJitteredBackoffManager(period, jitterFactor, &clock.RealClock{}), sliding, stopCh)
+}
+
+// BackoffUntil loops until stop channel is closed, run f every duration given by BackoffManager.
+//
+// If sliding is true, the period is computed after f runs. If it is false then
+// period includes the runtime for f.
+func BackoffUntil(f func(), backoff BackoffManager, sliding bool, stopCh <-chan struct{}) {
+	var t clock.Timer
+	for {
+		select {
+		case <-stopCh:
+			return
+		default:
+		}
+
+		if !sliding {
+			t = backoff.Backoff()
+		}
+
+		func() {
+			defer runtime.HandleCrash()
+			f()
+		}()
+
+		if sliding {
+			t = backoff.Backoff()
+		}
+
+		// NOTE: b/c there is no priority selection in golang
+		// it is possible for this to race, meaning we could
+		// trigger t.C and stopCh, and t.C select falls through.
+		// In order to mitigate we re-check stopCh at the beginning
+		// of every loop to prevent extra executions of f().
+		select {
+		case <-stopCh:
+			if !t.Stop() {
+				<-t.C()
+			}
+			return
+		case <-t.C():
+		}
+	}
+}
+
+// JitterUntilWithContext loops until context is done, running f every period.
+//
+// If jitterFactor is positive, the period is jittered before every run of f.
+// If jitterFactor is not positive, the period is unchanged and not jittered.
+//
+// If sliding is true, the period is computed after f runs. If it is false then
+// period includes the runtime for f.
+//
+// Cancel context to stop. f may not be invoked if context is already expired.
+func JitterUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration, jitterFactor float64, sliding bool) {
+	JitterUntil(func() { f(ctx) }, period, jitterFactor, sliding, ctx.Done())
+}
+
+// backoffManager provides simple backoff behavior in a threadsafe manner to a caller.
+type backoffManager struct {
+	backoff        Backoff
+	initialBackoff Backoff
+	resetInterval  time.Duration
+
+	clock clock.Clock
+
+	lock      sync.Mutex
+	lastStart time.Time
+	timer     clock.Timer
+}
+
+// Step returns the expected next duration to wait.
+func (b *backoffManager) Step() time.Duration {
+	b.lock.Lock()
+	defer b.lock.Unlock()
+
+	switch {
+	case b.resetInterval == 0:
+		b.backoff = b.initialBackoff
+	case b.clock.Now().Sub(b.lastStart) > b.resetInterval:
+		b.backoff = b.initialBackoff
+		b.lastStart = b.clock.Now()
+	}
+	return b.backoff.Step()
+}
+
+// Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer
+// for exponential backoff. The returned timer must be drained before calling Backoff() the second
+// time.
+func (b *backoffManager) Backoff() clock.Timer {
+	b.lock.Lock()
+	defer b.lock.Unlock()
+	if b.timer == nil {
+		b.timer = b.clock.NewTimer(b.Step())
+	} else {
+		b.timer.Reset(b.Step())
+	}
+	return b.timer
+}
+
+// Timer returns a new Timer instance that shares the clock and the reset behavior with all other
+// timers.
+func (b *backoffManager) Timer() Timer {
+	return DelayFunc(b.Step).Timer(b.clock)
+}
+
+// BackoffManager manages backoff with a particular scheme based on its underlying implementation.
+type BackoffManager interface {
+	// Backoff returns a shared clock.Timer that is Reset on every invocation. This method is not
+	// safe for use from multiple threads. It returns a timer for backoff, and caller shall backoff
+	// until Timer.C() drains. If the second Backoff() is called before the timer from the first
+	// Backoff() call finishes, the first timer will NOT be drained and result in undetermined
+	// behavior.
+	Backoff() clock.Timer
+}
+
+// Deprecated: Will be removed when the legacy polling functions are removed.
+type exponentialBackoffManagerImpl struct {
+	backoff              *Backoff
+	backoffTimer         clock.Timer
+	lastBackoffStart     time.Time
+	initialBackoff       time.Duration
+	backoffResetDuration time.Duration
+	clock                clock.Clock
+}
+
+// NewExponentialBackoffManager returns a manager for managing exponential backoff. Each backoff is jittered and
+// backoff will not exceed the given max. If the backoff is not called within resetDuration, the backoff is reset.
+// This backoff manager is used to reduce load during upstream unhealthiness.
+//
+// Deprecated: Will be removed when the legacy Poll methods are removed. Callers should construct a
+// Backoff struct, use DelayWithReset() to get a DelayFunc that periodically resets itself, and then
+// invoke Timer() when calling wait.BackoffUntil.
+//
+// Instead of:
+//
+//	bm := wait.NewExponentialBackoffManager(init, max, reset, factor, jitter, clock)
+//	...
+//	wait.BackoffUntil(..., bm.Backoff, ...)
+//
+// Use:
+//
+//	delayFn := wait.Backoff{
+//	  Duration: init,
+//	  Cap:      max,
+//	  Steps:    int(math.Ceil(float64(max) / float64(init))), // now a required argument
+//	  Factor:   factor,
+//	  Jitter:   jitter,
+//	}.DelayWithReset(reset, clock)
+//	wait.BackoffUntil(..., delayFn.Timer(), ...)
+func NewExponentialBackoffManager(initBackoff, maxBackoff, resetDuration time.Duration, backoffFactor, jitter float64, c clock.Clock) BackoffManager {
+	return &exponentialBackoffManagerImpl{
+		backoff: &Backoff{
+			Duration: initBackoff,
+			Factor:   backoffFactor,
+			Jitter:   jitter,
+
+			// the current impl of wait.Backoff returns Backoff.Duration once steps are used up, which is not
+			// what we ideally need here, we set it to max int and assume we will never use up the steps
+			Steps: math.MaxInt32,
+			Cap:   maxBackoff,
+		},
+		backoffTimer:         nil,
+		initialBackoff:       initBackoff,
+		lastBackoffStart:     c.Now(),
+		backoffResetDuration: resetDuration,
+		clock:                c,
+	}
+}
+
+func (b *exponentialBackoffManagerImpl) getNextBackoff() time.Duration {
+	if b.clock.Now().Sub(b.lastBackoffStart) > b.backoffResetDuration {
+		b.backoff.Steps = math.MaxInt32
+		b.backoff.Duration = b.initialBackoff
+	}
+	b.lastBackoffStart = b.clock.Now()
+	return b.backoff.Step()
+}
+
+// Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for exponential backoff.
+// The returned timer must be drained before calling Backoff() the second time
+func (b *exponentialBackoffManagerImpl) Backoff() clock.Timer {
+	if b.backoffTimer == nil {
+		b.backoffTimer = b.clock.NewTimer(b.getNextBackoff())
+	} else {
+		b.backoffTimer.Reset(b.getNextBackoff())
+	}
+	return b.backoffTimer
+}
+
+// Deprecated: Will be removed when the legacy polling functions are removed.
+type jitteredBackoffManagerImpl struct {
+	clock        clock.Clock
+	duration     time.Duration
+	jitter       float64
+	backoffTimer clock.Timer
+}
+
+// NewJitteredBackoffManager returns a BackoffManager that backoffs with given duration plus given jitter. If the jitter
+// is negative, backoff will not be jittered.
+//
+// Deprecated: Will be removed when the legacy Poll methods are removed. Callers should construct a
+// Backoff struct and invoke Timer() when calling wait.BackoffUntil.
+//
+// Instead of:
+//
+//	bm := wait.NewJitteredBackoffManager(duration, jitter, clock)
+//	...
+//	wait.BackoffUntil(..., bm.Backoff, ...)
+//
+// Use:
+//
+//	wait.BackoffUntil(..., wait.Backoff{Duration: duration, Jitter: jitter}.Timer(), ...)
+func NewJitteredBackoffManager(duration time.Duration, jitter float64, c clock.Clock) BackoffManager {
+	return &jitteredBackoffManagerImpl{
+		clock:        c,
+		duration:     duration,
+		jitter:       jitter,
+		backoffTimer: nil,
+	}
+}
+
+func (j *jitteredBackoffManagerImpl) getNextBackoff() time.Duration {
+	jitteredPeriod := j.duration
+	if j.jitter > 0.0 {
+		jitteredPeriod = Jitter(j.duration, j.jitter)
+	}
+	return jitteredPeriod
+}
+
+// Backoff implements BackoffManager.Backoff, it returns a timer so caller can block on the timer for jittered backoff.
+// The returned timer must be drained before calling Backoff() the second time
+func (j *jitteredBackoffManagerImpl) Backoff() clock.Timer {
+	backoff := j.getNextBackoff()
+	if j.backoffTimer == nil {
+		j.backoffTimer = j.clock.NewTimer(backoff)
+	} else {
+		j.backoffTimer.Reset(backoff)
+	}
+	return j.backoffTimer
+}
+
+// ExponentialBackoff repeats a condition check with exponential backoff.
+//
+// It repeatedly checks the condition and then sleeps, using `backoff.Step()`
+// to determine the length of the sleep and adjust Duration and Steps.
+// Stops and returns as soon as:
+// 1. the condition check returns true or an error,
+// 2. `backoff.Steps` checks of the condition have been done, or
+// 3. a sleep truncated by the cap on duration has been completed.
+// In case (1) the returned error is what the condition function returned.
+// In all other cases, ErrWaitTimeout is returned.
+//
+// Since backoffs are often subject to cancellation, we recommend using
+// ExponentialBackoffWithContext and passing a context to the method.
+func ExponentialBackoff(backoff Backoff, condition ConditionFunc) error {
+	for backoff.Steps > 0 {
+		if ok, err := runConditionWithCrashProtection(condition); err != nil || ok {
+			return err
+		}
+		if backoff.Steps == 1 {
+			break
+		}
+		time.Sleep(backoff.Step())
+	}
+	return ErrWaitTimeout
+}
+
+// ExponentialBackoffWithContext repeats a condition check with exponential backoff.
+// It immediately returns an error if the condition returns an error, the context is cancelled
+// or hits the deadline, or if the maximum attempts defined in backoff is exceeded (ErrWaitTimeout).
+// If an error is returned by the condition the backoff stops immediately. The condition will
+// never be invoked more than backoff.Steps times.
+func ExponentialBackoffWithContext(ctx context.Context, backoff Backoff, condition ConditionWithContextFunc) error {
+	for backoff.Steps > 0 {
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		default:
+		}
+
+		if ok, err := runConditionWithCrashProtectionWithContext(ctx, condition); err != nil || ok {
+			return err
+		}
+
+		if backoff.Steps == 1 {
+			break
+		}
+
+		waitBeforeRetry := backoff.Step()
+		select {
+		case <-ctx.Done():
+			return ctx.Err()
+		case <-time.After(waitBeforeRetry):
+		}
+	}
+
+	return ErrWaitTimeout
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/delay.go b/vendor/k8s.io/apimachinery/pkg/util/wait/delay.go
new file mode 100644
index 000000000..1d3dcaa74
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/delay.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"sync"
+	"time"
+
+	"k8s.io/utils/clock"
+)
+
+// DelayFunc returns the next time interval to wait.
+type DelayFunc func() time.Duration
+
+// Timer takes an arbitrary delay function and returns a timer that can handle arbitrary interval changes.
+// Use Backoff{...}.Timer() for simple delays and more efficient timers.
+func (fn DelayFunc) Timer(c clock.Clock) Timer {
+	return &variableTimer{fn: fn, new: c.NewTimer}
+}
+
+// Until takes an arbitrary delay function and runs until cancelled or the condition indicates exit. This
+// offers all of the functionality of the methods in this package.
+func (fn DelayFunc) Until(ctx context.Context, immediate, sliding bool, condition ConditionWithContextFunc) error {
+	return loopConditionUntilContext(ctx, &variableTimer{fn: fn, new: internalClock.NewTimer}, immediate, sliding, condition)
+}
+
+// Concurrent returns a version of this DelayFunc that is safe for use by multiple goroutines that
+// wish to share a single delay timer.
+func (fn DelayFunc) Concurrent() DelayFunc {
+	var lock sync.Mutex
+	return func() time.Duration {
+		lock.Lock()
+		defer lock.Unlock()
+		return fn()
+	}
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go b/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go
new file mode 100644
index 000000000..3f0c968ec
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/doc.go
@@ -0,0 +1,19 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package wait provides tools for polling or listening for changes
+// to a condition.
+package wait // import "k8s.io/apimachinery/pkg/util/wait"
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/error.go b/vendor/k8s.io/apimachinery/pkg/util/wait/error.go
new file mode 100644
index 000000000..dd75801d8
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/error.go
@@ -0,0 +1,96 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"errors"
+)
+
+// ErrWaitTimeout is returned when the condition was not satisfied in time.
+//
+// Deprecated: This type will be made private in favor of Interrupted()
+// for checking errors or ErrorInterrupted(err) for returning a wrapped error.
+var ErrWaitTimeout = ErrorInterrupted(errors.New("timed out waiting for the condition"))
+
+// Interrupted returns true if the error indicates a Poll, ExponentialBackoff, or
+// Until loop exited for any reason besides the condition returning true or an
+// error. A loop is considered interrupted if the calling context is cancelled,
+// the context reaches its deadline, or a backoff reaches its maximum allowed
+// steps.
+//
+// Callers should use this method instead of comparing the error value directly to
+// ErrWaitTimeout, as methods that cancel a context may not return that error.
+//
+// Instead of:
+//
+//	err := wait.Poll(...)
+//	if err == wait.ErrWaitTimeout {
+//	    log.Infof("Wait for operation exceeded")
+//	} else ...
+//
+// Use:
+//
+//	err := wait.Poll(...)
+//	if wait.Interrupted(err) {
+//	    log.Infof("Wait for operation exceeded")
+//	} else ...
+func Interrupted(err error) bool {
+	switch {
+	case errors.Is(err, errWaitTimeout),
+		errors.Is(err, context.Canceled),
+		errors.Is(err, context.DeadlineExceeded):
+		return true
+	default:
+		return false
+	}
+}
+
+// errInterrupted
+type errInterrupted struct {
+	cause error
+}
+
+// ErrorInterrupted returns an error that indicates the wait was ended
+// early for a given reason. If no cause is provided a generic error
+// will be used but callers are encouraged to provide a real cause for
+// clarity in debugging.
+func ErrorInterrupted(cause error) error {
+	switch cause.(type) {
+	case errInterrupted:
+		// no need to wrap twice since errInterrupted is only needed
+		// once in a chain
+		return cause
+	default:
+		return errInterrupted{cause}
+	}
+}
+
+// errWaitTimeout is the private version of the previous ErrWaitTimeout
+// and is private to prevent direct comparison. Use ErrorInterrupted(err)
+// to get an error that will return true for Interrupted(err).
+var errWaitTimeout = errInterrupted{}
+
+func (e errInterrupted) Unwrap() error        { return e.cause }
+func (e errInterrupted) Is(target error) bool { return target == errWaitTimeout }
+func (e errInterrupted) Error() string {
+	if e.cause == nil {
+		// returns the same error message as historical behavior
+		return "timed out waiting for the condition"
+	}
+	return e.cause.Error()
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go b/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go
new file mode 100644
index 000000000..107bfc132
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/loop.go
@@ -0,0 +1,95 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/runtime"
+)
+
+// loopConditionUntilContext executes the provided condition at intervals defined by
+// the provided timer until the provided context is cancelled, the condition returns
+// true, or the condition returns an error. If sliding is true, the period is computed
+// after condition runs. If it is false then period includes the runtime for condition.
+// If immediate is false the first delay happens before any call to condition, if
+// immediate is true the condition will be invoked before waiting and guarantees that
+// the condition is invoked at least once, regardless of whether the context has been
+// cancelled. The returned error is the error returned by the last condition or the
+// context error if the context was terminated.
+//
+// This is the common loop construct for all polling in the wait package.
+func loopConditionUntilContext(ctx context.Context, t Timer, immediate, sliding bool, condition ConditionWithContextFunc) error {
+	defer t.Stop()
+
+	var timeCh <-chan time.Time
+	doneCh := ctx.Done()
+
+	if !sliding {
+		timeCh = t.C()
+	}
+
+	// if immediate is true the condition is
+	// guaranteed to be executed at least once,
+	// if we haven't requested immediate execution, delay once
+	if immediate {
+		if ok, err := func() (bool, error) {
+			defer runtime.HandleCrash()
+			return condition(ctx)
+		}(); err != nil || ok {
+			return err
+		}
+	}
+
+	if sliding {
+		timeCh = t.C()
+	}
+
+	for {
+
+		// Wait for either the context to be cancelled or the next invocation be called
+		select {
+		case <-doneCh:
+			return ctx.Err()
+		case <-timeCh:
+		}
+
+		// IMPORTANT: Because there is no channel priority selection in golang
+		// it is possible for very short timers to "win" the race in the previous select
+		// repeatedly even when the context has been canceled.  We therefore must
+		// explicitly check for context cancellation on every loop and exit if true to
+		// guarantee that we don't invoke condition more than once after context has
+		// been cancelled.
+		if err := ctx.Err(); err != nil {
+			return err
+		}
+
+		if !sliding {
+			t.Next()
+		}
+		if ok, err := func() (bool, error) {
+			defer runtime.HandleCrash()
+			return condition(ctx)
+		}(); err != nil || ok {
+			return err
+		}
+		if sliding {
+			t.Next()
+		}
+	}
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/poll.go b/vendor/k8s.io/apimachinery/pkg/util/wait/poll.go
new file mode 100644
index 000000000..231d4c384
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/poll.go
@@ -0,0 +1,315 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"time"
+)
+
+// PollUntilContextCancel tries a condition func until it returns true, an error, or the context
+// is cancelled or hits a deadline. condition will be invoked after the first interval if the
+// context is not cancelled first. The returned error will be from ctx.Err(), the condition's
+// err return value, or nil. If invoking condition takes longer than interval the next condition
+// will be invoked immediately. When using very short intervals, condition may be invoked multiple
+// times before a context cancellation is detected. If immediate is true, condition will be
+// invoked before waiting and guarantees that condition is invoked at least once, regardless of
+// whether the context has been cancelled.
+func PollUntilContextCancel(ctx context.Context, interval time.Duration, immediate bool, condition ConditionWithContextFunc) error {
+	return loopConditionUntilContext(ctx, Backoff{Duration: interval}.Timer(), immediate, false, condition)
+}
+
+// PollUntilContextTimeout will terminate polling after timeout duration by setting a context
+// timeout. This is provided as a convenience function for callers not currently executing under
+// a deadline and is equivalent to:
+//
+//	deadlineCtx, deadlineCancel := context.WithTimeout(ctx, timeout)
+//	err := PollUntilContextCancel(deadlineCtx, interval, immediate, condition)
+//
+// The deadline context will be cancelled if the Poll succeeds before the timeout, simplifying
+// inline usage. All other behavior is identical to PollUntilContextCancel.
+func PollUntilContextTimeout(ctx context.Context, interval, timeout time.Duration, immediate bool, condition ConditionWithContextFunc) error {
+	deadlineCtx, deadlineCancel := context.WithTimeout(ctx, timeout)
+	defer deadlineCancel()
+	return loopConditionUntilContext(deadlineCtx, Backoff{Duration: interval}.Timer(), immediate, false, condition)
+}
+
+// Poll tries a condition func until it returns true, an error, or the timeout
+// is reached.
+//
+// Poll always waits the interval before the run of 'condition'.
+// 'condition' will always be invoked at least once.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// If you want to Poll something forever, see PollInfinite.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextTimeout.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func Poll(interval, timeout time.Duration, condition ConditionFunc) error {
+	return PollWithContext(context.Background(), interval, timeout, condition.WithContext())
+}
+
+// PollWithContext tries a condition func until it returns true, an error,
+// or when the context expires or the timeout is reached, whichever
+// happens first.
+//
+// PollWithContext always waits the interval before the run of 'condition'.
+// 'condition' will always be invoked at least once.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// If you want to Poll something forever, see PollInfinite.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextTimeout.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollWithContext(ctx context.Context, interval, timeout time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, false, poller(interval, timeout), condition)
+}
+
+// PollUntil tries a condition func until it returns true, an error or stopCh is
+// closed.
+//
+// PollUntil always waits interval before the first run of 'condition'.
+// 'condition' will always be invoked at least once.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
+	return PollUntilWithContext(ContextForChannel(stopCh), interval, condition.WithContext())
+}
+
+// PollUntilWithContext tries a condition func until it returns true,
+// an error or the specified context is cancelled or expired.
+//
+// PollUntilWithContext always waits interval before the first run of 'condition'.
+// 'condition' will always be invoked at least once.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollUntilWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, false, poller(interval, 0), condition)
+}
+
+// PollInfinite tries a condition func until it returns true or an error
+//
+// PollInfinite always waits the interval before the run of 'condition'.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollInfinite(interval time.Duration, condition ConditionFunc) error {
+	return PollInfiniteWithContext(context.Background(), interval, condition.WithContext())
+}
+
+// PollInfiniteWithContext tries a condition func until it returns true or an error
+//
+// PollInfiniteWithContext always waits the interval before the run of 'condition'.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollInfiniteWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, false, poller(interval, 0), condition)
+}
+
+// PollImmediate tries a condition func until it returns true, an error, or the timeout
+// is reached.
+//
+// PollImmediate always checks 'condition' before waiting for the interval. 'condition'
+// will always be invoked at least once.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// If you want to immediately Poll something forever, see PollImmediateInfinite.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextTimeout.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediate(interval, timeout time.Duration, condition ConditionFunc) error {
+	return PollImmediateWithContext(context.Background(), interval, timeout, condition.WithContext())
+}
+
+// PollImmediateWithContext tries a condition func until it returns true, an error,
+// or the timeout is reached or the specified context expires, whichever happens first.
+//
+// PollImmediateWithContext always checks 'condition' before waiting for the interval.
+// 'condition' will always be invoked at least once.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// If you want to immediately Poll something forever, see PollImmediateInfinite.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextTimeout.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediateWithContext(ctx context.Context, interval, timeout time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, true, poller(interval, timeout), condition)
+}
+
+// PollImmediateUntil tries a condition func until it returns true, an error or stopCh is closed.
+//
+// PollImmediateUntil runs the 'condition' before waiting for the interval.
+// 'condition' will always be invoked at least once.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediateUntil(interval time.Duration, condition ConditionFunc, stopCh <-chan struct{}) error {
+	return PollImmediateUntilWithContext(ContextForChannel(stopCh), interval, condition.WithContext())
+}
+
+// PollImmediateUntilWithContext tries a condition func until it returns true,
+// an error or the specified context is cancelled or expired.
+//
+// PollImmediateUntilWithContext runs the 'condition' before waiting for the interval.
+// 'condition' will always be invoked at least once.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediateUntilWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, true, poller(interval, 0), condition)
+}
+
+// PollImmediateInfinite tries a condition func until it returns true or an error
+//
+// PollImmediateInfinite runs the 'condition' before waiting for the interval.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediateInfinite(interval time.Duration, condition ConditionFunc) error {
+	return PollImmediateInfiniteWithContext(context.Background(), interval, condition.WithContext())
+}
+
+// PollImmediateInfiniteWithContext tries a condition func until it returns true
+// or an error or the specified context gets cancelled or expired.
+//
+// PollImmediateInfiniteWithContext runs the 'condition' before waiting for the interval.
+//
+// Some intervals may be missed if the condition takes too long or the time
+// window is too short.
+//
+// Deprecated: This method does not return errors from context, use PollUntilContextCancel.
+// Note that the new method will no longer return ErrWaitTimeout and instead return errors
+// defined by the context package. Will be removed in a future release.
+func PollImmediateInfiniteWithContext(ctx context.Context, interval time.Duration, condition ConditionWithContextFunc) error {
+	return poll(ctx, true, poller(interval, 0), condition)
+}
+
+// Internally used, each of the public 'Poll*' function defined in this
+// package should invoke this internal function with appropriate parameters.
+// ctx: the context specified by the caller, for infinite polling pass
+// a context that never gets cancelled or expired.
+// immediate: if true, the 'condition' will be invoked before waiting for the interval,
+// in this case 'condition' will always be invoked at least once.
+// wait: user specified WaitFunc function that controls at what interval the condition
+// function should be invoked periodically and whether it is bound by a timeout.
+// condition: user specified ConditionWithContextFunc function.
+//
+// Deprecated: will be removed in favor of loopConditionUntilContext.
+func poll(ctx context.Context, immediate bool, wait waitWithContextFunc, condition ConditionWithContextFunc) error {
+	if immediate {
+		done, err := runConditionWithCrashProtectionWithContext(ctx, condition)
+		if err != nil {
+			return err
+		}
+		if done {
+			return nil
+		}
+	}
+
+	select {
+	case <-ctx.Done():
+		// returning ctx.Err() will break backward compatibility, use new PollUntilContext*
+		// methods instead
+		return ErrWaitTimeout
+	default:
+		return waitForWithContext(ctx, wait, condition)
+	}
+}
+
+// poller returns a WaitFunc that will send to the channel every interval until
+// timeout has elapsed and then closes the channel.
+//
+// Over very short intervals you may receive no ticks before the channel is
+// closed. A timeout of 0 is interpreted as an infinity, and in such a case
+// it would be the caller's responsibility to close the done channel.
+// Failure to do so would result in a leaked goroutine.
+//
+// Output ticks are not buffered. If the channel is not ready to receive an
+// item, the tick is skipped.
+//
+// Deprecated: Will be removed in a future release.
+func poller(interval, timeout time.Duration) waitWithContextFunc {
+	return waitWithContextFunc(func(ctx context.Context) <-chan struct{} {
+		ch := make(chan struct{})
+
+		go func() {
+			defer close(ch)
+
+			tick := time.NewTicker(interval)
+			defer tick.Stop()
+
+			var after <-chan time.Time
+			if timeout != 0 {
+				// time.After is more convenient, but it
+				// potentially leaves timers around much longer
+				// than necessary if we exit early.
+				timer := time.NewTimer(timeout)
+				after = timer.C
+				defer timer.Stop()
+			}
+
+			for {
+				select {
+				case <-tick.C:
+					// If the consumer isn't ready for this signal drop it and
+					// check the other channels.
+					select {
+					case ch <- struct{}{}:
+					default:
+					}
+				case <-after:
+					return
+				case <-ctx.Done():
+					return
+				}
+			}
+		}()
+
+		return ch
+	})
+}
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/timer.go b/vendor/k8s.io/apimachinery/pkg/util/wait/timer.go
new file mode 100644
index 000000000..3efba3213
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/timer.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2023 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"time"
+
+	"k8s.io/utils/clock"
+)
+
+// Timer abstracts how wait functions interact with time runtime efficiently. Test
+// code may implement this interface directly but package consumers are encouraged
+// to use the Backoff type as the primary mechanism for acquiring a Timer. The
+// interface is a simplification of clock.Timer to prevent misuse. Timers are not
+// expected to be safe for calls from multiple goroutines.
+type Timer interface {
+	// C returns a channel that will receive a struct{} each time the timer fires.
+	// The channel should not be waited on after Stop() is invoked. It is allowed
+	// to cache the returned value of C() for the lifetime of the Timer.
+	C() <-chan time.Time
+	// Next is invoked by wait functions to signal timers that the next interval
+	// should begin. You may only use Next() if you have drained the channel C().
+	// You should not call Next() after Stop() is invoked.
+	Next()
+	// Stop releases the timer. It is safe to invoke if no other methods have been
+	// called.
+	Stop()
+}
+
+type noopTimer struct {
+	closedCh <-chan time.Time
+}
+
+// newNoopTimer creates a timer with a unique channel to avoid contention
+// for the channel's lock across multiple unrelated timers.
+func newNoopTimer() noopTimer {
+	ch := make(chan time.Time)
+	close(ch)
+	return noopTimer{closedCh: ch}
+}
+
+func (t noopTimer) C() <-chan time.Time {
+	return t.closedCh
+}
+func (noopTimer) Next() {}
+func (noopTimer) Stop() {}
+
+type variableTimer struct {
+	fn  DelayFunc
+	t   clock.Timer
+	new func(time.Duration) clock.Timer
+}
+
+func (t *variableTimer) C() <-chan time.Time {
+	if t.t == nil {
+		d := t.fn()
+		t.t = t.new(d)
+	}
+	return t.t.C()
+}
+func (t *variableTimer) Next() {
+	if t.t == nil {
+		return
+	}
+	d := t.fn()
+	t.t.Reset(d)
+}
+func (t *variableTimer) Stop() {
+	if t.t == nil {
+		return
+	}
+	t.t.Stop()
+	t.t = nil
+}
+
+type fixedTimer struct {
+	interval time.Duration
+	t        clock.Ticker
+	new      func(time.Duration) clock.Ticker
+}
+
+func (t *fixedTimer) C() <-chan time.Time {
+	if t.t == nil {
+		t.t = t.new(t.interval)
+	}
+	return t.t.C()
+}
+func (t *fixedTimer) Next() {
+	// no-op for fixed timers
+}
+func (t *fixedTimer) Stop() {
+	if t.t == nil {
+		return
+	}
+	t.t.Stop()
+	t.t = nil
+}
+
+var (
+	// RealTimer can be passed to methods that need a clock.Timer.
+	RealTimer = clock.RealClock{}.NewTimer
+)
+
+var (
+	// internalClock is used for test injection of clocks
+	internalClock = clock.RealClock{}
+)
diff --git a/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go b/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
new file mode 100644
index 000000000..6805e8cf9
--- /dev/null
+++ b/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go
@@ -0,0 +1,223 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package wait
+
+import (
+	"context"
+	"math/rand"
+	"sync"
+	"time"
+
+	"k8s.io/apimachinery/pkg/util/runtime"
+)
+
+// For any test of the style:
+//
+//	...
+//	<- time.After(timeout):
+//	   t.Errorf("Timed out")
+//
+// The value for timeout should effectively be "forever." Obviously we don't want our tests to truly lock up forever, but 30s
+// is long enough that it is effectively forever for the things that can slow down a run on a heavily contended machine
+// (GC, seeks, etc), but not so long as to make a developer ctrl-c a test run if they do happen to break that test.
+var ForeverTestTimeout = time.Second * 30
+
+// NeverStop may be passed to Until to make it never stop.
+var NeverStop <-chan struct{} = make(chan struct{})
+
+// Group allows to start a group of goroutines and wait for their completion.
+type Group struct {
+	wg sync.WaitGroup
+}
+
+func (g *Group) Wait() {
+	g.wg.Wait()
+}
+
+// StartWithChannel starts f in a new goroutine in the group.
+// stopCh is passed to f as an argument. f should stop when stopCh is available.
+func (g *Group) StartWithChannel(stopCh <-chan struct{}, f func(stopCh <-chan struct{})) {
+	g.Start(func() {
+		f(stopCh)
+	})
+}
+
+// StartWithContext starts f in a new goroutine in the group.
+// ctx is passed to f as an argument. f should stop when ctx.Done() is available.
+func (g *Group) StartWithContext(ctx context.Context, f func(context.Context)) {
+	g.Start(func() {
+		f(ctx)
+	})
+}
+
+// Start starts f in a new goroutine in the group.
+func (g *Group) Start(f func()) {
+	g.wg.Add(1)
+	go func() {
+		defer g.wg.Done()
+		f()
+	}()
+}
+
+// Forever calls f every period for ever.
+//
+// Forever is syntactic sugar on top of Until.
+func Forever(f func(), period time.Duration) {
+	Until(f, period, NeverStop)
+}
+
+// Jitter returns a time.Duration between duration and duration + maxFactor *
+// duration.
+//
+// This allows clients to avoid converging on periodic behavior. If maxFactor
+// is 0.0, a suggested default value will be chosen.
+func Jitter(duration time.Duration, maxFactor float64) time.Duration {
+	if maxFactor <= 0.0 {
+		maxFactor = 1.0
+	}
+	wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
+	return wait
+}
+
+// ConditionFunc returns true if the condition is satisfied, or an error
+// if the loop should be aborted.
+type ConditionFunc func() (done bool, err error)
+
+// ConditionWithContextFunc returns true if the condition is satisfied, or an error
+// if the loop should be aborted.
+//
+// The caller passes along a context that can be used by the condition function.
+type ConditionWithContextFunc func(context.Context) (done bool, err error)
+
+// WithContext converts a ConditionFunc into a ConditionWithContextFunc
+func (cf ConditionFunc) WithContext() ConditionWithContextFunc {
+	return func(context.Context) (done bool, err error) {
+		return cf()
+	}
+}
+
+// ContextForChannel provides a context that will be treated as cancelled
+// when the provided parentCh is closed. The implementation returns
+// context.Canceled for Err() if and only if the parentCh is closed.
+func ContextForChannel(parentCh <-chan struct{}) context.Context {
+	return channelContext{stopCh: parentCh}
+}
+
+var _ context.Context = channelContext{}
+
+// channelContext will behave as if the context were cancelled when stopCh is
+// closed.
+type channelContext struct {
+	stopCh <-chan struct{}
+}
+
+func (c channelContext) Done() <-chan struct{} { return c.stopCh }
+func (c channelContext) Err() error {
+	select {
+	case <-c.stopCh:
+		return context.Canceled
+	default:
+		return nil
+	}
+}
+func (c channelContext) Deadline() (time.Time, bool) { return time.Time{}, false }
+func (c channelContext) Value(key any) any           { return nil }
+
+// runConditionWithCrashProtection runs a ConditionFunc with crash protection.
+//
+// Deprecated: Will be removed when the legacy polling methods are removed.
+func runConditionWithCrashProtection(condition ConditionFunc) (bool, error) {
+	defer runtime.HandleCrash()
+	return condition()
+}
+
+// runConditionWithCrashProtectionWithContext runs a ConditionWithContextFunc
+// with crash protection.
+//
+// Deprecated: Will be removed when the legacy polling methods are removed.
+func runConditionWithCrashProtectionWithContext(ctx context.Context, condition ConditionWithContextFunc) (bool, error) {
+	defer runtime.HandleCrash()
+	return condition(ctx)
+}
+
+// waitFunc creates a channel that receives an item every time a test
+// should be executed and is closed when the last test should be invoked.
+//
+// Deprecated: Will be removed in a future release in favor of
+// loopConditionUntilContext.
+type waitFunc func(done <-chan struct{}) <-chan struct{}
+
+// WithContext converts the WaitFunc to an equivalent WaitWithContextFunc
+func (w waitFunc) WithContext() waitWithContextFunc {
+	return func(ctx context.Context) <-chan struct{} {
+		return w(ctx.Done())
+	}
+}
+
+// waitWithContextFunc creates a channel that receives an item every time a test
+// should be executed and is closed when the last test should be invoked.
+//
+// When the specified context gets cancelled or expires the function
+// stops sending item and returns immediately.
+//
+// Deprecated: Will be removed in a future release in favor of
+// loopConditionUntilContext.
+type waitWithContextFunc func(ctx context.Context) <-chan struct{}
+
+// waitForWithContext continually checks 'fn' as driven by 'wait'.
+//
+// waitForWithContext gets a channel from 'wait()”, and then invokes 'fn'
+// once for every value placed on the channel and once more when the
+// channel is closed. If the channel is closed and 'fn'
+// returns false without error, waitForWithContext returns ErrWaitTimeout.
+//
+// If 'fn' returns an error the loop ends and that error is returned. If
+// 'fn' returns true the loop ends and nil is returned.
+//
+// context.Canceled will be returned if the ctx.Done() channel is closed
+// without fn ever returning true.
+//
+// When the ctx.Done() channel is closed, because the golang `select` statement is
+// "uniform pseudo-random", the `fn` might still run one or multiple times,
+// though eventually `waitForWithContext` will return.
+//
+// Deprecated: Will be removed in a future release in favor of
+// loopConditionUntilContext.
+func waitForWithContext(ctx context.Context, wait waitWithContextFunc, fn ConditionWithContextFunc) error {
+	waitCtx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	c := wait(waitCtx)
+	for {
+		select {
+		case _, open := <-c:
+			ok, err := runConditionWithCrashProtectionWithContext(ctx, fn)
+			if err != nil {
+				return err
+			}
+			if ok {
+				return nil
+			}
+			if !open {
+				return ErrWaitTimeout
+			}
+		case <-ctx.Done():
+			// returning ctx.Err() will break backward compatibility, use new PollUntilContext*
+			// methods instead
+			return ErrWaitTimeout
+		}
+	}
+}
diff --git a/vendor/k8s.io/utils/clock/README.md b/vendor/k8s.io/utils/clock/README.md
new file mode 100644
index 000000000..ad2a8868a
--- /dev/null
+++ b/vendor/k8s.io/utils/clock/README.md
@@ -0,0 +1,4 @@
+# Clock
+
+This package provides an interface for time-based operations.  It allows
+mocking time for testing.
diff --git a/vendor/k8s.io/utils/clock/clock.go b/vendor/k8s.io/utils/clock/clock.go
new file mode 100644
index 000000000..b8b6af5c8
--- /dev/null
+++ b/vendor/k8s.io/utils/clock/clock.go
@@ -0,0 +1,178 @@
+/*
+Copyright 2014 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package clock
+
+import "time"
+
+// PassiveClock allows for injecting fake or real clocks into code
+// that needs to read the current time but does not support scheduling
+// activity in the future.
+type PassiveClock interface {
+	Now() time.Time
+	Since(time.Time) time.Duration
+}
+
+// Clock allows for injecting fake or real clocks into code that
+// needs to do arbitrary things based on time.
+type Clock interface {
+	PassiveClock
+	// After returns the channel of a new Timer.
+	// This method does not allow to free/GC the backing timer before it fires. Use
+	// NewTimer instead.
+	After(d time.Duration) <-chan time.Time
+	// NewTimer returns a new Timer.
+	NewTimer(d time.Duration) Timer
+	// Sleep sleeps for the provided duration d.
+	// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
+	Sleep(d time.Duration)
+	// Tick returns the channel of a new Ticker.
+	// This method does not allow to free/GC the backing ticker. Use
+	// NewTicker from WithTicker instead.
+	Tick(d time.Duration) <-chan time.Time
+}
+
+// WithTicker allows for injecting fake or real clocks into code that
+// needs to do arbitrary things based on time.
+type WithTicker interface {
+	Clock
+	// NewTicker returns a new Ticker.
+	NewTicker(time.Duration) Ticker
+}
+
+// WithDelayedExecution allows for injecting fake or real clocks into
+// code that needs to make use of AfterFunc functionality.
+type WithDelayedExecution interface {
+	Clock
+	// AfterFunc executes f in its own goroutine after waiting
+	// for d duration and returns a Timer whose channel can be
+	// closed by calling Stop() on the Timer.
+	AfterFunc(d time.Duration, f func()) Timer
+}
+
+// WithTickerAndDelayedExecution allows for injecting fake or real clocks
+// into code that needs Ticker and AfterFunc functionality
+type WithTickerAndDelayedExecution interface {
+	WithTicker
+	// AfterFunc executes f in its own goroutine after waiting
+	// for d duration and returns a Timer whose channel can be
+	// closed by calling Stop() on the Timer.
+	AfterFunc(d time.Duration, f func()) Timer
+}
+
+// Ticker defines the Ticker interface.
+type Ticker interface {
+	C() <-chan time.Time
+	Stop()
+}
+
+var _ = WithTicker(RealClock{})
+
+// RealClock really calls time.Now()
+type RealClock struct{}
+
+// Now returns the current time.
+func (RealClock) Now() time.Time {
+	return time.Now()
+}
+
+// Since returns time since the specified timestamp.
+func (RealClock) Since(ts time.Time) time.Duration {
+	return time.Since(ts)
+}
+
+// After is the same as time.After(d).
+// This method does not allow to free/GC the backing timer before it fires. Use
+// NewTimer instead.
+func (RealClock) After(d time.Duration) <-chan time.Time {
+	return time.After(d)
+}
+
+// NewTimer is the same as time.NewTimer(d)
+func (RealClock) NewTimer(d time.Duration) Timer {
+	return &realTimer{
+		timer: time.NewTimer(d),
+	}
+}
+
+// AfterFunc is the same as time.AfterFunc(d, f).
+func (RealClock) AfterFunc(d time.Duration, f func()) Timer {
+	return &realTimer{
+		timer: time.AfterFunc(d, f),
+	}
+}
+
+// Tick is the same as time.Tick(d)
+// This method does not allow to free/GC the backing ticker. Use
+// NewTicker instead.
+func (RealClock) Tick(d time.Duration) <-chan time.Time {
+	return time.Tick(d)
+}
+
+// NewTicker returns a new Ticker.
+func (RealClock) NewTicker(d time.Duration) Ticker {
+	return &realTicker{
+		ticker: time.NewTicker(d),
+	}
+}
+
+// Sleep is the same as time.Sleep(d)
+// Consider making the sleep interruptible by using 'select' on a context channel and a timer channel.
+func (RealClock) Sleep(d time.Duration) {
+	time.Sleep(d)
+}
+
+// Timer allows for injecting fake or real timers into code that
+// needs to do arbitrary things based on time.
+type Timer interface {
+	C() <-chan time.Time
+	Stop() bool
+	Reset(d time.Duration) bool
+}
+
+var _ = Timer(&realTimer{})
+
+// realTimer is backed by an actual time.Timer.
+type realTimer struct {
+	timer *time.Timer
+}
+
+// C returns the underlying timer's channel.
+func (r *realTimer) C() <-chan time.Time {
+	return r.timer.C
+}
+
+// Stop calls Stop() on the underlying timer.
+func (r *realTimer) Stop() bool {
+	return r.timer.Stop()
+}
+
+// Reset calls Reset() on the underlying timer.
+func (r *realTimer) Reset(d time.Duration) bool {
+	return r.timer.Reset(d)
+}
+
+type realTicker struct {
+	ticker *time.Ticker
+}
+
+func (r *realTicker) C() <-chan time.Time {
+	return r.ticker.C
+}
+
+func (r *realTicker) Stop() {
+	r.ticker.Stop()
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 7f5aedc56..d97b84fbb 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -7,7 +7,7 @@ github.com/asaskevich/govalidator
 # github.com/blang/semver/v4 v4.0.0
 ## explicit; go 1.14
 github.com/blang/semver/v4
-# github.com/cilium/cilium v1.16.3
+# github.com/cilium/cilium v1.16.4
 ## explicit; go 1.22.0
 github.com/cilium/cilium/api/v1/flow
 github.com/cilium/cilium/api/v1/models
@@ -37,6 +37,7 @@ github.com/cilium/cilium/pkg/cidr
 github.com/cilium/cilium/pkg/clustermesh/types
 github.com/cilium/cilium/pkg/command
 github.com/cilium/cilium/pkg/container
+github.com/cilium/cilium/pkg/datapath/linux/safenetlink
 github.com/cilium/cilium/pkg/defaults
 github.com/cilium/cilium/pkg/hubble/api/v1
 github.com/cilium/cilium/pkg/hubble/filters
@@ -55,6 +56,7 @@ github.com/cilium/cilium/pkg/mac
 github.com/cilium/cilium/pkg/monitor/api
 github.com/cilium/cilium/pkg/monitor/notifications
 github.com/cilium/cilium/pkg/option
+github.com/cilium/cilium/pkg/resiliency
 github.com/cilium/cilium/pkg/slices
 github.com/cilium/cilium/pkg/time
 github.com/cilium/cilium/pkg/version
@@ -240,7 +242,7 @@ github.com/stoewer/go-strcase
 # github.com/subosito/gotenv v1.6.0
 ## explicit; go 1.18
 github.com/subosito/gotenv
-# github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21
+# github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81
 ## explicit; go 1.12
 github.com/vishvananda/netlink
 github.com/vishvananda/netlink/nl
@@ -415,9 +417,11 @@ gopkg.in/yaml.v3
 k8s.io/apimachinery/pkg/labels
 k8s.io/apimachinery/pkg/selection
 k8s.io/apimachinery/pkg/util/errors
+k8s.io/apimachinery/pkg/util/runtime
 k8s.io/apimachinery/pkg/util/sets
 k8s.io/apimachinery/pkg/util/validation
 k8s.io/apimachinery/pkg/util/validation/field
+k8s.io/apimachinery/pkg/util/wait
 # k8s.io/client-go v0.30.2
 ## explicit; go 1.22.0
 k8s.io/client-go/third_party/forked/golang/template
@@ -433,6 +437,7 @@ k8s.io/klog/v2/internal/severity
 k8s.io/klog/v2/internal/sloghandler
 # k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
 ## explicit; go 1.18
+k8s.io/utils/clock
 k8s.io/utils/internal/third_party/forked/golang/net
 k8s.io/utils/net
 k8s.io/utils/strings/slices