link: netkit: Add support for Headroom and Tailroom attributes.

IFLA_NETKIT_HEADROOM and IFLA_NETKIT_TAILROOM attributes were added to
upstream kernel 6.14, allowing Netkit devices to be configured with
appropriate headroom/tailroom space to accommodate additional headers,
packet length changes and so forth.

Signed-off-by: Alasdair McWilliam <alasdair.mcwilliam@isovalent.com>
This commit is contained in:
Alasdair McWilliam
2025-08-21 11:00:57 +01:00
committed by Alessandro Boch
parent 349c84c717
commit cf66e1d224
4 changed files with 112 additions and 5 deletions

View File

@@ -410,6 +410,8 @@ type Netkit struct {
PeerPolicy NetkitPolicy
Scrub NetkitScrub
PeerScrub NetkitScrub
Headroom uint16
Tailroom uint16
supportsScrub bool
isPrimary bool
peerLinkAttrs LinkAttrs

View File

@@ -2802,6 +2802,15 @@ func addNetkitAttrs(nk *Netkit, linkInfo *nl.RtAttr, flag int) error {
data.AddRtAttr(nl.IFLA_NETKIT_SCRUB, nl.Uint32Attr(uint32(nk.Scrub)))
data.AddRtAttr(nl.IFLA_NETKIT_PEER_SCRUB, nl.Uint32Attr(uint32(nk.PeerScrub)))
// Any headroom or tailroom set on the primary device attributes will result in
// the kernel carrying them over into the peer device attributes for us.
if nk.Headroom > 0 {
data.AddRtAttr(nl.IFLA_NETKIT_HEADROOM, nl.Uint16Attr(nk.Headroom))
}
if nk.Tailroom > 0 {
data.AddRtAttr(nl.IFLA_NETKIT_TAILROOM, nl.Uint16Attr(nk.Tailroom))
}
if (flag & unix.NLM_F_EXCL) == 0 {
// Modifying peer link attributes will not take effect
return nil
@@ -2870,6 +2879,10 @@ func parseNetkitData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_NETKIT_PEER_SCRUB:
netkit.supportsScrub = true
netkit.PeerScrub = NetkitScrub(native.Uint32(datum.Value[0:4]))
case nl.IFLA_NETKIT_HEADROOM:
netkit.Headroom = native.Uint16(datum.Value[0:2])
case nl.IFLA_NETKIT_TAILROOM:
netkit.Tailroom = native.Uint16(datum.Value[0:2])
}
}
}

View File

@@ -23,10 +23,12 @@ import (
)
const (
testTxQLen int = 100
defaultTxQLen int = 1000
testTxQueues int = 4
testRxQueues int = 8
testTxQLen int = 100
defaultTxQLen int = 1000
testTxQueues int = 4
testRxQueues int = 8
testHeadroom uint16 = 32
testTailroom uint16 = 64
)
func testLinkAddDel(t *testing.T, link Link) {
@@ -87,6 +89,12 @@ func testLinkAddDel(t *testing.T, link Link) {
if resultPrimary.SupportsScrub() && resultPrimary.PeerScrub != inputPrimary.PeerScrub {
t.Fatalf("Peer Scrub is %d, should be %d", int(resultPrimary.PeerScrub), int(inputPrimary.PeerScrub))
}
if resultPrimary.Headroom != inputPrimary.Headroom {
t.Fatalf("Headroom is %d, should be %d", resultPrimary.Headroom, inputPrimary.Headroom)
}
if resultPrimary.Tailroom != inputPrimary.Tailroom {
t.Fatalf("Tailroom is %d, should be %d", resultPrimary.Tailroom, inputPrimary.Tailroom)
}
if inputPrimary.Mode == NETKIT_MODE_L2 && inputPrimary.HardwareAddr != nil {
if inputPrimary.HardwareAddr.String() != resultPrimary.HardwareAddr.String() {
t.Fatalf("Hardware address is %s, should be %s", resultPrimary.HardwareAddr.String(), inputPrimary.HardwareAddr.String())
@@ -123,6 +131,12 @@ func testLinkAddDel(t *testing.T, link Link) {
if resultPrimary.Scrub != resultPeer.PeerScrub {
t.Fatalf("PeerScrub from peer is %d, should be %d", int(resultPeer.PeerScrub), int(resultPrimary.Scrub))
}
if resultPrimary.Headroom != resultPeer.Headroom {
t.Fatalf("Headroom from peer is %d, should be %d", resultPeer.Headroom, resultPeer.Headroom)
}
if resultPrimary.Tailroom != resultPeer.Tailroom {
t.Fatalf("Tailroom from peer is %d, should be %d", resultPeer.Tailroom, resultPeer.Tailroom)
}
if inputPrimary.Mode == NETKIT_MODE_L2 && inputPrimary.peerLinkAttrs.HardwareAddr != nil {
if inputPrimary.peerLinkAttrs.HardwareAddr.String() != resultPeer.HardwareAddr.String() {
t.Fatalf("Peer hardware address is %s, should be %s", resultPeer.HardwareAddr.String(), inputPrimary.peerLinkAttrs.HardwareAddr.String())
@@ -1261,6 +1275,82 @@ func TestLinkAddDelNetkit(t *testing.T) {
testLinkAddDel(t, netkit)
}
func TestLinkAddDelNetkitWithHeadroom(t *testing.T) {
minKernelRequired(t, 6, 14)
tearDown := setUpNetlinkTest(t)
defer tearDown()
netkit := &Netkit{
LinkAttrs: LinkAttrs{
Name: "foo",
HardwareAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
Mode: NETKIT_MODE_L2,
Policy: NETKIT_POLICY_FORWARD,
PeerPolicy: NETKIT_POLICY_BLACKHOLE,
Scrub: NETKIT_SCRUB_DEFAULT,
PeerScrub: NETKIT_SCRUB_NONE,
Headroom: testHeadroom,
}
peerAttr := &LinkAttrs{
Name: "bar",
HardwareAddr: net.HardwareAddr{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB},
}
netkit.SetPeerAttrs(peerAttr)
testLinkAddDel(t, netkit)
}
func TestLinkAddDelNetkitWithTailroom(t *testing.T) {
minKernelRequired(t, 6, 14)
tearDown := setUpNetlinkTest(t)
defer tearDown()
netkit := &Netkit{
LinkAttrs: LinkAttrs{
Name: "foo",
HardwareAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
Mode: NETKIT_MODE_L2,
Policy: NETKIT_POLICY_FORWARD,
PeerPolicy: NETKIT_POLICY_BLACKHOLE,
Scrub: NETKIT_SCRUB_DEFAULT,
PeerScrub: NETKIT_SCRUB_NONE,
Tailroom: testTailroom,
}
peerAttr := &LinkAttrs{
Name: "bar",
HardwareAddr: net.HardwareAddr{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB},
}
netkit.SetPeerAttrs(peerAttr)
testLinkAddDel(t, netkit)
}
func TestLinkAddDelNetkitWithHeadAndTailroom(t *testing.T) {
minKernelRequired(t, 6, 14)
tearDown := setUpNetlinkTest(t)
defer tearDown()
netkit := &Netkit{
LinkAttrs: LinkAttrs{
Name: "foo",
HardwareAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
Mode: NETKIT_MODE_L2,
Policy: NETKIT_POLICY_FORWARD,
PeerPolicy: NETKIT_POLICY_BLACKHOLE,
Scrub: NETKIT_SCRUB_DEFAULT,
PeerScrub: NETKIT_SCRUB_NONE,
Headroom: testHeadroom,
Tailroom: testTailroom,
}
peerAttr := &LinkAttrs{
Name: "bar",
HardwareAddr: net.HardwareAddr{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB},
}
netkit.SetPeerAttrs(peerAttr)
testLinkAddDel(t, netkit)
}
func TestLinkAddDelVeth(t *testing.T) {
t.Cleanup(setUpNetlinkTest(t))

View File

@@ -54,7 +54,9 @@ const (
IFLA_NETKIT_MODE
IFLA_NETKIT_SCRUB
IFLA_NETKIT_PEER_SCRUB
IFLA_NETKIT_MAX = IFLA_NETKIT_MODE
IFLA_NETKIT_HEADROOM
IFLA_NETKIT_TAILROOM
IFLA_NETKIT_MAX = IFLA_NETKIT_TAILROOM
)
const (