Однажды мне понадобилось в Zabbix сделать мониторинг потери пакетов между мастером и репликами (репликация плохо себя чувствует если канал не очень хороший). Для этого, в Zabbix есть встроенный параметр icmppingloss, на удаленный хост отправляется серия ICMP пакетов и результат фиксируется в системе мониторинга. И вот параметр добавлен, триггер настроен. Казалось бы задача выполена, однако как говорится «Доверяй, но проверяй». Осталось проверить что триггер сработает когда потери действительно будут. Итак, как сэмулировать потерю пакетов? Об этом, да и не только, пойдет речь под катом.
Первая мысль которая пришла мне в голову это использовать iptables. И правда, недолгий поиск привел меня к модулю statistic — если вкратце, то этот модуль обрабатывает пакеты привнося в процесс некоторую статистическую вероятность.
Вобщем задача была решена с помощью правила
iptables -A INPUT -p icmp -s zabbix_ip -m statistic --mode random --probability 0.1 -j DROP
или
iptables -A INPUT -p icmp -s zabbix_ip -m statistic --mode nth --every 10 -j DROP
Как видно тут есть 2 варианта --mode random --probability 0.1 — означает что пакет будет выбран случайно, c вероятностью 10%. И --mode nth --every 10 — обрабатывать каждый десятый пакет. Таким способом я добился потери пакетов около 10%, триггер сработал, все замечательно.
На этом вроде бы можно и остановиться, но совершенно случайно я узнал о такой функциональности как Network Emulator из ядерной подсистемы Network QoS. Причем возможности NetEm гораздо шире чем у модуля statistic:
- задержка (delay) — добавление указанной задержки к отправляемым пакетам на указанном интерфейсе;
- распределение (distribution) — позволяет указать вариант распределения задержки;
- сброс (drop) — позволяет указать потерю пакетов;
- повреждение (corrupt) — определяет возможность повреждения пакетов;
- дублирование (duplicate) — позволяет определить дублирование пакетов перед тем как они будут поставлены в очередь;
- переупорядочивание (reorder) — определяет переупорядочивание пакетов (используется совместно с задержкой);
- лимитирование (limit) — ограничивает эффект выше указанных опций на указанное число пакетов.
Теперь обо всем этом поподробнее.
Network emulator поддерживается с ядер 2.6 и на данный момент оно присутствует во всех современных дистрибутивах (речь о Linux конечно же). Чтобы проверить наличие поддержки Network Emulator в ядре, проверяем конфиг ядра в /boot (либо /proc/config.gz)
# grep NETEM /boot/config-$(uname -r)
CONFIG_NET_SCH_NETEM=m
Как видно из вывода поддержка в виде модуля, поэтому подгружаем его. Также нам понадобится утилита tc из пакета iproute2.
# modprobe sch_netem
Если же, ничего нету, то необходимо пересобрать ядро. Кто знаком с конфигурированием и сборкой ядра — небольшая подсказка, Network emulator находится здесь:
Networking -->
Networking Options -->
QoS and/or fair queuing -->
Network emulator
Кто незнаком со сборкой ядра, ищите статьи по сборке ядра в документации к вашему дистрибутиву.
Когда все готово, можно приступать. Рекомендую открыть вторую сессию в которой запустить ping до какого-либо узла в локальной сети. Таким образом вносимые эмуляции будут наблюдаться достаточно четко.
Для экспериментов нам понадобится утилита tc из пакета iproute2. Полный синтаксис выглядит следующим образом:
tc qdisc ACTION dev DEVICE add netem OPTIONS
ACTION := [ add | change | delete ]
OPTIONS := [ LIMIT ] [ DELAY ] [ DROP ] [ CORRUPT ] [ DUPLICATION ] [ REORDER ]
LIMIT := limit packets
DELAY := delay TIME [ JITTER [ CORRELATION ]]] [ distribution { uniform | normal | pareto | paretonormal } ]
DROP := drop PERCENT [ CORRELATION ]
CORRUPT := corrupt PERCENT [ CORRELATION ]]
DUPLICATION := duplicate PERCENT [ CORRELATION ]]
REORDER := reorder PERCENT [ CORRELATION ] [ gap DISTANCE ]
1) Задержка пакетов.
Добавляем к отправке пакетов задержку в 100ms:
# tc qdisc add dev eth0 root netem delay 100ms
Здесь мы указываем джиттер и таким образом к уже имеющейся задержке в 100ms и добавляем некоторое отклонение в ± 10ms.
# tc qdisc add dev eth0 root netem delay 100ms 10ms
Теперь добавляем корреляцию, таким образом задержка при отправке слеудющего пакета будет зависеть от задержки предыдущего пакета.
# tc qdisc add dev eth0 root netem delay 100ms 10ms 50%
2) Распределение задержки. В предыдущих примерах мы получали более-менее равномерное распределение задержек на все количество отправленных пакетов. Однако в настоящем мире, сетевые задержки совсем неравномерны. Для получения более реалистичной картины используется распределение (по-умолчанию, если не указывать распределение явно, то используется normal).
В примере ниже мы указываем распределение pareto, также доступны normal и paretonormal — задержка будет расчитываться по математическим формулам. Кроме того можно создать свои таблицы распределения. На мой взгляд, это довольно специфичный кейс применения, но вдруг кто-то заинтересуется.
# tc qdisc add dev eth0 root netem delay 100ms 10ms distribution pareto
3) Потеря пакетов. С этого все и началось, да…
Указывает потерю пакетов в размере 20%.
# tc qdisc add dev eth0 root netem drop 20%
Дополнительно можно указать корреляцию, в таком случае, генератор случайных чисел будет менее случайным и можно будет наблюдать всплески в потерях:
# tc qdisc add dev eth0 root netem drop 20% 10%
4) Повреждение пакетов.
Намеренное повреждение пакетов, каким образом оно делается? С указанной вероятностью, в случайное место внутри случайно выбранного пакета, записывается некорректный бит. В итоге, контрольная сумма не сходится — пакет отбрасывается. Также как и в случае потерь, можно указать корреляцию для формирования всплесков.
# tc qdisc add dev eth0 root netem corrupt 20%
5) Дублирование пакетов.
Дублирование пакетов определяется таким же образом как и потеря либо коррупция пакетов. И конечно же можно указать и корреляцию.
# tc qdisc add dev eth0 root netem duplicate 20%
6) Переупорядочивание пакетов
В следующем примере 30% пакетов будут отправлены сразу же, остальные будут задержаны на 100ms.
# tc qdisc add dev eth0 root netem delay 100ms reorder 30%
В примере ниже, первые 4 пакета (gap — 1) будут задержаны на 100ms, последующие пакеты будут отправлены немедленно с вероятностью 25% (+корреляция 50%) или наоборот задержаны с вероятностью 75%. Как только пакет будет переупорядочен, итерация повторяется и следующие 4 пакета задерживаются, остальные отправляются немедленно либо задерживаются с указанной вероятностью.
# tc qdisc add dev eth0 root netem delay 100ms reorder 25% 50% gap 5
Кому лень заморачиваться с этим делом, есть небольшой демо-ролик
Вот такие дела. Всем спасибо за внимание, экспериментируйте на здоровье )))
Автор: lesovsky