?

Log in

No account? Create an account
chuck

dadv


Choose your future

Choose to sysadmin


Previous Entry Share Flag Next Entry
MPPC/MPPE в FreeBSD
chuck
dadv

При использовании mpd для организации pptp/l2tp-туннелей чаще всего применяют MPPC и MPPE для компрессии и шифрования трафика туннеля. При этом mpd использует ядерную netgraph-ноду ng_mppc, реализующую нужные алгоритмы. У кода в этой ноде есть одно ужасное свойство. Из-за переупорядочивания или потери сжатых туннельных пакетов у алгоритмов может произойти срыв синхронизации, что приводит к необходимости сторонам произвести re-keying: пересоздать криптографические ключи. Код ng_mppc считает эту процедуру настолько "тяжелой" в смысле загрузки CPU, что при накоплении определенного количества ошибок тупо отключает работу этого туннеля. Внешне это выглядит так: туннель установлен, системные интерфейсы выглядят "как живые", только вот полезный трафик по туннелю ходить перестаёт совсем и требуется переустановка туннеля для возобновления нормальной работы - до следующего срыва. При этом в dmesg попадает сообщение такого вида:

ng_mppc_decompress: too many (4094) packets dropped, disabling node 0xc7020900!

Такое "решение" было мотивировано "защитой от DoS" в 2000-м году, из которого растут ноги этого кода. Не стану обсуждать разумность такого решения в то время, но теперь, когда FreeBSD почти всегда работает на машинах с безумными мегагерцами и гигагерцами, хотелось бы более стабильной работы туннелей.

Попалась мне пара машин под FreeBSD с mpd, которые устанавливают между собой l2tp-туннель, который через несколько секунд после начала работы стабильно воспроизводит эту проблему. Сделал патч для ng_mppc.c, который вводит новый sysctl net.graph.mppe_max_rekey (а так же loader tunnable) со значением по умолчанию 1000 - тот самый порог, после которого непатченная нода ng_mppc прекращает работать. Если присвоить этому sysctl отрицательное значение, то код перестанет блокировать свою работу по достижении порога, а только будет писать в лог указанное выше сообщение. Вместо блокирования туннеля в этом случае mpd производит сброс протокола CCP в туннеле и работа его продолжается, а в логе mpd на одной стороне появляется строка (если, конечно, включено логирование ccp):

CCP: SendResetReq #3 link 0 (Opened)

На второй стороне туннеля:

CCP: rec'd Reset Request #3 (Opened)

Провел тест: запустил ping длинными пакетами по 10 пакетов в секунду, поймал момент превышения порога - в момент сброса CCP потерялось 4 пакета, то есть заминка в работе туннеля составила около 0.4 секунды, вместо полной блокировки.

Если у вас нода ng_mppc.ko подгружается динамически при старте mpd (а не вкомпилирована статически в ядро), то net.graph.mppe_max_rekey=-1000 нужно писать в /boot/loader.conf, а не в /etc/sysctl.conf, так как в момент обработки sysctl.conf при загрузке системы переменной net.graph.mppe_max_rekey ещё не будет существовать. loader.conf задаёт для неё значение по умолчанию, которое ng_mppc использует при своей инициализации.

Применять патч:

fetch http://www.grosbein.net/freebsd/patches/ng_mppc.c.diff
cd /usr/src
patch < /path/to/ng_mppc.c.diff

После этого, если ng_mppc статически собирается с ядром, нужно пересобрать ядро. А если он подгружается динамически, то делаем так:

cd sys/modules/netgraph/mppc
make obj depend && make all install

После чего можно выгрузить модуль командой kldunload ng_mppc (предварительно остановив mpd, если он запущен) и загрузить его заново: kldload ng_mppc.

Update: обновил патч (URL тот же). Вместо одного sysctl net.graph.mppe_max_rekey вводится три:

  • net.graph.mppe.block_on_max_rekey - блокировать ноду по достижению порога ошибок (1) или нет (0), по умолчанию не блокировать (то есть, с примененным патчем никаких настроек для исправления проблемы делать не надо);
  • net.graph.mppe.log_max_rekey - писать ли в лог сообщения о достижении порога (1) или нет (0), по умолчанию 1;
  • net.graph.mppe.max_rekey - задаёт порог (1000 по умолчанию, как и без патча).

Update: Патч принят в основное дерево и даже бекпортирован в 10-STABLE, 9-STABLE и 8-STABLE. Будет в 9.3 и в 10.1. Спасибо Александру Мотину (mav).



  • 1
Женя! Вот почему вы все свои наработки не анонсируете как следует, а? ;)

где, скажем, пост в -net@?

У меня давно зреет тот же вопрос.

Commited & MFC'd вплоть до восьмерки.

Делалось ночью и был очень уставший, чтобы ещё писать по-английски. Да и первоначальная версия патча самому не очень нравилась. Подрихтовал и закинул в PR: http://www.freebsd.org/cgi/query-pr.cgi?pr=182212

Commited & MFC'd вплоть до восьмерки.

Жень, с Праздником!!!

Спасибо :-) Я вообще в отпуске, поэтому пока реагирую не сразу.

Спасибо за пост + патч!
Столкнулся с аналогичной проблемой, решение применил, будем посмотреть... :)

> Спасибо за пост + патч!
> Столкнулся с аналогичной проблемой, решение применил, будем посмотреть... :)

И как результат?

Результат - положительный.
За прошедший период эффект "зависания" проявился только один раз, и то без характерных для этого случая сообщений в логах mpd-сервера. Хотя до применения патча эффект проявлял себя стабильно пару-тройку раз в неделю.
Списал на "подземный стук", особо не разбираясь, т.к. с хостом в это время случались и другие нештатные ситуации.

Commited & MFC'd вплоть до восьмерки.

  • 1