#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. Кажется, что он правильно отсоединяет пакеты от очередей