LINUX.ORG.RU

Проблемы в самописном модуле обработки сетевых пакетов в ядре.

 ,


0

2

В исследовательских целях пишу модуль, реализующий сетевой обмен в контексте ядра. На одном хосте модуль формирует IP/UDP пакет и отправляет его чрез стевой интерфейс. На другом хосте такой же модуль ставит ловушку в цепочку PREROUTING и перехватывает пришедшие пакеты. Вроде отладил, как-то это худо бедно заработало. Но заработало при обмене пакетами малых размеров. Специально начал отладку с маленьких пакетов, так как порции данных, которые надо пересылать могут быть разных размеров. Стоило увеличить размер пакетов сетевого обмена, как начались чудеса. Если payload по udp до 208 включительно, то все ок. Ставлю 216 и более - не работает. Т.е. смотрю отправляемый sk_buf перед самой передачей. Ничего подозрительного не видно в обоих случаях. Смотрю wireshark-ом на принимающей стороне. Что маленький, что большой пакеты заполнены так, как и должны (т.е. между ними не наблюдаю принципиальной разницы, кроме соответствующих размеров). Однако ловушка на приемном конце не может нормально принять большой пакет. Причем видно, что ip_total_len у пойманного пакета такая же, как у отправленного (и захваченного wireshark-ом). А вот tail почему-то указывает, что прочитан только IP-заголовок + UDP-заголовок. Ну т.е., если отправлен пакет с payload 216, то получаю разницу между data и head в 76 байт и tail 106, в итоге между data и tail 28 байт, т.е. всего на IP+UDP заголовки. А дальше мусор. Понимаю, что где-то какой-то обидный ляп, а как его теперь ловить - уже ума не приложу.

Показали бы хоть какой-нибудь кусок вашего кода, а то совсем не понятно, что именно вы там делаете.

mky ★★★★★ ()

Данные в sk_buff могут быть фрагметироваными, посмотрите на реализацию макрос skb_walk_frags и реализацию метода skb_copy_bits

zaz ★★★★ ()
Ответ на: комментарий от zaz

Данные в sk_buff могут быть фрагметироваными, посмотрите на реализацию макрос skb_walk_frags и реализацию метода skb_copy_bits

Что-то вызывает сомнение, что при пересылке 300 байт что-то может фрагментироваться.

zloy_starper ★★★ ()
Ответ на: комментарий от mky

А что тут непонятного то? На одном конце формирую sk_buf с нужными IP и UDP заголовками. Шлю пакет с помощью netdev_start_xmit.

На другом конце с помощью nf_register_hook регистрируется ловушка в NF_INET_PRE_ROUTING. Если отсылается пакет с payload не больше 208 байт, то все хорошо работает. Иначе ловушка читает из области payload какой-то мусор.

На том-же хосте, где работает ловушка, wireshark читает отосланные пакеты ровно такими, какими я их формирую.

Подскажите хотя бы, как wireshark захватывает пакеты. Судя по тому, что я наблюдаю, он это делает где-то еще раньше, чем формируется входящий sk_buf.

zloy_starper ★★★ ()
Ответ на: комментарий от zloy_starper

Подскажите хотя бы, как wireshark захватывает пакеты.

Через AF_PACKET. Соответствующий код в ядре - net/packet/af_packet.c

Sorcerer ★★★★★ ()
Ответ на: комментарий от zloy_starper

Что-то вызывает сомнение, что при пересылке 300 байт что-то может фрагментироваться.

Ну и зря, фрагментация может быть по очень многим причинам, например ваш сетевой адаптер может осуществлять блочную передачу данных фрагментами по 255 байт, тогда sk_buf тоже будут фрагментироватся на этот размер. Или у вас на сервере может быть очень большой траффик из мелких пакетов (скажем по 200 байт), в результате в ядре в кеше будет очень много свободных sk_buf этого размера, и большие пакеты будут фрагментироватся на куски из кеша

zaz ★★★★ ()
Ответ на: комментарий от zaz

Все-таки передавать фрагментами по 28 байт - это уже за гранью здравого смысла. Загрузка там вообще близкая к 0. К тому же, насколько я понимаю, если wireshark нормально читает эти пакеты, то они как-то образуются в «нормальном виде» до сетевой ловушки.

Ну и самое подозрительное, что по параметрам sk_buf он обрезается ровно по IP + UDP заголовку.

Ну да фиг пока с ним. Будет время - посмотрю, в чем может быть причина. Сделал работу не через UDP - проблема пропала.

zloy_starper ★★★ ()
Ответ на: комментарий от zloy_starper

Не важно как вы формируете пакет, для теста можете и с помощью userspace отправлять данные. А для приёма лучше напишите и покажите простейший короткий код, который просто что-нибудь печатает (printk) по каждому принятому пакету. Чтобы было понятно, какой приоритет вы задали своему обработчику, проверяется ли skb_is_nonlinear()...

mky ★★★★★ ()
Ответ на: комментарий от mky

Спасибо. Верный путь указываете, товарищ. :-)

skb_is_nonlinear() говорит, что вырисовывается новая головная боль.

zloy_starper ★★★ ()
Ответ на: комментарий от mky

Попутно уж заодно хочу уточнить. С приемной стороной стало вроде все понятно. А вот, когда в моем коде создается sk_buf (вызываю __netdev_alloc_skb(dev, size, GFP_NOWAIT)), то по умолчанию создается буфер с линейным распределением памяти под данные? Или тут тоже это надо проверять? Или же для нелинейного распределения надо предпринимать явные действия?

zloy_starper ★★★ ()

UDP штука вообще коварная. Если канал между хостами сколько-нибудь сложный, пакеты могут приходить вообще не в том порядке, в котором их отсылали, и на приёмном конце их придётся сортировать. (В моём случае передающая сторона специально предусматривала счётчик пакетов, передававшийся в каждой датаграмме.)

hobbit ★★★★★ ()
Последнее исправление: hobbit (всего исправлений: 1 )
Ответ на: комментарий от zloy_starper

Вроде всегда должен выделяться линейный буфер. Нелинейный sk_buf образуется при приёме данных, драйвер сетёвки так записывает (scatter-gather DMA).

mky ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.