From 584e30216896fd4de6301f9cf937829e16d22c49 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 30 Mar 2026 02:14:47 +0900 Subject: [PATCH] internal/netlink: set receive buffer size This is done by both systemd sd-device and AOSP ueventd to improve robustness. Rosa OS will still handle ENOBUFS via coldboot but a big buffer should mitigate this as well. Signed-off-by: Ophestra --- container/dispatcher.go | 2 +- internal/netlink/netlink.go | 23 ++++++++++++++++++++++- internal/netlink/rtnl.go | 4 ++-- internal/uevent/uevent.go | 4 ++-- internal/uevent/uevent_test.go | 4 ++-- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/container/dispatcher.go b/container/dispatcher.go index 9f971fa5..d3ff4f00 100644 --- a/container/dispatcher.go +++ b/container/dispatcher.go @@ -179,7 +179,7 @@ func (direct) mustLoopback(ctx context.Context, msg message.Msg) { lo = ifi.Index } - c, err := netlink.DialRoute() + c, err := netlink.DialRoute(0) if err != nil { msg.GetLogger().Fatalln(err) } diff --git a/internal/netlink/netlink.go b/internal/netlink/netlink.go index 7324f1a7..6cd15610 100644 --- a/internal/netlink/netlink.go +++ b/internal/netlink/netlink.go @@ -46,7 +46,11 @@ type Conn struct { // Dial returns the address of a newly connected generic netlink connection of // specified family and groups. -func Dial(family int, groups uint32) (*Conn, error) { +// +// For a nonzero rcvbuf, the socket receive buffer size is set to its absolute +// value via SO_RCVBUF for a positive value, or SO_RCVBUFFORCE for a negative +// value. +func Dial(family int, groups uint32, rcvbuf int64) (*Conn, error) { var c Conn if fd, err := syscall.Socket( syscall.AF_NETLINK, @@ -75,6 +79,23 @@ func Dial(family int, groups uint32) (*Conn, error) { return nil, syscall.ENOTRECOVERABLE } + if rcvbuf != 0 { + opt := syscall.SO_RCVBUF + if rcvbuf < 0 { + opt = syscall.SO_RCVBUFFORCE + rcvbuf = -rcvbuf + } + if err = syscall.SetsockoptInt( + fd, + syscall.SOL_SOCKET, + opt, + int(rcvbuf), + ); err != nil { + _ = syscall.Close(fd) + return nil, os.NewSyscallError("setsockopt", err) + } + } + c.family = family c.f = os.NewFile(uintptr(fd), "netlink") if c.raw, err = c.f.SyscallConn(); err != nil { diff --git a/internal/netlink/rtnl.go b/internal/netlink/rtnl.go index e370bae7..521e8569 100644 --- a/internal/netlink/rtnl.go +++ b/internal/netlink/rtnl.go @@ -13,8 +13,8 @@ type RouteConn struct{ conn *Conn } func (c *RouteConn) Close() error { return c.conn.Close() } // DialRoute returns the address of a newly connected [RouteConn]. -func DialRoute() (*RouteConn, error) { - c, err := Dial(syscall.NETLINK_ROUTE, 0) +func DialRoute(rcvbuf int64) (*RouteConn, error) { + c, err := Dial(syscall.NETLINK_ROUTE, 0, rcvbuf) if err != nil { return nil, err } diff --git a/internal/uevent/uevent.go b/internal/uevent/uevent.go index 47091f59..25fd02be 100644 --- a/internal/uevent/uevent.go +++ b/internal/uevent/uevent.go @@ -50,9 +50,9 @@ func (c *Conn) exitExcl() { c.excl.Store(false) } func (c *Conn) Close() error { return c.conn.Close() } // Dial returns the address of a newly connected [Conn]. -func Dial() (*Conn, error) { +func Dial(rcvbuf int64) (*Conn, error) { // kernel group is hard coded in lib/kobject_uevent.c, undocumented - c, err := netlink.Dial(syscall.NETLINK_KOBJECT_UEVENT, 1) + c, err := netlink.Dial(syscall.NETLINK_KOBJECT_UEVENT, 1, rcvbuf) if err != nil { return nil, err } diff --git a/internal/uevent/uevent_test.go b/internal/uevent/uevent_test.go index 7dce4798..9b986ff3 100644 --- a/internal/uevent/uevent_test.go +++ b/internal/uevent/uevent_test.go @@ -116,7 +116,7 @@ func adeB[V any, S interface { func TestDialConsume(t *testing.T) { t.Parallel() - c, err := uevent.Dial() + c, err := uevent.Dial(0) if err != nil { t.Fatalf("Dial: error = %v", err) } @@ -127,7 +127,7 @@ func TestDialConsume(t *testing.T) { }) // check kernel-assigned port id - c0, err0 := uevent.Dial() + c0, err0 := uevent.Dial(0) if err0 != nil { t.Fatalf("Dial: error = %v", err) }