treewide: unfork netlink
We were using our own fork because of the psample change whose
upstreaming effort has stalled since Mateusz left the company. That
netlink base is now getting too old and we have more patches on top
which all have since become irrelevant or got upstreamed.
The new version of netlink also no longer has the quirk that default
routes do not have a destination set, fix that in the DHCP tests and use
go-cmp as the raw binary values are annoying to get right and do not
matter. Semantic equivalence is what we're after.
Thus stop using our fork and instead pick up the rebased psample patches
from the new upstreaming effort. This removes one more replace directive
which is nice.
Change-Id: I21a59c2c9a99dd3baf672a8aa2ad9332e573cba1
Reviewed-on: https://review.monogon.dev/c/monogon/+/3750
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
Tested-by: Jenkins CI
diff --git a/build/bazel/go.MODULE.bazel b/build/bazel/go.MODULE.bazel
index de8ad0d..e982ebd 100644
--- a/build/bazel/go.MODULE.bazel
+++ b/build/bazel/go.MODULE.bazel
@@ -337,8 +337,7 @@
},
"github.com/vishvananda/netlink": {
"patches": [
- "//third_party/go/patches:netlink-permhwaddr.patch",
- "//third_party/go/patches:netlink-use-rtm_setlink.patch",
+ "//third_party/go/patches:netlink-psample.patch",
],
},
"gvisor.dev/gvisor": {
diff --git a/go.mod b/go.mod
index ac869f3..7ba4e34 100644
--- a/go.mod
+++ b/go.mod
@@ -42,9 +42,6 @@
// bazeldnf currently comes with a go-rpmutils patch
replace github.com/sassoftware/go-rpmutils v0.1.1 => github.com/rmohr/go-rpmutils v0.1.2-0.20201215123907-5acf7436c00d
-// Our psample patches
-replace github.com/vishvananda/netlink => github.com/monogon-dev/netlink v0.0.0-20230125113930-88977c3ff4b3
-
// Pin buildtools version to an up to date version, as the bazeldnf version
// is outdated and gazelle needs it.
replace github.com/bazelbuild/buildtools => github.com/bazelbuild/buildtools v0.0.0-20231103205921-433ea8554e82
diff --git a/go.sum b/go.sum
index 3ced292..5b66db0 100644
--- a/go.sum
+++ b/go.sum
@@ -2969,8 +2969,6 @@
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
-github.com/monogon-dev/netlink v0.0.0-20230125113930-88977c3ff4b3 h1:y05BDqZ6q3if6pYBHJcnQRUd92ihzBEJde/S4fpKEAM=
-github.com/monogon-dev/netlink v0.0.0-20230125113930-88977c3ff4b3/go.mod h1:cAAsePK2e15YDAMJNyOpGYEWNe4sIghTY7gpz4cX/Ik=
github.com/monogon-dev/packngo v0.0.0-20240122175436-ecbd9eb00ddb h1:sxSnvzB4iDBNhUBqXME/ETqjF4vX0mURE85T/I/Mr0o=
github.com/monogon-dev/packngo v0.0.0-20240122175436-ecbd9eb00ddb/go.mod h1:Io6VJqzkiqmIEQbpOjeIw9v8q9PfcTEq8TEY/tMQsfw=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
@@ -3478,6 +3476,13 @@
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netlink v1.3.1-0.20240905180732-b1ce50cfa9be h1:xdCMvyhnKzaepIUgVpUmTJo/+H1AQ7HuFYn1hv7/Neo=
+github.com/vishvananda/netlink v1.3.1-0.20240905180732-b1ce50cfa9be/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
@@ -4108,6 +4113,7 @@
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -4254,7 +4260,6 @@
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/metropolis/node/core/network/dhcp4c/callback/BUILD.bazel b/metropolis/node/core/network/dhcp4c/callback/BUILD.bazel
index 89ad035..2091f6b 100644
--- a/metropolis/node/core/network/dhcp4c/callback/BUILD.bazel
+++ b/metropolis/node/core/network/dhcp4c/callback/BUILD.bazel
@@ -25,8 +25,8 @@
pure = "on",
deps = [
"//metropolis/node/core/network/dhcp4c",
+ "@com_github_google_go_cmp//cmp",
"@com_github_insomniacslk_dhcp//dhcpv4",
- "@com_github_stretchr_testify//require",
"@com_github_vishvananda_netlink//:netlink",
"@org_golang_x_sys//unix",
],
diff --git a/metropolis/node/core/network/dhcp4c/callback/callback_test.go b/metropolis/node/core/network/dhcp4c/callback/callback_test.go
index e83596e..3045f47 100644
--- a/metropolis/node/core/network/dhcp4c/callback/callback_test.go
+++ b/metropolis/node/core/network/dhcp4c/callback/callback_test.go
@@ -24,8 +24,8 @@
"testing"
"time"
+ "github.com/google/go-cmp/cmp"
"github.com/insomniacslk/dhcp/dhcpv4"
- "github.com/stretchr/testify/require"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
@@ -133,7 +133,9 @@
if err != nil {
t.Fatalf("test cannot read back addrs from interface: %v", err)
}
- require.Equal(t, test.expectedAddrs, addrs, "Wrong IPs on interface")
+ if diff := cmp.Diff(test.expectedAddrs, addrs); diff != "" {
+ t.Errorf("Wrong IPs on interface (-want +got):\n%s", diff)
+ }
})
}
}
@@ -184,10 +186,8 @@
initialRoutes: []netlink.Route{},
newLease: leaseAddRouter(trivialLeaseFromNet(testNet1), testNet1Router),
expectedRoutes: []netlink.Route{{
- Protocol: unix.RTPROT_DHCP,
- // Linux weirdly returns no RTA_DST for default routes, but one
- // for everything else.
- Dst: nil,
+ Protocol: unix.RTPROT_DHCP,
+ Dst: mustParseCIDR("0.0.0.0/0"),
Family: unix.AF_INET,
Gw: testNet1Router,
Src: testNet1.IP,
@@ -260,7 +260,7 @@
newLease: leaseAddRouter(trivialLeaseFromNet(testNet2), testNet2Router),
expectedRoutes: []netlink.Route{{
Protocol: unix.RTPROT_DHCP,
- Dst: nil,
+ Dst: mustParseCIDR("0.0.0.0/0"),
Family: unix.AF_INET,
Gw: testNet2Router,
Src: testNet2.IP,
@@ -282,7 +282,7 @@
),
expectedRoutes: []netlink.Route{{
Protocol: unix.RTPROT_DHCP,
- Dst: nil,
+ Dst: mustParseCIDR("0.0.0.0/0"),
Family: unix.AF_INET,
Gw: net.IPv4(192, 168, 42, 1).To4(), // Equal() doesn't know about canonicalization
Src: testNet1.IP,
@@ -360,7 +360,9 @@
notKernelRoutes = append(notKernelRoutes, route)
}
}
- require.Equal(t, test.expectedRoutes, notKernelRoutes, "Wrong Routes")
+ if diff := cmp.Diff(test.expectedRoutes, notKernelRoutes); diff != "" {
+ t.Errorf("Expected route mismatch (-want +got):\n%s", diff)
+ }
})
}
}
diff --git a/metropolis/node/core/network/static.go b/metropolis/node/core/network/static.go
index fdd00a8..cdf72b0 100644
--- a/metropolis/node/core/network/static.go
+++ b/metropolis/node/core/network/static.go
@@ -289,9 +289,9 @@
if len(parsedHWAddr) != 0 {
// If device has a permanent hardware address, it must match,
// otherwise the standard hardware address must match
- if len(d.dev.PermHardwareAddr) > 0 {
- if !bytes.Equal(d.dev.PermHardwareAddr, parsedHWAddr) {
- l.V(1).Infof("mismatched perm hw addr %q: %s %s\n", d.dev.Name, d.dev.PermHardwareAddr, parsedHWAddr)
+ if len(d.dev.PermHWAddr) > 0 {
+ if !bytes.Equal(d.dev.PermHWAddr, parsedHWAddr) {
+ l.V(1).Infof("mismatched perm hw addr %q: %s %s\n", d.dev.Name, d.dev.PermHWAddr, parsedHWAddr)
continue
}
} else if !bytes.Equal(d.dev.HardwareAddr, parsedHWAddr) {
diff --git a/osbase/net/dump/netdump.go b/osbase/net/dump/netdump.go
index a7d8023..c3bf9f7 100644
--- a/osbase/net/dump/netdump.go
+++ b/osbase/net/dump/netdump.go
@@ -61,7 +61,7 @@
var iface netapi.Interface
switch l := link.(type) {
case *netlink.Device:
- mac := link.Attrs().PermHardwareAddr
+ mac := link.Attrs().PermHWAddr
if len(mac) == 0 {
// Try legacy method for old kernels
mac, err = getPermanentHWAddrLegacy(l.Name)
diff --git a/third_party/go/patches/netlink-permhwaddr.patch b/third_party/go/patches/netlink-permhwaddr.patch
deleted file mode 100644
index cedc9b0..0000000
--- a/third_party/go/patches/netlink-permhwaddr.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-diff --git a/link.go b/link.go
-index 8e6b09e..fcbecfc 100644
---- a/link.go
-+++ b/link.go
-@@ -50,7 +50,9 @@ type LinkAttrs struct {
- GROMaxSize uint32
- Vfs []VfInfo // virtual functions available on link
- Group uint32
-- Slave LinkSlave
-+
-+ PermHardwareAddr net.HardwareAddr
-+ Slave LinkSlave
- }
-
- // LinkSlave represents a slave device.
-diff --git a/link_linux.go b/link_linux.go
-index cc80fb6..8681c75 100644
---- a/link_linux.go
-+++ b/link_linux.go
-@@ -2018,6 +2018,16 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
- base.NumRxQueues = int(native.Uint32(attr.Value[0:4]))
- case unix.IFLA_GROUP:
- base.Group = native.Uint32(attr.Value[0:4])
-+ case unix.IFLA_PERM_ADDRESS:
-+ var nonzero bool
-+ for _, b := range attr.Value {
-+ if b != 0 {
-+ nonzero = true
-+ }
-+ }
-+ if nonzero {
-+ base.PermHardwareAddr = attr.Value[:]
-+ }
- }
- }
-
diff --git a/third_party/go/patches/netlink-psample.patch b/third_party/go/patches/netlink-psample.patch
new file mode 100644
index 0000000..210e353
--- /dev/null
+++ b/third_party/go/patches/netlink-psample.patch
@@ -0,0 +1,263 @@
+From 5aceb9e681cd6c82a2eccc25e1452d72d991c613 Mon Sep 17 00:00:00 2001
+From: Mateusz Zalega <mateusz@monogon.tech>
+Date: Wed, 25 Jan 2023 11:20:06 +0000
+Subject: [PATCH] Support "sample" filter action
+
+This change adds support for packet sampling using "psample" kernel
+module.
+---
+ filter.go | 23 +++++++++
+ filter_linux.go | 25 +++++++++
+ filter_test.go | 132 ++++++++++++++++++++++++++++++++++++++++++++++++
+ nl/tc_linux.go | 11 ++++
+ 4 files changed, 191 insertions(+)
+
+diff --git a/filter.go b/filter.go
+index 84e1ca7..e4f3167 100644
+--- a/filter.go
++++ b/filter.go
+@@ -369,6 +369,29 @@ func NewPoliceAction() *PoliceAction {
+ }
+ }
+
++type SampleAction struct {
++ ActionAttrs
++ Group uint32
++ Rate uint32
++ TruncSize uint32
++}
++
++func (action *SampleAction) Type() string {
++ return "sample"
++}
++
++func (action *SampleAction) Attrs() *ActionAttrs {
++ return &action.ActionAttrs
++}
++
++func NewSampleAction() *SampleAction {
++ return &SampleAction{
++ ActionAttrs: ActionAttrs{
++ Action: TC_ACT_PIPE,
++ },
++ }
++}
++
+ // MatchAll filters match all packets
+ type MatchAll struct {
+ FilterAttrs
+diff --git a/filter_linux.go b/filter_linux.go
+index 1930661..d61e357 100644
+--- a/filter_linux.go
++++ b/filter_linux.go
+@@ -705,6 +705,17 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
++ case *SampleAction:
++ table := attr.AddRtAttr(tabIndex, nil)
++ tabIndex++
++ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("sample"))
++ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
++ gen := nl.TcGen{}
++ toTcGen(action.Attrs(), &gen)
++ aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PARMS, gen.Serialize())
++ aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_RATE, nl.Uint32Attr(action.Rate))
++ aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP, nl.Uint32Attr(action.Group))
++ aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_TRUNC_SIZE, nl.Uint32Attr(action.TruncSize))
+ case *GenericAction:
+ table := attr.AddRtAttr(tabIndex, nil)
+ tabIndex++
+@@ -790,6 +801,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
+ action = &ConnmarkAction{}
+ case "csum":
+ action = &CsumAction{}
++ case "sample":
++ action = &SampleAction{}
+ case "gact":
+ action = &GenericAction{}
+ case "tunnel_key":
+@@ -902,6 +915,18 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
+ tcTs := nl.DeserializeTcf(adatum.Value)
+ actionTimestamp = toTimeStamp(tcTs)
+ }
++ case "sample":
++ switch adatum.Attr.Type {
++ case nl.TCA_ACT_SAMPLE_PARMS:
++ gen := *nl.DeserializeTcGen(adatum.Value)
++ toAttrs(&gen, action.Attrs())
++ case nl.TCA_ACT_SAMPLE_RATE:
++ action.(*SampleAction).Rate = native.Uint32(adatum.Value[0:4])
++ case nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP:
++ action.(*SampleAction).Group = native.Uint32(adatum.Value[0:4])
++ case nl.TCA_ACT_SAMPLE_TRUNC_SIZE:
++ action.(*SampleAction).TruncSize = native.Uint32(adatum.Value[0:4])
++ }
+ case "gact":
+ switch adatum.Attr.Type {
+ case nl.TCA_GACT_PARMS:
+diff --git a/filter_test.go b/filter_test.go
+index 3a49f1b..774e7d6 100644
+--- a/filter_test.go
++++ b/filter_test.go
+@@ -2471,3 +2471,135 @@ func TestFilterChainAddDel(t *testing.T) {
+ t.Fatal("Failed to remove qdisc")
+ }
+ }
++
++func TestFilterSampleAddDel(t *testing.T) {
++ minKernelRequired(t, 4, 11)
++ if _, err := GenlFamilyGet("psample"); err != nil {
++ t.Skip("psample genetlink family unavailable - is CONFIG_PSAMPLE enabled?")
++ }
++
++ tearDown := setUpNetlinkTest(t)
++ defer tearDown()
++ if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
++ t.Fatal(err)
++ }
++ link, err := LinkByName("foo")
++ if err != nil {
++ t.Fatal(err)
++ }
++ if err := LinkSetUp(link); err != nil {
++ t.Fatal(err)
++ }
++
++ qdisc := &Ingress{
++ QdiscAttrs: QdiscAttrs{
++ LinkIndex: link.Attrs().Index,
++ Handle: MakeHandle(0xffff, 0),
++ Parent: HANDLE_INGRESS,
++ },
++ }
++ if err := QdiscAdd(qdisc); err != nil {
++ t.Fatal(err)
++ }
++ qdiscs, err := SafeQdiscList(link)
++ if err != nil {
++ t.Fatal(err)
++ }
++
++ found := false
++ for _, v := range qdiscs {
++ if _, ok := v.(*Ingress); ok {
++ found = true
++ break
++ }
++ }
++ if !found {
++ t.Fatal("Qdisc is the wrong type")
++ }
++
++ sample := NewSampleAction()
++ sample.Group = 7
++ sample.Rate = 12
++ sample.TruncSize = 200
++
++ classId := MakeHandle(1, 1)
++ filter := &MatchAll{
++ FilterAttrs: FilterAttrs{
++ LinkIndex: link.Attrs().Index,
++ Parent: MakeHandle(0xffff, 0),
++ Priority: 1,
++ Protocol: unix.ETH_P_ALL,
++ },
++ ClassId: classId,
++ Actions: []Action{
++ sample,
++ },
++ }
++
++ if err := FilterAdd(filter); err != nil {
++ t.Fatal(err)
++ }
++
++ filters, err := FilterList(link, MakeHandle(0xffff, 0))
++ if err != nil {
++ t.Fatal(err)
++ }
++ if len(filters) != 1 {
++ t.Fatal("Failed to add filter")
++ }
++ mf, ok := filters[0].(*MatchAll)
++ if !ok {
++ t.Fatal("Filter is the wrong type")
++ }
++
++ if len(mf.Actions) < 1 {
++ t.Fatalf("Too few Actions in filter")
++ }
++ if mf.ClassId != classId {
++ t.Fatalf("ClassId of the filter is the wrong value")
++ }
++
++ lsample, ok := mf.Actions[0].(*SampleAction)
++ if !ok {
++ t.Fatal("Unable to find sample action")
++ }
++ if lsample.Group != sample.Group {
++ t.Fatalf("Inconsistent sample action group")
++ }
++ if lsample.Rate != sample.Rate {
++ t.Fatalf("Inconsistent sample action rate")
++ }
++ if lsample.TruncSize != sample.TruncSize {
++ t.Fatalf("Inconsistent sample truncation size")
++ }
++
++ if err := FilterDel(filter); err != nil {
++ t.Fatal(err)
++ }
++ filters, err = FilterList(link, MakeHandle(0xffff, 0))
++ if err != nil {
++ t.Fatal(err)
++ }
++ if len(filters) != 0 {
++ t.Fatal("Failed to remove filter")
++ }
++
++ if err := QdiscDel(qdisc); err != nil {
++ t.Fatal(err)
++ }
++ qdiscs, err = SafeQdiscList(link)
++ if err != nil {
++ t.Fatal(err)
++ }
++
++ found = false
++ for _, v := range qdiscs {
++ if _, ok := v.(*Ingress); ok {
++ found = true
++ break
++ }
++ }
++ if found {
++ t.Fatal("Failed to remove qdisc")
++ }
++}
+diff --git a/nl/tc_linux.go b/nl/tc_linux.go
+index 0720729..db3ca1c 100644
+--- a/nl/tc_linux.go
++++ b/nl/tc_linux.go
+@@ -77,6 +77,17 @@ const (
+ TCA_ACT_MAX
+ )
+
++const (
++ TCA_ACT_SAMPLE_UNSPEC = iota
++ TCA_ACT_SAMPLE_TM
++ TCA_ACT_SAMPLE_PARMS
++ TCA_ACT_SAMPLE_RATE
++ TCA_ACT_SAMPLE_TRUNC_SIZE
++ TCA_ACT_SAMPLE_PSAMPLE_GROUP
++ TCA_ACT_SAMPLE_PAD
++ TCA_ACT_SAMPLE_MAX
++)
++
+ const (
+ TCA_PRIO_UNSPEC = iota
+ TCA_PRIO_MQ
+--
+2.47.0
+
diff --git a/third_party/go/patches/netlink-use-rtm_setlink.patch b/third_party/go/patches/netlink-use-rtm_setlink.patch
deleted file mode 100644
index 7d05d0e..0000000
--- a/third_party/go/patches/netlink-use-rtm_setlink.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From f367f115a327ca07a294022bc296b4a2fd4e8f8c Mon Sep 17 00:00:00 2001
-From: Lorenz Brun <lorenz@monogon.tech>
-Date: Thu, 6 Apr 2023 23:06:03 +0200
-Subject: [PATCH] Use RTM_SETLINK where appropriate
-
----
- link_linux.go | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/link_linux.go b/link_linux.go
-index cc80fb6..db89880 100644
---- a/link_linux.go
-+++ b/link_linux.go
-@@ -332,7 +332,7 @@ func BridgeSetMcastSnoop(link Link, on bool) error {
- func (h *Handle) BridgeSetMcastSnoop(link Link, on bool) error {
- bridge := link.(*Bridge)
- bridge.MulticastSnooping = &on
-- return h.linkModify(bridge, unix.NLM_F_ACK)
-+ return h.linkModify(bridge, unix.RTM_SETLINK, unix.NLM_F_ACK)
- }
-
- func BridgeSetVlanFiltering(link Link, on bool) error {
-@@ -342,7 +342,7 @@ func BridgeSetVlanFiltering(link Link, on bool) error {
- func (h *Handle) BridgeSetVlanFiltering(link Link, on bool) error {
- bridge := link.(*Bridge)
- bridge.VlanFiltering = &on
-- return h.linkModify(bridge, unix.NLM_F_ACK)
-+ return h.linkModify(bridge, unix.RTM_SETLINK, unix.NLM_F_ACK)
- }
-
- func SetPromiscOn(link Link) error {
-@@ -1197,7 +1197,7 @@ func LinkAdd(link Link) error {
- // are taken from the parameters in the link object.
- // Equivalent to: `ip link add $link`
- func (h *Handle) LinkAdd(link Link) error {
-- return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
-+ return h.linkModify(link, unix.RTM_NEWLINK, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
- }
-
- func LinkModify(link Link) error {
-@@ -1205,10 +1205,10 @@ func LinkModify(link Link) error {
- }
-
- func (h *Handle) LinkModify(link Link) error {
-- return h.linkModify(link, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
-+ return h.linkModify(link, unix.RTM_SETLINK, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
- }
-
--func (h *Handle) linkModify(link Link, flags int) error {
-+func (h *Handle) linkModify(link Link, proto, flags int) error {
- // TODO: support extra data for macvlan
- base := link.Attrs()
-
-@@ -1373,7 +1373,7 @@ func (h *Handle) linkModify(link Link, flags int) error {
- return nil
- }
-
-- req := h.newNetlinkRequest(unix.RTM_NEWLINK, flags)
-+ req := h.newNetlinkRequest(proto, flags)
-
- msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
- // TODO: make it shorter
---
-2.39.2
-