Netlink: отправка из ядра пользователю - EAGAIN и ENOBUFS - PullRequest
2 голосов
/ 12 декабря 2011

У меня много проблем с отправкой сообщений netlink из модуля ядра в userpace-daemon.Они случайно терпят неудачу.На стороне ядра, genlmsg_unicast завершается с ошибкой EAGAIN, а на стороне пользователя, nl_recvmsgs_default (функция из libnl) завершается с NLE_NOMEM, что вызвано сбоем системного вызова recvmsg с ENOBUFS.

Сообщения Netlink малы, максимальный размер полезной нагрузки составляет ~ 300 Б.

Вот код для отправки сообщения из ядра:

int send_to_daemon(void* msg, int len, int command, int seq, u32 pid) {
    struct sk_buff* skb;
    void* msg_head;
    int res, payload;

    payload = GENL_HDRLEN+nla_total_size(len)+36;
    skb = genlmsg_new(payload, GFP_KERNEL);
    msg_head = genlmsg_put(skb, pid, seq, &psvfs_gnl_family, 0, command);
    nla_put(skb, PSVFS_A_MSG, len, msg);
    genlmsg_end(skb, msg_head);
    genlmsg_unicast(&init_net, skb, pid);

    return 0;
}

Я абсолютно не знаю, почему этопроисходит, и мой проект просто не будет работать из-за этого!Я действительно надеюсь, что кто-то может помочь мне с этим.

Ответы [ 2 ]

2 голосов
/ 09 августа 2013

У меня была похожая проблема при получении ENOBUFS через recvmsg из сокета netlink. Я обнаружил, что моя проблема заключалась в заполнении буфера сокета ядра до того, как пользовательское пространство могло его истощить.

Из справочной страницы netlink (7) :

   However, reliable transmissions from kernel to user are impossible in
   any case.  The kernel can't send a  netlink  message  if  the  socket
   buffer  is  full:  the message will be dropped and the kernel and the
   user-space process will no longer have the same view of kernel state.
   It  is  up  to  the  application to detect when this happens (via the
   ENOBUFS error returned by recvmsg(2)) and resynchronize.

Я решил эту проблему, увеличив размер буфера приема сокета (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, ...) или nl_socket_set_buffer_size () , если вы используете libnl).

2 голосов
/ 14 декабря 2011

Интересно, работаете ли вы на 64-битной машине?Если это так, я подозреваю, что использование int в качестве типа payload может быть причиной некоторых проблем, поскольку genlmsg_new() ожидает size_t, что составляет 64 бита на x86_64.

Во-вторых, я не думаю, что вам нужно добавлять GENL_HDRLEN к payload, поскольку об этом позаботится genlmsg_new() (используя genlmsg_total_size(), который возвращает genlmsg_msg_size(), который в итоге выполняет сложение).Почему это + 36 кстати?Не выглядит очень портативно и неясно, для чего он нужен.

Трудно сказать больше, не глядя на остальную часть кода.

...