Немного о Iptables, Iproute2 и эмуляции сетевых проблем

Скопипизжено с http://habrahabr.ru/post/237217/

Первая мысль которая пришла мне в голову это использовать 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):

<span class="comment"># grep NETEM /boot/config-$(uname -r)</span>
CONFIG_NET_SCH_NETEM=m

Как видно из вывода, поддержка в виде модуля, поэтому подгружаем его. Также нам понадобится утилита tc из пакета iproute:

<span class="comment"># modprobe sch_netem</span>

Если же ничего нет, необходимо пересобрать ядро. Кто знаком со сборкой ядра — небольшая подсказка, Network emulator находится здесь:

 Networking -->
   Networking Options -->
     QoS and/or fair queuing -->
        Network emulator

Кто незнаком со сборкой ядра, ищите статьи по сборке ядра в документации к вашему дистрибутиву.

Когда все готово, можно приступать. Рекомендую открыть вторую сессию в которой запустить ping до какого-либо узла в локальной сети. Таким образом вносимые эмуляции будут наблюдаться достаточно четко.

Для экспериментов нам понадобится утилита tc из пакета iproute2. Полный синтаксис выглядит следующим образом:

tc qdisc ACTION dev DEVICE add netem OPTIONS
       ACTION := <span class="test_condition">[ add | change | delete ]</span>
       OPTIONS := <span class="test_condition">[ LIMIT ]</span> <span class="test_condition">[ DELAY ]</span> <span class="test_condition">[ DROP ]</span> <span class="test_condition">[ CORRUPT ]</span> <span class="test_condition">[ DUPLICATION ]</span> <span class="test_condition">[ REORDER ]</span>
       LIMIT := limit packets
       DELAY := delay TIME <span class="test_condition">[ JITTER [ CORRELATION ]</span>]] <span class="test_condition">[ distribution { uniform | normal | pareto |  paretonormal } ]</span>
       DROP := drop PERCENT <span class="test_condition">[ CORRELATION ]</span>
       CORRUPT := corrupt PERCENT <span class="test_condition">[ CORRELATION ]</span>]
       DUPLICATION := duplicate PERCENT <span class="test_condition">[ CORRELATION ]</span>]
       REORDER := reorder PERCENT <span class="test_condition">[ CORRELATION ]</span> <span class="test_condition">[ gap DISTANCE ]</span>

1) Задержка пакетов.

Добавляем к отправке пакетов задержку в 100ms:

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms</span>

Здесь мы указываем джиттер и таким образом к уже имеющейся задержке в 100ms и добавляем некоторое отклонение в ± 10ms.

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms 10ms</span>

Теперь добавляем корреляцию, таким образом задержка при отправке слеудющего пакета будет зависеть от задержки предыдущего пакета.

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms 10ms 50%</span>

2) Распределение задержки.

В предыдущих примерах мы получали более-менее равномерное распределение задержек на все количество отправленных пакетов. Однако в настоящем мире, сетевые задержки совсем неравномерны. Для получения более реалистичной картины используется распределение (по-умолчанию, если не указывать распределение явно, то используется normal).

В примере ниже мы указываем распределение pareto, также доступны normal и paretonormal — задержка будет рассчитываться по математическим формулам. Кроме того можно создать свои таблицы распределения. На мой взгляд, это довольно специфичный кейс применения, но вдруг кто-то заинтересуется.

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms 10ms distribution pareto</span>

3) Потеря пакетов.

С этого все и началось, да…

Указывает потерю пакетов в размере 20%.

<span class="comment"># tc qdisc add dev eth0 root netem drop 20%</span>

Дополнительно можно указать корреляцию, в таком случае, генератор случайных чисел будет менее случайным и можно будет наблюдать всплески в потерях:

<span class="comment"># tc qdisc add dev eth0 root netem drop 20% 10%</span>

4) Повреждение пакетов.

Намеренное повреждение пакетов, каким образом оно делается? С указанной вероятностью, в случайное место внутри случайно выбранного пакета, записывается некорректный бит. В итоге, контрольная сумма не сходится — пакет отбрасывается. Также как и в случае потерь, можно указать корреляцию для формирования всплесков.

<span class="comment"># tc qdisc add dev eth0 root netem corrupt 20%</span>

5) Дублирование пакетов.

Дублирование пакетов определяется таким же образом как и потеря либо коррупция пакетов. И конечно же можно указать и корреляцию.

<span class="comment"># tc qdisc add dev eth0 root netem duplicate 20%</span>

6) Переупорядочивание пакетов

В следующем примере 30% пакетов будут отправлены сразу же, остальные будут задержаны на 100ms.

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms reorder 30%</span>

В примере ниже, первые 4 пакета (gap — 1) будут задержаны на 100ms, последующие пакеты будут отправлены немедленно с вероятностью 25% (+корреляция 50%) или наоборот задержаны с вероятностью 75%. Как только пакет будет переупорядочен, итерация повторяется и следующие 4 пакета задерживаются, остальные отправляются немедленно либо задерживаются с указанной вероятностью.

<span class="comment"># tc qdisc add dev eth0 root netem delay 100ms reorder 25% 50% gap 5</span>

Кому лень заморачиваться с этим делом, есть небольшой демо-ролик.

Вот такие дела. Всем спасибо за внимание, экспериментируйте на здоровье.

 
comments powered by Disqus