[Bug 279444] rtnetlink: recv(4) with MSG_DONTWAIT returns EAGAIN.

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 31 May 2024 22:10:39 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=279444

            Bug ID: 279444
           Summary: rtnetlink: recv(4) with MSG_DONTWAIT returns EAGAIN.
           Product: Base System
           Version: 14.0-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: gnats@duck.com

When reading the title, you're probably thinking, “well, yeah, that's how it
should work.” and while I agree with you, the musl developers don't! [1]
(Though, it's really not their fault.) While testing the glibc netlink
shenanigans bug #279012, I also decided to test musl. In which, I found that
because musl does a recv(2) (which is technically a recvfrom(2)) with
MSG_DONTWAIT on a netlink socket, it always returns -1 (EAGAIN or EWOULDBLOCK).
[1] That said, you can actually get it to work intermittently if you supply
some latency (e.g., strace); however, like mentioned, this tends to be
unpredictable. I imagine that the Linux kernel is not faster than us here, but
rather doing something clever, and we have yet to implement such trickery as
well. I'll attach some code that reproduces the issue. This can be compiled on
the linuxulator and freebsd to the same effect, which implies this problem
resides in the base netlink code.

#include <stdio.h>
#include <string.h>

#ifdef __FreeBSD__
#include <netlink/netlink.h>
#include <netlink/netlink_route.h>
#else
#include <linux/rtnetlink.h>
#endif

#include <arpa/inet.h>

int main(void) {
    int fd;
    fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
    if (fd < 0) return -1;

    unsigned int seq = 1;
    int type = RTM_GETLINK;
    int af = AF_UNSPEC;

    struct nlmsghdr * h;
    union {
        uint8_t buf[8192];
        struct {
            struct nlmsghdr nlh;
            struct rtgenmsg g;
        }
        req;
        struct nlmsghdr reply;
    }
    u;
    int r, ret;

    memset( & u.req, 0, sizeof(u.req));
    u.req.nlh.nlmsg_len = sizeof(u.req);
    u.req.nlh.nlmsg_type = type;
    u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
    u.req.nlh.nlmsg_seq = seq;
    u.req.g.rtgen_family = af;
    r = send(fd, & u.req, sizeof(u.req), 0);
    if (r < 0) return r;

    do {
        r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT);
        if (r <= 0)
            printf("bad recv: %d\n", r);
        else
            printf("good recv: %d\n", r);
    } while (r <= 0);
    return 0;
}


[1] https://elixir.bootlin.com/musl/latest/source/src/network/netlink.c#L31

-- 
You are receiving this mail because:
You are the assignee for the bug.