From d62516ed1ee148c58eed60c4fa38c5dc2c3b9622 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 25 Mar 2026 17:11:57 +0900 Subject: [PATCH] internal/netlink: enlarge recvfrom buffer This also uses an array type for the buffer since its size now uses the hardcoded value found in the kernel. Signed-off-by: Ophestra --- internal/netlink/netlink.go | 19 ++++++++++++------- internal/netlink/netlink_test.go | 6 +----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/internal/netlink/netlink.go b/internal/netlink/netlink.go index 406f567b..89f692a5 100644 --- a/internal/netlink/netlink.go +++ b/internal/netlink/netlink.go @@ -23,6 +23,9 @@ func getpid() uint32 { return nlPid } +// net/netlink/af_netlink.c +const maxRecvmsgLen = 32768 + // A conn represents resources associated to a netlink socket. type conn struct { // AF_NETLINK socket. @@ -37,8 +40,8 @@ type conn struct { typ, flags uint16 // Outgoing position in buf. pos int - // A page holding incoming and outgoing messages. - buf []byte + // Pages holding incoming and outgoing messages. + buf [maxRecvmsgLen]byte // An instant some time after conn was established, but before the first // I/O operation on f through raw. This serves as a cached deadline to // cancel blocking I/O. @@ -70,17 +73,19 @@ func dial(family int) (*conn, error) { } c.pos = syscall.NLMSG_HDRLEN - c.buf = make([]byte, os.Getpagesize()) c.t = time.Now().UTC() return &c, nil } +// ok returns whether conn is still open. +func (c *conn) ok() bool { return c.family >= 0 } + // Close closes the underlying socket. func (c *conn) Close() error { - if c.buf == nil { + if !c.ok() { return syscall.EINVAL } - c.buf = nil + c.family = -1 return c.f.Close() } @@ -245,7 +250,7 @@ type HandlerFunc func(resp []syscall.NetlinkMessage) error // returned by f. An error of type [Complete] is returned as nil. func (c *conn) receive(ctx context.Context, f HandlerFunc, flags int) error { for { - buf := c.buf + buf := c.buf[:] if n, _, err := c.recvfrom(ctx, buf, flags); err != nil { return err } else if n < syscall.NLMSG_HDRLEN { @@ -276,7 +281,7 @@ func (c *conn) receive(ctx context.Context, f HandlerFunc, flags int) error { // Roundtrip sends the pending message and handles the reply. func (c *conn) Roundtrip(ctx context.Context, f HandlerFunc) error { - if c.buf == nil { + if !c.ok() { return syscall.EINVAL } defer func() { c.seq++ }() diff --git a/internal/netlink/netlink_test.go b/internal/netlink/netlink_test.go index 0926e3bd..0b7df0f1 100644 --- a/internal/netlink/netlink_test.go +++ b/internal/netlink/netlink_test.go @@ -1,7 +1,6 @@ package netlink import ( - "os" "syscall" "testing" ) @@ -23,10 +22,7 @@ func checkPayload(t *testing.T, testCases []payloadTestCase) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - c := conn{ - pos: syscall.NLMSG_HDRLEN, - buf: make([]byte, os.Getpagesize()), - } + c := conn{pos: syscall.NLMSG_HDRLEN} tc.f(&c) if got := c.pending(); string(got) != string(tc.want) { t.Errorf("pending: %#v, want %#v", got, tc.want)