Сокет UDP модуля ядра удаляет дейтаграммы, хотя они и используются

#c #sockets #linux-kernel #udp #kernel-module

#c #розетки #linux-ядро #udp #kernel-module #сокеты

Вопрос:

Ситуация

В настоящее время я пишу модуль ядра, который должен обрабатывать пользовательский сетевой протокол, основанный на UDP. Что я делаю (скорее в псевдокоде), так это создаю сокет UDP с

 sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, amp;sk);
  

где sk находится указатель сокета.
Итак, вместо того, чтобы активно опрашивать ядро на предмет новых данных UDP, я зарегистрировал обратный вызов data ready с помощью

 sk->sk_data_ready = myudp_data_ready;
  

А вот полный код myudp_data_ready функции:

 void myudp_data_ready(struct sock *sk) {
    struct sk_buff *skb;
    int err;

    if ((skb = skb_recv_datagram(sk, 0, 1, amp;err)) == NULL) {
        goto Bail;
    }

    // ...
    // HERE, MY CUSTOM UDP-BASED PROTOCOL WILL BE IMPLEMENTED
    // ...

    skb_free_datagram(sk, skb);

    return;
Bail:
    return;
}

  

В чем проблема

Проблема сейчас в том, что я получаю все UDP-пакеты в полном порядке. skb_recv_datagram Функция возвращает буфер сокета, с которым я могу справиться. Однако через некоторое время он перестает работать.

Что я уже пробовал

В /proc/net/udp я вижу, что rx_queue он растет до тех пор, пока не заполнится, а затем пакеты будут отброшены. Это то, где я больше не получаю никаких пакетов в своем коде (очевидно). Это кажется странным. Если я правильно понял, ядро использует счетчик ссылок в буферах сокетов. Если это значение падает до 1, буфер освобождается и отсоединяется от очереди приема. Я заглянул в skb->users поле, которое должно быть счетчиком ссылок. Для него установлено значение 1 , что означает, что мой код является единственным местом, содержащим ссылку на skb . Но ни skb_free_datagram то, ни kfree_skb другое, похоже, не освобождает буфер, так как rx_queue он продолжает расти. И я понятия не имею, почему. У вас есть какие-либо советы? Я что-то упускаю?

Дополнительная информация

Я использую Ubuntu 20.04 с версией ядра 5.4.0-52. У меня есть простое пользовательское приложение, отправляющее UDP-пакеты на определенный порт, на котором прослушивается модуль ядра.

Спасибо вам за вашу помощь.

Комментарии:

1. «Если это число падает до 1» — фактически до 0.

2. У меня такая же проблема с написанием очень похожего кода. Вы когда-нибудь решали эту проблему?

3. Я просто решил проблему, используя вместо этого kernel_recvmsg. Кажется, что он правильно отсоединяет пакеты от очередей