LINUX.ORG.RU
ФорумAdmin

Шейпер трафика в юзерспейсе (NFQUEUE + raw sockets)

 , , ,


1

1

Привет, лор.

Всегда удивлялся и немного завидовал людям, которые овладели искусством шейпинга трафика в линуксе. Там начиная от терминологии и заканчивая результатами сплошные заклинания и загадки для непосвященных. И еще удивлялся, почему никто не напишет простой шейпер для тупых вроде меня альтернативно одаренных, которые ниасилевают. Удивлялся-удивлялся, никто так и не писал, и решил делать сам.

Получилась вот такая штука https://github.com/vmxdev/damper/

Работает штука приблизительно так:

При старте создаются два потока. В первом NFQUEUE захватывает пакеты, они анализируются, каждому пакету назначается «вес» (или приоритет) и пакет сохраняется в очереди с приоритетами. NFQUEUE выносит вердикт DROP, т.е. пакет дальше не идет. Когда очередь заполнена, пакеты с низким приоритетом затираются высокоприоритетными. Другой поток выбирает пакеты с наибольшим весом и посылает (точнее, перепосылает) их. Перепосылание происходит с ограниченной скоростью, из-за этого собственно и получается шейпирование.

Вес назначается в «модулях», их искаропки 4 штуки. Можно использовать их вместе, можно по отдельности. Веса пакетов, измеренные в каждом модуле, умножаются на коэффициент(каждому модулю можно задать свой) и складываются. Получается результирующий вес

Модули:

  • inhibit_big_flows - подавляет большие потоки. Чем больше передано байт между двумя IP-адресами, тем меньшим становится «вес» пакета. То есть повышается вероятность того что пакет из большой тяжелой сессии будет отброшен. Информация хранится в кольцевом буфере, так что время от времени наступает амнистия (количество отслеживаемых сессий задается в конфиге), потоки замещаются более свежими
  • bymark - вес пакетов задается по марке. iptables-ом выставляется марка по каким-то критериям, для этих пакетов будет применяться коэффициент, указанный в конфиге
  • entropy - вес считается в зависимости от энтропии (Шенноновской) потока. Поток идентифицируется адресами и номером протокола. Для TCP/UDP учитывается еще и порт источника и назначения. Чем выше энтропия, тем меньше вес. Т.е. шифрованный, сжатый, мультимедиа-трафик отбрасывается с большей вероятностью чем остальной
  • и очень примитивный модуль random - просто добавляет случайности в процесс отброса и переупорядочивания пакетов (если использовать только этот модуль, получится классический RED)

Шейпить можно любые направления, хоть входящие, хоть исходящие, все что сможет захватить NFQUEUE и потом корректно обработается сетевым стеком при ре-инъекции в сырой сокет.

Еще шейпер умеет вести примитивную статистику и рисовать графики. Выглядит это так: http://damper.xenoeye.com . Зеленое - сколько пропущено октетов/пакетов, красное - сколько отброшено. График можно позумить/поскроллить.

На больших скоростях и большом количестве пользователей я этот шейпер не тестировал, скорее всего вылезут какие-то неожиданные проблемы. Но на 10-100М и с полутора пользователями выглядит вроде норм. Хотя грузит CPU, но это от корявости кода, можно отпимизировать и оптимизировать.

Если у кого-то есть мысли по поводу, было бы интересно почитать. Экспертов тоже интересно.

Кастну на всякий случай vel, он вроде писал что еще не видел шейперов на NFQUEUE. Вот, как минимум один уже есть

Deleted

Забавный велосипед :)

Есть вопрос: а почему нельзя тупо задерживать accept пакета или выдавать accept на их в другом порядке ? А дропать только то, что действительно должно быть дропнуто.

Дропать пакет, а потом инжектить - IMHO не слишком хорошая идея. С conntrack проблем нет ? А как такой пакет потом фильтровать/натить ?

Шейпить с использованием iptables в любом направлении умеет imq.

Гонять пакеты между ядром и юзерспейс - всегда медленно (даже если оно с mmap) т.к. переключение контекста длительный процесс (особенно в x86).

Собственно, а за что была борьба?

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

почему нельзя тупо задерживать accept пакета или выдавать accept на их в другом порядке ?

Ну я сначала так и хотел сделать. И с наскока не получилось. Пишут, что от такого NFQUEUE плохо. Вердикт нужно выдавать как можно быстрее. Вот тут еще пишут что пробовали просто добавлять задержки перед ACCEPT, «but an order of magnitude of increased delay has been observed for nfqueue»: http://www.dorsal.polymtl.ca/fr/blog/francis-giraldeau/nfqueue-simulate-full-...

С conntrack проблем нет ?

Смотря в какую сторону шейпить. Но вообще да, есть проблемы, я добавлял -j NOTRACK в raw таблицу для ingress трафика

А как такой пакет потом фильтровать/натить ?

То что реинжектнулось, считается локально сгенерированным, т.е. попадает в OUTPUT, дальше можно уже что-нибудь делать.

Мне было интересно посмотреть на альтернативные алгоритмы шейпинга. По содержимому, например. Возможно ли вообще быстро (хотя бы очень грубо) отдетектить сжатый и шифрованный трафик? Как вообще сделать серфинг на узком канале комфортнее? Почему у tc такой норкоманский интерфейс и можно ли сделать проще при приблизительно таком же результате? Вот такие вопросы волновали в процессе

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

"-j NOTRACK" - это писец нату.

С чего бы ему было плохо, если он для этого придуман? Задача быстро реагировать на сообщения о приходящих пакетах, а когда выдавать вердикт - это твое личное дело. Вопрос только в одном - сколько пакетов может ожидать ядро.

детектить можно до шейпера. Детектить нужно соединение. ndpi-netfilter много чего умеет.

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

"-j NOTRACK" - это писец нату.

Это понадобилось только в одном случае, для шейпинга трафика уже от роутера к клиентам, после ната. То есть с натом вроде как никаких проблем нет

ndpi-netfilter

Ну, с моими кривыми руками в ядро лучше лезть по минимуму (или вообще не лезть)

Deleted ()

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

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

Сейчас оно без патчей работает на ядрах > 3.12

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

То, что автор сделал рабочую версию - это хорошо.

Просто у меня возник вопрос - нельзя ли было обойтись без инжекта пакетов, т.к. это сразу ломает кучу вещей.

Без инжекта пакетов это было бы очень приличным решением.

vel ★★★★★ ()

Присоединюсь к остальным. Достойно уважения! Хоть для себя применения и не вижу. :)

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

А. Кажется понял. Ты пишешь о полисинге (в терминах циски): когда превысили полосу, просто отбрасываем пакеты (картинка). Без откладывания их в очередь. Если пытаться задерживать nfqueue-пакеты в его очереди, нужно как-то серьезно поприседать, наверное. И непонятно, получится ли вообще без каких-то трюков. Мне кажется, держать в своей очереди и инъектировать в сырой сокет проще, и это точно работает.

На SO народ тоже советует выдавать всем пакетам вердикт DROP, сохранять в своей очереди и потом уже перепосылать с задержкой ( http://stackoverflow.com/a/31369129 , http://stackoverflow.com/a/6562060 )

Deleted ()
Ответ на: комментарий от anc

wtf? Не узнаю лор. Должны были уже раз 10 дать ссылку на lartc, раз 5 на CoDel и пару раз на статьи Вана Якобсона

Дожили, блин

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

SO в данном случае не показатель.

В смысле «поприседать» ?

Ты в коллбеке получил пакет. Генерить сразу вердикт тебя никто не заставляет. Положи пакет в свою очередь и вернись из коллбека как можно быстрее. Нужно чтобы цикл чтения mnl_socket_recvfrom + mnl_cb_run не тормозил.

Далее по таймеру или после обработки сообщения nfqueue или отдельным тредом разбираем очередь и генерим вердикты.

Нужно только не забыть увеличить размер очереди (NFQA_CFG_QUEUE_MAXLEN) который по-умолчанию 1024, а для реальной работы этого мало. Все что не влезает в очередь пакетов ожидающих вердикта либо дропается, либо пролетает скозняком при --queue-bypass.

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

Судя по тексту топика и проделанной работе вам это не требуется :)

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

Хм. Получается, проблемы были не от того что долго выносил вердикт, а от того что долго спал в коллбэке? Вот ведь. Непонятно, почему никто об этом не пишет, в гугле по «nfqueue delay» только эти советы выносить вердикт DROP и перепосылать.

Сделал щас без реинъекции (и даже пушнул в гитхаб), вроде бы работает, но потестирую еще немного.

Спасибо за разъяснения

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