Вначале немного истории и лирики - решение в самом конце.
Есть у меня сервер с FreeBSD (7.0). Материнка Microstar AMD 9650 на четыре ядра. Занимается VPN (poptop) и шейпингом (dummynet).
Когда резко увеличили канал в интернет (с 20 до 100 мегабит) сервер начал падать пару раз в сутки. При падении выдавал что-то похожее:
Fatal trap 12: page fault while in kernel mode current process = 11 (swi1: net) (на одном ядре) и current process = dummynet (на другом) trap number = 12 panic: page fault
Подозрения на железо. Поменяли все (включая корпус). Не помогло. Поменяли версию операционки. Ставили 5.4, 6.2 потом поставили 7.1-RC2. Не помагает. Причем в половине случаев даже не сам перегружается. (Заготовили пару бубнов и начили разучивать шаманские танцы:)
Временно решили проблему поднятием резерва с перехватом (резервной сервак постоянно пингует основной, когда ответа нет, меняет себе маки и отвечат на ВПН сам). Но это не дело (причем иногда он на пинги отвечал, зараза, нужно что-то другое анализировать или ставить аппаратные вачдоги).
В /var/log/messages перед моментом падения появлелись сообщения ipfw: ouch!, skip past end of rules, denying packet.
Интернет по этому поводу молчит. Все решения сводятся к манипуляцием с ядром и sysctl и заменой железа. Как правило замена железа помагала. (Как потом выснелось, в большинстве случаев ставилось более новое железо и просто падала общая нагрузка и глюки исчезали.)
Раскопали, что в ряде прочессоров AMD 9550-9650 есть глюки с кешем. Попробывали на относительно стором двухядерном - то-же самое.
Попутно опеределили, что версия 7.1-RC2 имеет в том числе два прекрасных усовершенствования.
1. При максимальной загрузке по процесу dummynet (более 90%) на предыдущих версиях резко повышался пинг (с 5 до 300 милисекунд) и держался таким пока загрузка не спадала. В новой версии при загрузке 100% пинги не повышаютя и шейпинг остается на приемлемом уровне (правда не понятно за счет чего это достигается, но все равно приятно)
2. Появилось пару новых ключей в sysctl которые снизили нагрузку на процессы dummynet и sw1: net что благоприятно отобразилось на загрузке всей машины и общей latency системы.
Потом обратили внимание, что сервер пару раз падал на галзах при операциях с фаерволом. Добавление, удаление правил. Стали копать дальше.
У нас в середине фаервола для каждого юзверя создается три правила которые отправляют пакеты на шейпинг. Одно для входящешго и два для исходящего (так надо). При изменении параметров тарифных пакетов клиента правила дропались, менялись параметры пайпов и новые правила создавались. Также аналогично правила создавались и для клиентов, которые вышли за лимит и т.д. Два раза в сутки все правила пересоздавались (в 12 и 8 - ночью скорости для клиентов в два раза выше). Падения сервера были примерно в 18-19 (час пик) и в 12 часов (как правило) . Значит проблема в манипуляциями с фаерволлом.
Стали перед удалением правил и пайп делать команду ipfw add XXX skipto YYY all from any to any и давать задержку до 300 секунд перед удалением, чтобы явно все пакеты из пайп ушли. Стало лучше, но падения остались.
Думали про altq. Подходит с большим скрипом. Во первых не шейпит входящие пакеты. Да можно их шейпить на исходящем интерфесе, но исходящие в моем случае - это динамически сосздаваемые и так-же динамически умирающие tun интерфейсы числом до 500. И как их обллуживать красиво и помощью altq - это тот еще вопрос. Да конечно, можно поставить еще одну машину, только для altq. (но это не решение проблемы - это борьба с последствиями). Второй скользкий вопрос - это поведение altq пр изагрузке процессора до 100%. Интернет говорит, что это поведение не очень, по крайней мере хуже dummynet. (не проверяли на практике, но dummynet на 7.2 при 100% загрузки себя ведет себя прекрасно)
Накопали в инете переписку с коммитерами еще по 4 версии FreeBSD. (сейчас не смог найти что-бы дать ссылку) Речь шла о появлении сообщений ipfw: "ouch!, skip past end of rules, denying packet". Это сообщение появляется когда правило с которого ушли пакеты на dummynet удалено в то время пока в dummynet еще есть пакеты. По умолчанию такие пакеты дропаются (или разрешаются в зависимости от параметров ядра.)
Как для меня представлялась система dummynet. Что-то вроде natd. Существуют трубы (pipe) и queue со своими параметрами. Правилом фаэрвола на них пересылается пакеты. После должной обработки пакеты возвращаются на фаэрвол (если другое поведение не определено настройками - пакет может просто разрешатся). Причем пакет возвращается не на правило с номером большим чем правило отправившее пакет на dummynet как это есть в natd, а пакет возвращается на СЛЕДУЮЩЕЕ правило. И в переписке сказано, что пайпа ДОЛЖНА иметь номер правила фаэрвола (очевидно последнего используемого, т.к. правил может быть много) с которого ушел пакет. Иначе там толи нул толи хз.
И как оказалось, СИСТЕМА ПАДАЕТ КОГДА УДАЛЯЕТСЯ ПРАВИЛО КОТОРОЕ ОТПРАВЛЯЕТ ПАКЕТЫ НА DUMMYNET, причем без разницы, есть ли в данный момент пакеты на обработке dummynet. Причем, когда загрузка меньше 1 (в еденицах из top), то все нормально, а когда загрузка превышает 1 - вероятность падежа повышается прямо пропорционально загрузке.
Решение:
Никогда не удалять правила фаервола, которые отправляют пакеты в DUMMYNET. Создать при старте или при необходимости, определить пайпы или queue и не торгать их больше. Надо запретить пакеты - или deny раньше по фаерволу или дать пользователю пару бит в сек. Надо отменить шейпинг - говорим "bw 0" или сказать skipto. Да, есть мнение, что наличее ненужных pipe (так как скорость на них не лимитируется) только уменьшает производительность (занимают память и dummynet с частотой Hz (из параметров ядра) их обходит), но лучше так, чем kernel panic.
После замены логики - сервер без перезагрузок более недели.
P.S. Не пробывали только менять правила фаэрвола через сеты (ipfw set см. man ipfw) - быть может там другая ситуация