полезное по линуксу и iphone собрано все интересное мне лично (методом copy-paste из инета и не пыхтите насчет копирайта я ссылки на источник ставлю)

вторник, 30 ноября 2010 г.

RabbitMQ: Введение в AMQP

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

И вот, в один прекрасный день, собрались инженеры с духом, и разработали AMQP — Advanced Message Queuing Protocol. Этот протокол позволяет не задумываться над тем, где находятся получатели сообщения, сколько их, от кого надо ждать сообщение, когда оно будет доставлено получателю. Кроме этого, AMQP снимает с разработчика ещё многие рутинные задачи и позволяет заниматься непосредственной проблемой, а не обслуживанием процесса разработки.

AMQP имеет три базовых понятия:
  • Обменник (exchange)
  • Очередь (queue)
  • Связь, или маршрут (routing key)

Обмен сообщениями осуществляется в пределах одного обменника (есть ещё цепное связывание, но об этом в другой раз), в котором определены связи, являющиеся своеобразными маршрутами, по которым идут сообщения, попавшие в этот обменник. Каждый маршрут связывает обменник с одной или несколькими очередями. Программное обеспечение, реализующее описанные действия, называют AMQP-сервером. Узлы, помещающие сообщения в обменники и получающие их из очередей, называются AMQP-клиентами. Другими словами, AMQP-сервер предоставляет шину обмена данными, а AMQP-клиенты используют эту шину для обмена сообщениями между собой.
Клиенты могут создавать новые обменники (об их типах поговорим позже) и очереди:
Exchange.Declare  TYPE 
Queue.Declare 

Процесс помещения данных на шину называется публикацией. Когда AMQP-клиент публикует сообщение на шину, он задаёт имя обменника и имя связи:
Message.Publish  TO  WITH 

До этого момента, один из клиентов должен осуществить связку, указав имя обменника, очереди и маршрут, соответствующий ей:
Queue.Bind  TO  WITH 

В результате, сообщение будет доставлено в очередь .Но на этом ещё не всё, так как путь сообщения очередью не заканчивается. Один из AMQP-клиентов подписывается на получение сообщений, попавших в заданную очередь:
Queue.Subscribe  TO 

где — идентификатор процесса. Здесь и далее работа с AMQP будет описываться с точки зрения программирования на Erlang, в реализациях клиентов на других языках сообщения вычитываются из очереди явной инструкцией, либо вешаются коллбэки и подписки как таковой нет. После подписки на очередь, все сообщения, попавшие в неё, будут пересылаться подписанному процессу. Если на одну очередьподписано несколько процессов, сообщения будут распределяться по подписчикам методом round-robin.

Для получения ответа, при отправлении запроса в свойствах сообщения заполняется полеReply-To, содержащее, как правило, очередь приватного типа, на которую подписан только отправитель.

На этом пока всё, в следующий раз постараюсь написать про типы обменников и показать примеры кода, хотя посмотреть их можно уже сейчас вот здесь


Оригинал: http://habrahabr.ru/blogs/erlang/64192/

Два твика для ускорения Cydia и iPhone

Cydia – отличный менеджер пакетов для iPhone, iPod touch и iPad с джейлбрейком. Но по умолчанию программа работает слишком медленно. Сегодня мы покажем как легко можно ускорить Cydia и любой “яблочный” гаджет с джейлбрейком.

Отключение автоматического обновления Cydia

Автоматическое обновление в Cydia – одна из самых надоедливых функций программы. Cydia настойчиво обновляет базу репозиториев при каждой загрузке, и при большом количестве источников это сильно замедляет старт программы.
Далее инструкция по отключению автоматического обновления репозиториев в Cydia:
Шаг 1: Запустите Cydia и в разделе Search найдите и установите утилиту SBSettings.
Шаг 2: Во вкладке Sources добавьте источник http://repo.modyouri.com/.
Шаг 3: Вернитесь в раздел Search, найдите утилиту “NoCyfresh i4″ (или “NoCyfresh i3″, если у вас iPhone 3G или 3GS) и установите ее.
Шаг 4: Откройте SBSettings (по умолчанию свайп по строке статуса iOS). Включите опцию NoCyfresh.
Шаг 5: Не закрывая SBSettings, нажмите кнопку Respring.
Шаг 6: Теперь Cydia будет открываться очень быстро и зависания со строчкой Refresh Database пропадут. Если вам понадобится обновить репозитории, то сделать это можно вручную. Для этого в Cydia в разделе Changes достаточно нажать Refresh.

Отключение баннеров на уровне iOS

При просмотре любого пакета в Cydia подгружаются различные ссылки, описания, баннеры, логотипы и т.д. Это существенно замедляет работу приложения. В одной из прошлых статей мы рассматривали как отключаются баннеры в Cydia через SSH. Однако твик SBAdBlockToggle избавляет от всех этих сложностей. При этом SBAdBlockToggle блокирует баннеры на уровне операционной системы!
Шаг 1: Если вы уже подключили источник http://repo.modyouri.com/ для первого твика, то запустите Cydia и во вкладке Search найдите и установите утилиту SBAdBlockToggle.
Шаг 2: После Respring в SBSettings появится значок Adblock. Нажмите у удерживайте его до перезагрузки своего iPhone, iPod touch или iPad.
Шаг 3: Теперь, при просмотре любого пакета в Cydia вы заметите разницу в скорости его запуска. Как я уже говорил, SBAdBlockToggle отключает баннерную рекламу на уровне iOS. Другими словами баннеров не будет во всех приложениях, загруженных из Cydia, App Store и даже разработанных Apple, например Safari!

Источник: http://www.macdigger.ru/iphone-ipod/dva-tvika-dlya-uskoreniya-cydia-i-iphone-dzhejlbrejk.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+Macdigger+%28MacDigger.ru%29

Играем с BGP в Quagga

1 комментарий

Комментарий от: Andrew A. Sabitov [Посетитель]
Всё карачо, но не рассмотрен самый частый случай: Ваша АС с БГП-раутером + 2-3 аплинка к провайдерам. Всё настроено по варианту 3, всё работает, а потом у одного из провайдеров падает _его_ (единственный!!!) аплинк. Картина маслом...

Это кусочек рабочего конфига, который был в работе лет 9 тому назад. Все возможные совпадения адресов считать случайными :)

router bgp 25549
bgp router-id 217.70.98.105
network 195.49.168.0/22

!default AS (Electrosvyaz)
neighbor 217.70.98.106 remote-as 16054
neighbor 217.70.98.106 description Sibirtelecom aka Elektrosvyaz
neighbor 217.70.98.106 filter-list 21701 out
neighbor 217.70.98.106 filter-list 21700 in

! ZSTTK AS
neighbor 81.1.255.45 remote-as 21127
neighbor 81.1.255.45 description ZSTTK
neighbor 81.1.255.45 filter-list 8101 out

ip as-path access-list 21701 permit ^$
ip as-path access-list 21701 permit 25549$
ip as-path access-list 21701 deny .*

ip as-path access-list 21700 deny 21127$
ip as-path access-list 21700 deny 20651$
ip as-path access-list 21700 permit .*

ip as-path access-list 8101 permit ^$
ip as-path access-list 8101 permit 25549$
ip as-path access-list 8101 deny .*

Оригинал: http://blog.peter.am/index.php/2010/11/27/bgp-quagga

Linux на службе у провайдера

Просмотрев большинство тематических постов на хабре был безмерно удивлён тому факту, что крайне скудно освещена тема использования ОС Unix/Linux на службе интернет провайдеров (Internet service provider). Данной статьёй я частично попытаюсь восполнить данный пробел.


Почему в сети интернет наблюдается полное отсутствие таких статей догадаться не сложно — всех кто использует Linux/FreeBSD в ISP сразу же обвиняют в нищебродстве и советуют купить Cisco или уж на совсем крайний случай Juniper. Именно поэтому вторая цель данной статьи показать читателю, что некоторые технические решения на базе ОС Linux по многим показателям на порядки превосходят брэндовые решения от самых известных вендоров.


Шейпинг

Наш первый опыт «нестандартного» использования Linux появился сразу после начала предоставления услуг широкополосного доступа для физических лиц. Необходимо было чем-то «порезать» внешний канал каждого из наших пользователей. Здесь ввиду отсутствия собственных наработок на данную тему пришлось изобретать свой собственный велосипед применяя cbq и собственной обвязки к нему. Данная схема проработала пару месяцев пока мы не осознали всех ее минусов и не упёрлись в производительность машины.

Все дело в том, что система начала «съедать» слишком много soft interrupts даже при не большом трафике, на вскидку при транзитном трафике в 300 мегабит и 30 kpps при 1000 линейных правил cbq (по 2 правила вход/выход на пользователя) на каждом интерфейсе в top si достигал 100%.

Если бы в данный момент перед нами бы встала та же самая задача при тех де самых технических средствах мы бы решали ее с помошью Linux htb tc + хэш фильтры.

NAT

Так как на тот момент мы являлись небольшим местячковым домашним провайдером, то при подключении абонентов физических лиц у нас остро встал вопрос выдавать ли клиенту «белый» маршрутизируемый ip адрес, либо ограничиться выдачей «серых» ip адресов.

Остановились на «серых» адресах, т. к. при их использовании существенно экономился столько ценных на тот момент материал как реальные адреса. Также несколько повышалась безопасность и комфортность работы наших пользователей, т. к. извне их компьютеры не были доступны всей сети интернет «напрямую».

Для NAT-а было выбрано оборудование Cisco в частности Cisco ASA 5505 — на тот момент ее мощности было достаточно чтобы покрыть потребности наших клиентов.

В то же самое время ВДРУГ появилась информация, что заказанная нами Cisco ASA несколько подзадержится, и собственно встал вопрос чем от NAT-ить 100Мбит/с поток.

«На коленке» был собран тестовый стенд из обычного офисного PC-ка с 2 сетевыми гигабитными адаптерами и выяснилось, что при небольшом тюнинге этот самый обычный «писюк» с самыми обычными реалтеками способен отнатить нужный нам поток.

После замены железа через один из наших NAT серверов в пиках проходило 1800 мбит/с (да, да это не описка, трафик почти 2 гигабита/с) при сравнительно небольшой нагрузке на систему.

NETFLOW

Столкнувшись с проблемой сбора статистики работы домашних пользователей до NAT-а т. е. c «серыми» адресами пришли к простейшей схеме получения статистики NETFLOW.

Собрали схему при которой мы «выгоняем» копию всего трафика пользователей (SPAN PORT) в нужные сетевые порты сервера с ОС Linux на борту, а далее с помощью ipt_NETFLOW формируем поток FLOWS на нужный сервер.

Более подробно вместе с конфигами схема работы приведена здесь.

P.S. Мы в курсе, что большинство оборудования Cisco может лить уже сформированный NETFLOW поток в указанный Netflow коллектор, но в нашей схеме сети на тот момент такого оборудования просто не могло быть :)

Терминация пользовательских сетей.

Изначально хотелось дать пользователю ip адрес, маску подсети, и шлюз и не грузить его настройками PPPoE, PPTP, VPN что в конечном итоге должно было несколько разгрузить службу технической поддержки (что и произошло на практике), так как настройка сети становилась достаточно тривиальной в любой пользовательской ОС.

Решив применить наш предыдущий опыт использования ОС Linux пришли к следующей схеме, в ключевых местах сети устанавливаются Linux сервера с парой четырех-портовых сетевых адаптеров, один линк «уходит» в сторону ядра сети остальные в сторону «кластеров». В результате на каждом интерфейсе поднимается куча VLAN-ов с несколькими сетями в каждом из них.

Всего у нас на всю сеть было 4 сервера примерно по 10k абонентов на каждом.

Пиковый трафик достигаемый каждым сервером в часы пик стремился к полутора мегапакетам в секунду. Сервера обменивались друг с другом маршрутами по протоколу ospf.

Блокирование доступа пользователям осуществлялось с помошью ipset.

Бордер

Тут бы на этой счастливой ноте и закончить, но хочется написать о еще одном «не стандартном» применении Linux — в качестве бордера. Так получилось, что у нас вышла из строя Cisco ASR выполняющая функции бордера на который приходило 2 full view от двух аплинков.

Здесь следует небольшое лирическое отступление. Компания Cisco на 100% сдержала свои обязательства и выслала замену в течении нескольких часов после заполнения необходимых документов, но как Вы понимаете клиенты не будут ждать сутки пока новое железо прилетит в наши края. Решение было спонтанным.

Со склада взяли сервер установили на него Linux + quagga и благополучно поставили вместо вышедшей из строя Cisco.

В час пик это чудо инженерной мысли «прожевало» входящий поток 1.4Гбит/c, при суммарном kpps на всех интерфейсах порядка 400.

P.S. В ходе работы нами было собрано и протестировано множество RPM пакетов для дистрибутива CentOS 5 вот лишь небольшой их список:
  • ipset
  • connlimit
  • conntrack-tools
  • ipt_netflow
  • flow-tools
  • quagga


Cкачать их можно из данного репозитория.

P.P.S. Если у Вас есть свои собственные наработки или заметки по поводу использования *nix like OS на службе ISP, добро пожаловать.

Оригинал: http://habrahabr.ru/blogs/sysadm/106932/

Процесс запуска RabbitMQ на Linux

Вступление

Запуск RabbitMQ сервера при более глубоком рассмотрении выглядит весьма запутанным делом. Почему это так и как все все обстоит на самом деле можно прочитать под катом.
  1. Версия RabbitMQ-Server — 2.1.0
  2. ОС: Fedora

Коротко

Внимательно смотрим на PID'ы процессов. Ниже идет объяснение происходящего:
-bash-3.2# /etc/init.d/rabbitmq-server start
root  7732  3834  0 11:54 pts/0    00:00:00 /bin/sh /etc/init.d/rabbitmq-server start
root      7733  7732  0 11:54 pts/0    00:00:00 /bin/sh /usr/sbin/rabbitmq-multi start_all 1
root      7740  7733  0 11:54 pts/0    00:00:00 su rabbitmq -s /bin/sh -c /usr/lib/rabbitmq/bin/rabbitmq-multi  "start_all" "1"
rabbitmq  7741  7740  7 11:54 ?        00:00:00 /usr/lib64/erlang/erts-5.7.5/bin/beam.smp -- -root /usr/lib64/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-  2.1.0/sbin/../ebin -noshell -noinput -hidden -K true -sname rabbitmq_multi7741 -s rabbit_multi -extra start_all 1
rabbitmq  7767  7741  0 11:54 ?        00:00:00 inet_gethost 4
rabbitmq  7768  7767  0 11:54 ?        00:00:00 inet_gethost 4
rabbitmq  7769  7741  0 11:54 ?        00:00:00 /bin/sh /usr/lib/rabbitmq/bin/rabbitmq-server -noinput
rabbitmq  7794  7769  0 11:54 ?        00:00:00 /bin/sh /usr/lib/rabbitmq/bin/rabbitmq-server -noinput
rabbitmq  7795  7794  0 11:54 ?        00:00:00 ps -ef
rabbitmq  7796  7794  0 11:54 ?        00:00:00 grep rabbit
-bash-3.2# echo $$
3834

Подробнее

  • Из shell (PID = 3834) запускается /etc/init.d/rabbitmq-server start;
  • В init.d скрипте (PID = 7732) происходит подгрузка (source) конф. файла /etc/sysconfig/rabbitmq;
  • Из init.d скрипта запускается shell скрипт su rabbitmq -s /bin/sh -c /usr/lib/rabbitmq/bin/rabbitmq-multi «start_all» «1» (PID = 7740); Из него подгужается (source) /usr/lib/rabbitmq/bin/rabbitmq-evn, в котором подгужается /etc/rabbimq/rabbitmq.conf
  • В /usr/lib/rabbitmq/bin/rabbitmq-multi запускается erlang (PID = 7741) с некоторым набором параметром. Наиболее интересным является -s rabbit_multi. Указывающий функцию, которая будет вызвана вместо start (man erl);
  • Из запущенного erlang приложения запускается shell скрипт /bin/sh /usr/lib/rabbitmq/bin/rabbitmq-server -noinput (PID = 7769), в котором и происходит запуск самого rabbitmq-server.
Вот код из rabbit_mulri.erl, в котором происходит вызов shell скрипта:
220 run_rabbitmq_server() ->
 221     with_os([{unix, fun run_rabbitmq_server_unix/0},
 222              {win32, fun run_rabbitmq_server_win32/0}]).
 223
 224 run_rabbitmq_server_unix() ->
 225     CmdLine = getenv("RABBITMQ_script_HOME") ++ "/rabbitmq-server -noinput",
 226     erlang:open_port({spawn, CmdLine}, [nouse_stdio]).
 227 
 228 run_rabbitmq_server_win32() ->
 229     Cmd = filename:nativename(os:find_executable("cmd")),
 230     CmdLine = "\"" ++ getenv("RABBITMQ_script_HOME")
 231                                          ++ "\\rabbitmq-server.bat\" -noinput",
 232     erlang:open_port({spawn_executable, Cmd},
 233                      [{arg0, Cmd}, {args, ["/q", "/s", "/c", CmdLine]},
 234                       nouse_stdio, hide]).
Настолько нетривиальный процесс запуска явно делается из-за мультиплатформенности самого приложения.
Переменные окружения
Теперь у нас есть понимание того, как происходит процесс запуска rabbitmq-server, но нет понимая того как на него повлиять. Рассмотрим немного подробнее запуск самих erlang приложений.
Запуск лаунчера (rabbit_multi)
exec erl \
   -pa "${RABBITMQ_HOME}/ebin" \
   -noinput \
   -hidden \
   ${RABBITMQ_MULTI_ERL_ARGS} \
   -sname rabbitmq_multi$$ \
   -s rabbit_multi \
   ${RABBITMQ_MULTI_START_ARGS} \
   -extra "$@"
Запуск сервера
exec erl
${RABBITMQ_EBIN_PATH}
   ${RABBITMQ_START_RABBIT}
   -sname ${RABBITMQ_NODENAME}
   -boot ${RABBITMQ_BOOT_FILE}
   ${RABBITMQ_CONFIG_ARG}
   +W w \
   ${RABBITMQ_SERVER_ERL_ARGS} \
   ${RABBITMQ_LISTEN_ARG} \
   -sasl errlog_type error \
   -kernel error_logger '{file,"'${RABBITMQ_LOGS}'"}' \
   -sasl sasl_error_logger '{file,"'${RABBITMQ_SASL_LOGS}'"}' \
   -os_mon start_cpu_sup true \
   -os_mon start_disksup false \
   -os_mon start_memsup false \
   -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \
   ${RABBITMQ_SERVER_START_ARGS} \
   "$@"
Думаю теперь видно какие переменные окружения влияют на каждый из erlang процессов. Изменять данные параметры рекомендуется в /etc/rabbitmq/rabbitmq.conf, который как мы помним подгружается при запуске /usr/lib/rabbitmq/bin/rabbitmq-multi.Вот так выглядит запущенный сервис с параметрами по-умолчанию:
exec erl -noinput -sname rabbit@hostname -boot /var/lib/rabbitmq/mnesia/rabbit@hostname/plugins-scratch/rabbit \    
   -config /etc/rabbitmq/rabbitmq +W w  +K true +A30 +P 1048576 -kernel inet_default_listen_options [{nodelay,true}] \
   -kernel inet_default_connect_options [{nodelay,true}] \
   -sasl errlog_type error -kernel error_logger '{file,'/var/log/rabbitmq/rabbit@hostname.log'}' \
   -sasl sasl_error_logger '{file,'/var/log/rabbitmq/rabbit@hostname-sasl.log'}' \
   -os_mon start_cpu_sup true -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit@hostname" -noinput

Итог по конф. файлам

В итоге за работу rabbitmq-server отвечают 3 конф. файла:
  • /etc/sysconfig/rabbitmq; — В нем принято указывать какие-либо низкоуровневые параметры (например ulimit)
  • /etc/rabbitmq/rabbitmq.conf; — Настраиваются переменные окружения для запуска erlang
  • /etc/rabbitmq/rabbitmq.config. — Настраивается сам rabbitmq-server
Надеюсь кому-то эта статья сэкономит немного времени. О том какие именно значения выставлять переменным, влияющим на работу сервера — это уже дело личное. Возможно я напишу об этом несколько позже.

Оригинал: http://habrahabr.ru/blogs/linux/105364/
 

Еще один способ отбиться от небольшого DDOS

Все нижеописанное относится к GNU/Linux 2.6.x. ДДОС совершенно тупой, разномастный: syn/tcp/udp/icmp flood тупо на все открытые порты, мегабит на 60. UDP срали вообще куда попало. Но основная атака конечно на HTTP. По этому, тушим сервисы и пишем….

Немного sysctl…

vm.min_free_kbytes=70000
net.core.somaxconn=65536
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.ip_local_port_range = 2000 61000
net.ipv4.tcp_fin_timeout = 25
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_timestamps = 0
net.core.rmem_max=16777216
net.core.wmem_max=32777216
net.ipv4.tcp_no_metrics_save=0
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 187380 32777216
net.core.netdev_max_backlog=16384
net.ipv4.tcp_max_syn_backlog=4096
net.ipv4.ip_conntrack_max=600000
net.ipv4.icmp_echo_ignore_all=1
net.ipv4.netfilter.ip_conntrack_max=500000
net.netfilter.nf_conntrack_max=500000
Не забываем перезапустить Network.

Немного iptables….

# Форвард нам нэ нада
iptables -P FORWARD DROP
# BAN – цепочка для помещения туда айпи хостов, ведущих себя не правильно ) Ну типа
# iptables – I BAN -s 123.123.123.123 -j DROP
iptables -N BAN
# TRUSTED – цепочка для помещения туда правильных хостов и хостов откуда мы сидим в шелле. Типа
# iptables -I TRUSTED -s 111.111.111.111 -j ACCEPT
iptables -N TRUSTED
# Стандартный заголовок, eth1 – наш интерфейс внешний
# если есть еще интерфейсы, надо их тоже запрячь правилами разрешения как у lo
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i eth1 -m state –state ESTABLISHED -j ACCEPT
iptables -A INPUT -i eth1 -m state –state RELATED -j ACCEPT
# Проход по белым и черным цепочкам
iptables -A INPUT -i eth1 -j TRUSTED
iptables -A INPUT -i eth1 -j BAN
# У меня висит только сервис http, по этому здесь такая себе мини защита по данному порту
# Насчет –seconds 10 –hitcount 10, курим маны, экспериментируем, ставим то, что подойдет.
# Режем всех TCP на порту 80, которые за последние 10 секунд сделали 10 попыток открыть соединение
# (кому то может не подойти!)
iptables -A INPUT -p tcp -m tcp –dport 80 -m state –state NEW -m recent –update –seconds 10 –hitcount 10 –name httpd –rsource -j DROP
# А остальных разрешаем
iptables -A INPUT -i eth1 -p tcp -m tcp –dport 80 -j ACCEPT
# Вот по этой теме ддосеры тоже затрахали, по этому был категоричен
iptables -A OUTPUT -p udp -j DROP
iptables -A OUTPUT -p icmp -j DROP
# Здесь добавить разрешения на прочие порты, у меня прочих не было
# …
# Здесь добавить (!!!) свои айпи, с которых сидишь в шелле
iptables -A TRUSTED -s 111.111.111.111 -j ACCEPT
# Хорошо подумаем, покурим, затаим дыхание и напишем….
iptables -P INPUT DROP
# Что означает зарезать все, что не разрешили на INPUT’е
А теперь запускаем nginx/httpd и прочую лабуду. Надеюсь заработает. У меня заработало, как будто ничего и не происходило :) 
 
Оригинал: http://www.pentarh.com/wp/2010/08/11/%d0%95%d1%89%d0%b5-%d0%be%d0%b4%d0%b8%d0%bd-%d1%81%d0%bf%d0%be%d1%81%d0%be%d0%b1-%d0%be%d1%82%d0%b1%d0%b8%d1%82%d1%8c%d1%81%d1%8f-%d0%be%d1%82-%d0%bd%d0%b5%d0%b1%d0%be%d0%bb%d1%8c%d1%88%d0%be%d0%b3/

Отбил небольшой DDOS ;)

DDOS на HTTP 20 Мбит входящего. Отбито софтварным костылем 8-)
Конфигурация машины: Quad Core Xeon / 4G RAM, CentOS 5.3 x86_64
Сервисы: apache(back) + nginx(front)
Sysctl:
kernel.shmall = 4294967296
vm.min_free_kbytes=70000
net.core.somaxconn=65536
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.ip_local_port_range = 2000 61000
net.ipv4.tcp_fin_timeout = 25
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_timestamps = 0
net.core.rmem_max=8388608
net.core.wmem_max=16777216
net.ipv4.tcp_no_metrics_save=0
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 87380 16777216
net.core.netdev_max_backlog=65536
net.ipv4.tcp_max_syn_backlog=4096
net.ipv4.ip_conntrack_max=300000
nginx:
worker_rlimit_nofile 80000;
events {
worker_connections  65536;
use epoll;
}
http {
gzip off; # ;)
keepalive_timeout  0;
server_tokens off;
reset_timedout_connection on;
server {
listen x.x.x.x default deferred;
log_format IP $remote_addr;
location / {
proxy_pass http://127.0.0.1/;
….
access_log /var/log/nginx/ipban IP;
apache: ServerLimit и MaxClients установить так, чтобы не засрало более чем 80% памяти. (В top’е можно глянуть сколько памяти потребляет каждый процесс).
Собсно скрипт. Запускается по крону раз в минуту и банит нах айпи, которые за эту минуту обратились к скриптовой части более 20 раз.
#!/usr/bin/perl
system(‘mv /var/log/nginx/ipban /var/log/nginx/ipban.proc’);
system(‘touch /var/log/nginx/ipban’);
system(«/etc/init.d/nginx reload»);
open $f,’/var/log/nginx/ipban.proc’;
%h=();
while(<$f>) {
chomp;
if (/\d+\.\d+\.\d+\.\d+/) {
unless ($h{$_}) {
$h{$_}=1;
} else {
$h{$_}++;
}
}
}
close $f;
foreach $k (keys(%h)) {
if ($h{$k} > 20) {
system(«iptables -I INPUT -s $k -j DROP»);
print «$k banned\n»;
}
}
20 -число вычисленное в ходе проб и ошибок применительно к этому серверу и location’у nginx. После того как скрипт беспощадно побанил 2к хостов, сервер начал подавать внешние признаки жизни, после 3к забаненых зомби начала грузицца морда.
В процессе работы мой рабочий комп был дважды забанен в ходе экспериментов ))
Более серъезный DDOS конечно будет трудно отбивать тупой банилкой.
АПДЕЙТ. Время шло, таблица бана росла, ддосеры не унимались.
Поставил вот эту хрень http://www.configserver.com/cp/csf.html
Софтина умеет вообще много чего. Но практически все что она умеет бесполезно. Кроме temporary ban ip address.
В конфигах отключил практически все, ибо оно (все) мешало. Мне надо было от этой проги только то, чтобы она банила айпи с TTL. Т.е. на время. И крон стал пускать раз в 5 минут.
Соответственно, в кроновом скрипте поменял
if ($h{$k} > 20) {
system(«iptables -I INPUT -s $k -j DROP»);
На
if ($h{$k} > 60) {
system(«/usr/sbin/csf –tempdeny $k 28800″);
Так же цель атаки – страницу, сделал статичной.  ДДОС просел, сайт ожил.

Оригинал  http://www.pentarh.com/wp/2009/05/02/%d0%9e%d1%82%d0%b1%d0%b8%d0%bb-%d0%bd%d0%b5%d0%b1%d0%be%d0%bb%d1%8c%d1%88%d0%be%d0%b9-ddos/

пятница, 26 ноября 2010 г.

IPoE, а также Client-VLAN и DHCP Option 82

В этой статье я опишу что из себя представляет технология доступа в Интернет IPoE, которой на самом деле не существует. А также расскажу про схему Client-VLAN и про опцию 82 DHCP (DHCP Option 82), которые стали неотъемлемой частью этой несуществующей технологии. Все это, конечно же, с технической точки зрения и с примерами конфигов.

Существует множество технологий доступа в Интернет для конечных абонентов. В России особенно популярны две: PPTP и PPPoE. В обоих случаях создается PPP-туннель, производится аутентификация, и внутри туннеля ходит абонентский IP-трафик. Основное отличие этих протоколов – они работают на разных уровнях сетевой модели OSI. PPPoE работает на втором (канальном) уровне, добавляя специальные теги, идентифицирующие конкретный туннель, в Ethernet-фреймы. PPTP работает на третьем (сетевом) уровне, упаковывая IP-пакеты в GRE.


IPoE


IPoE принципиально отличается от PPTP и PPPoE. Вообще этой технологии не существует. Нет RFC, нет никаких стандартов ее описывающих. Сам термин придуман, скорее всего, в России и является абстрактным. Означает он следующее: IP over Ethernet. Смысл именно такой, как и расшифровка – IP-трафик поверх Ethernet, грубо говоря, обычная локалка. Абоненту выдается в лучшем случае статический или динамический белый IP-адрес, в худшем случае серый IP с NAT. Контроль доступа в данном случае может осуществляется при помощи привязок IP-MAC на коммутаторах доступа или на BRAS или выделения VLAN на каждого абонента (так называемый Client-VLAN).

Client-VLAN


При использовании технологии Client-VLAN возникает проблема: как сэкономить IP-адреса? Ведь, если подумать, каждому клиенту надо выделять /30 подсеть. На самом деле проблема легко решаема. Привожу пример для маршрутизатора на базе Linux:
ip route add unreachable 192.0.2.0/24
ip addr add 192.0.2.1/32 dev lo

vconfig add eth0 101
ip link set eth0.101 up
ip route add 192.0.2.101/32 dev eth0.101 src 192.0.2.1

Подсеть 192.0.2.0/24 рекомендована IANA для использования в примерах.

Это классический Cisco'вский ip unnumbered в Linux'овой реализации. IP шлюза (192.0.2.1) вешается на loopback-интерфейс, делается unreachable для всей подсети, чтобы пакеты ходили только на хосты, для которых прописан роутинг. Далее поднимается VLAN и прописывается роутинг на конкретный хост (маска /32) с src шлюза. А можно сделать немного иначе (это лишний раз демонстрирует гибкость Linux):
ip route add unreachable 192.0.2.0/24

vconfig add eth0 101
ip link set eth0.101 up
ip addr add 192.0.2.1/32 dev eth0.101
ip route add 192.0.2.101/32 dev eth0.101

Или так:
ip route add unreachable 192.0.2.0/24

vconfig add eth0 101
ip link set eth0.101 up
ip addr add 192.0.2.1/24 dev eth0.101
ip route del 192.0.2.0/24 dev eth0.101
ip route add 192.0.2.101/32 dev eth0.101

Все эти варианты работают, можно выбрать тот, при котором интерфейсы отображаются наиболее удобным образом. Во всех случаях IP абонента – 192.0.2.101/24.

Proxy_arp


Еще одна проблема, с которой вы можете столкнуться – нет связи между абонентами в разных VLAN и с IP из одной подсети. Действительно, система абонента видит, что IP-адрес назначения в одной подсети с ней, и шлет ARP-запросы, чтобы определить MAC, но из этого ничего не выходит, т.к. они в разных VLAN. Для решения этой проблемы служит технология proxy_arp. Суть ее в том, что маршрутизатор при получении ARP-запросов с интерфейса будет проверять есть ли у него запрашиваемый IP на других интерфейсах. Если есть, то в ответ на ARP-запрос выдаст свой MAC. Таким образом, пакеты будут отправляться на маршрутизатор, который позаботится об их доставке. Включается proxy_arp для конкретного интерфейса следующим образом:
sysctl net.ipv4.conf.eth0/101.proxy_arp=1

или
echo 1 > /proc/sys/net/ipv4/conf/eth0.101/proxy_arp


DHCP Option 82


При использовании IPoE DHCP упростит настройку сети на стороне абонента до нуля. Воткнул патчкорд и ты в сети. Только возникает вопрос: как DHCP узнает кому какой адрес выдавать? Можно определять по MAC, особенно если вы уже используете привязки IP-MAC. Но привязки MAC чреваты частыми звонками в поддержку, т.к. абоненты иногда меняют оборудование. Справиться с этой проблемой поможет расширение протокола DHCP – Option 82. Опция 82 содержит два поля:
  • Agent Circuit ID – номер порта DHCP-релэя, на который пришел DHCP-запрос.
  • Agent Remote ID – некий идентификатор самого DHCP-релэя.

В качестве DHCP-релэев при этом обычно выступают коммутаторы доступа, к которым непосредственно подключаются абоненты. В качестве Agent Remote ID обычно используется MAC коммутатора (по умолчанию в D-Link). Опция 82 поддерживается широким диапазоном оборудования, в том числе типичными у российских провайдеров D-Link DES-3526/3028/3200.
На коммутаторах D-Link есть два режима DHCP-релэя: dhcp_relay и dhcp_local_relay. dhcp_relay работает глобально, для всех портов и VLAN, при этом добавляется опция 82 и запрос передается уже не бродкастом, а непосредственно на DHCP-сервер, т.е. это полноценный DHCP-релэй. dhcp_local_relay работает для конкретных VLAN, но запрос по сути не релэится, а в него просто добавляется опция 82.
Базовые настройки dhcp_relay на D-Link'ах:
enable dhcp_relay
config dhcp_relay option_82 state enable
config dhcp_relay add ipif System 192.168.0.1

192.168.0.1 – IP-адрес DHCP-сервера, доступного в управляющем VLAN.
Базовые настройки dhcp_local_relay:
enable dhcp_local_relay
config dhcp_local_relay vlan 101 state enable

И наконец приведу базовый конфиг для ISC's DHCP с комментариями:
# пишем в лог
log(info, "***");
if exists agent.circuit-id {
 # присутствует опция 82
 # пишем в лог выданный IP-адрес, Agent Remote ID, Agent Circuit ID
 log( info,concat("*Leased ",binary-to-ascii(10,8,".",leased-address)," (with opt82)") );
 log( info,concat("*Remote-ID: ",binary-to-ascii(16,8,":",substring(option agent.remote-id,2,6))) );
 log( info,concat("*Port: ",binary-to-ascii(10,8,"",suffix(option agent.circuit-id,1))) );
} else {
 # опции 82 нет
 # пишем в лог выданный IP-адрес
 log( info,concat("*Leased ",binary-to-ascii(10,8,".",leased-address)," (without opt82)") );
}
log(info, "***");


# в данном примере 192.0.2.101/24 - IP абонента, подключенного к коммутатору с MAC 0:c:29:ec:23:64, на порт 1
# MAC-адрес левый, взят с виртуалки VMWare
# 192.168.0.0/24 - подсеть управления коммутаторами, с адресов в этой подсети будут приходить DHCP-запросы
# эти две подсети следует объединить в одну shared-network для корректной работы

shared-network test {

subnet 192.0.2.0 netmask 255.255.255.0 {

 # определяем класс

 class "v101" {

  # определяем условия соответствия классу:
  # Agent Circuit ID = 1, Agent Remote ID = 0:c:29:ec:23:64
  # обратите внимание - ведущие нули в Agent Remote ID не пишутся (т.е. c вместо 0c и т.д.)

  match if (binary-to-ascii(10,8,"",suffix(option agent.circuit-id,1)) = "1") and
   (binary-to-ascii(16,8,":",substring(option agent.remote-id,2,6)) = "0:c:29:ec:23:64");
 }

 # собственно выдаем IP классу

 pool {
  range 192.0.2.101;
  allow members of "v101";
 }
}

subnet 192.168.0.0 netmask 255.255.255.0 {
}
}
 
 
Источник: http://habrahabr.ru/blogs/sysadm/108453/ 

Шейпирование трафика в Linux. Часть 2

Вторая часть статьи об управлении трафиком в Linux. В статье приведены примеры приоретизации трафика (QoS) и рассказано об использовании hash таблиц при фильтрации трафика (fast hash tables), использование которых позволяет существенно увеличить производительность.
В первой части мы остановились на генерации конфигов средней сложность для htbinit. Сегодня мы поговорим о приоретизации трафика и использовании хэш таблиц в фильтрах. Я подразумеваю, что Вы прочитали первую часть статьи .
Предположим, что нам надоели замечания пользователей о высоком пинге, надоели постоянные детские вопли на форуме о том, что в counter-strike играть невозможно: «лаги страшные», или «у меня странички медленно грузятся, вконтакте открывался 10 минут», а писать что все замеры нужно производить при отключенном «торренте» уже нету сил.
Посему тто бы наша совесть была чиста, и мы могли не кривя душой сказать: «проблема на стороне провайдера предоставляющего данный сервис»(обозначить направление движения в сторону южного полюса) — озаботимся приоретизацией трафика.

Приоритеты выставим в таком порядке:
1. icmp
2. udp
3. tcp port 80
4. bulk traffic

Рассмотрим ограничение полосы на внутреннем интерфейсе, управлять будем «скоростью скачивания».
Напомню.
В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

Пример

#!/bin/bash

#"Очищаем" интерфейс eht1
/sbin/tc qdisc del dev eth1 root handle 1: htb default 15
#Создаем заново дисциплину и указываем дефолтный класс
/sbin/tc qdisc add dev eth1 root handle 1: htb default 15
#Создаем общий для клиентов класс
/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit

#Создаем корневой класс клиента
/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 512kbit ceil 512kbit

#Создаем 4 подкласса для каждого из видов трафика
/sbin/tc class add dev eth1 parent 1:10 classid 1:11 htb rate 1kbit ceil 512kbit prio 1
/sbin/tc class add dev eth1 parent 1:10 classid 1:12 htb rate 1kbit ceil 512kbit prio 2
/sbin/tc class add dev eth1 parent 1:10 classid 1:13 htb rate 1kbit ceil 512kbit prio 3
/sbin/tc class add dev eth1 parent 1:10 classid 1:14 htb rate 1kbit ceil 512kbit prio 4

#Создаем дисциплины шейпирования для конечных классов
/sbin/tc qdisc add dev eth1 parent 1:11 handle 11: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:12 handle 12: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:13 handle 13: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:14 handle 14: sfq perturb 10

Создаем 4 фильтра, для каждого из видов трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.


Думаю из примера видно, что для реализации приоретизиции трафика мы создали для каждого отдельный класс. Далее создаем фильтры, причем чем меньше prio, тем больше у трафика приоритет. Вообще правила обрабатываются согласно тому как их добавляли, в случае с приоритетами — первыми обслуживаются правила, имеющие наивысший приоритет.
Так же вы можете каждому из классов обзначить RATE равный одной четвертой от RATE корневого класса клиента, что бы уже наверняка.
Хочу обратить внимание, на то что нам пришлось создать 4 фильтра, для оного ип, а если ип 3-4 тысячи, то получим огромный линейный список правил — в итоге производительность упадет ниже плинтуса.
Что бы этого избежать воспользуемся «быстрыми» хэш таблицами.
О том, что такое хэш таблицы Вы можете посмотреть на Википедии.
Создадим 4 таблицы по 256 ячеек, каждая из таблиц будет оценивать один из октетов ип адреса.
И в конечном итоге, вместо поиска по всему списку, как это было бы в классическом варианте, мы уменьшим количество проверок и значительно снизим нагрузку.
Пример.
#Создаем корневой фильтр
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32
#Создаем 4 хеш таблицы для каждого октета
/sbin/tc filter add dev eth1 parent 1:0 handle 10: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 11: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 12: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 13: protocol ip u32 divisor 256
#Создаем фильтр направлящий весь трафик в хеш таблицу с ID 10
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:
#Добавляем правило в 10 хеш таблицу, если первый октет равен 192, то оправляем пакет в 11 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 10:c0: match ip dst 192.0.0.0/8  hashkey mask 0xff0000 at 16 link 11:
#Добавляем правило в 11 хеш таблицу, если второй октет равен 168, то оправляем пакет в 12 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 11:a8: match ip dst 192.168.0.0/16 hashkey mask 0xff00 at 16 link 12:
#Добавляем правило в 12 хеш таблицу, если третий октет равен 2, то оправляем пакет в 13 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 12:2: match ip dst 192.168.2.0/24 hashkey mask 0xff at 16 link 13:

#Добавляем правила в 13 хеш таблицу, оцениваем 4 октет и направляем в необходимый класс, в зависимости от вида трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 ht 13:2: match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.

Ниже приведен листинг скрипка генерирующего правила для tc включающие в себя приоретизацию и хеш фильтры.
Скрип полностью рабочий, думаю не составит большого труда модифицировать его под себя.
При переходе с линейных фильтров на хеш таблицы нагрузка упала почти в 4 раза.
#!/bin/bash
mysql="mysql -ppass -u user -h host"
#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внешних интерфейсов
echo "select ext_iface from system.shaper_view group by ext_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:";
}'

#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внутренних интерфейсов
echo "select int_iface from system.shaper_view group by int_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip src 0.0.0.0/0 hashkey mask 0xff000000 at 12 link 10:";
}'


#создаем классы, фильтры,дисциплины и при необходимости заполняем таблицы хешей
echo "select user_id,ip,speed,int_iface,ext_iface from system.shaper_view order by user_id;"|$mysql|sed 1d|
awk '
BEGIN{
buf=0;
class_id=255;
tc_class="/sbin/tc class add dev";
tc_qdisc="/sbin/tc qdisc add dev";
tc_filter="/sbin/tc filter add dev";
}
{
if(buf!=$1)
  {
  printf "%s%x%s\n", "# ",class_id," "class_id" "$2;
  client_speed=$3*128;
  printf "%s%x%s\n",tc_class" "$4" parent 1:1 classid 1:",++class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  printf "%s%x%s\n",tc_class" "$5" parent 1:1 classid 1:",class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  client_class=class_id;
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  }
split($2,ip,".");
if (ht_1[ip[1]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip dst "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 16 link 11:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip src "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 12 link 11:";
ht_1[ip[1]]=1;
}
if (ht_2[ip[2]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip dst "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 16 link 12:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip src "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 12 link 12:";
ht_2[ip[2]]=1;
}
if (ht_3[ip[3]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip dst "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 16 link 13:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip src "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 12 link 13:";
ht_3[ip[3]]=1;
}
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 17 0xff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 17 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 6 0xff match ip dport 80 0xffff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 flowid 1:",client_class
buf=$1;
}'

* This source code was highlighted with Source Code Highlighter.

Надеюсь данный опус помог Вам вникнуть в основы управления трафиком в Linux.

Источник: http://habrahabr.ru/blogs/sysadm/89002/

Шейпирование трафика в Linux

Под катом описано как шейпировать трафик в Linux и что для этого нужно знать.
Осуществлять шейпирование трафика будем посредством утилиты tc из пакета iproute2.
Знания без которых нельзя осознать всю полноту управления трафиком в Linux:
Шейпировать можно только исходящий из интерфейса трафик. (в связи с чем возникает проблема с nat, о ней мы поговорим позже). Предположим, что имеется роутер между «интернетом» и абонентом. В роутер воткнуто две сетевые карты: eth0 смотрит на абонента, а eth1 в мир. Для ограничения «скорости скачивания» правила шейпирования описываем на eth0, для ограничения «отдачи» — на eth1.
Необходимо понимать разницу между rate и ceil. Rate — гарантированная полоса пропуская, Ceil — максимальная полоса которую может получить данный класс, rate не может быть больше ceil
Параметры rate и ceil для корневого класса должны совпадать. Таким образом мы определяем общую полосу пропускания.
Сумма Rate'ов классов-потомков, не должна превышать Rate родительского класса. Конечно можно не выполнять этот пункт, но тогда могут возникнуть проблемы с предоставлением «гарантированной полосы пропускания».
Идентификаторы классов указаны в шестнадцатеричной системе, и должны находиться в пределах от 2 до 2^16
Для промежуточных классов необязательно создавать дисциплины и фильтры.
Идентификаторы классов в пределах интерфейса должны быть уникальны.

В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

В принципе все просто, но в реальной жизни придется потратить много нервов, что бы добиться желаемого результата.
Один из способов добиться результата не тратя много нервов — использовать скрипт htbinit (взять его можно с sourceforge.net/projects/htbinit/). Синтаксис конфигов простой, создание классов тоже просто.
Для построения конфигураций средней сложность вполне достаточно.
Пример.
Имеется локальная сеть, средних размеров. Вам необходимо ограничивать скорость абонентов согласно прейскуранту, трансляция адресов (NAT) происходит на другом сервере.

Получение htbinit
debian:~# wget downloads.sourceforge.net/project/htbinit/HTB.init/0.8.5/htb.init-v0.8.5?use_mirror=surfnet
debian:~# mv htb.init-v0.8.5 /usr/local/sbin/
debian:~# cd /usr/local/sbin/
debian:/usr/local/sbin# mv htb.init-v0.8.5 htb.init
debian:/usr/local/sbin# chmod +x htb.init

По умолчанию htbinit хранит конфиги в папке /etc/sysconfig/htb.
debian:~# mkdir -p /etc/sysconfig/htb
Создаем коневую дисциплину для интерфейса eth0 (интерфейс смотрит в локальную сеть, «на абонента»)
debian:~# touch /etc/sysconfig/htb/eth0
Указываем в какой класс будет попадать трафик не попавший ни в один из фильтров
debian:~# mcedit /etc/sysconfig/htb/eth0
DEFAULT=42

Создаем корневой класс
debian:~# touch /etc/sysconfig/htb/eth0-2.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2.root
RATE=100Mbit

Можно не указывать CEIL, тогда он автоматом будет равен RATE.

Создаем класс для не классифицированного трафика
debian:~# touch /etc/sysconfig/htb/eth0-2:42.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2:42.root
RATE=4Kbit


Создаем общий клиентский класс. Пускай его ID будет равно «D» и всего для абонентов мы выделим 10 Мбит.
debian:~# touch /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
debian:~# mcedit /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
RATE=10Mbit


Теперь можно заняться абонентами.
Что бы ограничить скорость скачивания в 512 КБит абоненту Василию нужно:
Создать класс для абонента Василия. Пускай ID клиентов будут начинаться с 255. Весьма полезно, если потребуется создать какой либо «системный» класс.
debian:~# touch /etc/sysconfig/htb/eth0-2:D:100.client_login
Интерфейс, идентификатор класса и родительские классы описываются в названии конфига.
Запись eth0-2:D:100.client_login означает что
eth0- Данный класс принадлежит к интерфейсу eth0
2 Корневой класс
D Родительский класс (В нашем случае общий клиентский класс)
100 Идентификатор класса клента
client_login Мнемоническая составляющая названия файла, несет смысловую нагрузку, в генерации классов не используется

Название файла генерируется таким образом:
1. Интерфейс к которому принадлежит класс.
2. Разделитель "-"(минус)
3. ID корневого класса
4. Разделитель ":"(двоеточие)
5. ID родительского класса
6. Разделитель ":"(двоеточие)
7. ID клиентского класса
8. Разделитель "."(точка)
9. Мнемоническая составляющая названия файла
Пункты 5 и 6 могут отсутствовать, в зависимость от выбранной Вами стратегии шейпирования.

debian:~# mcedit /etc/sysconfig/htb/eth0-2:D:100.client_login
RATE=512Kbit
LEAF=sfq
RULE=0.0.0.0/0,client_ip/32

По минимуму в конфиге должно быть 3 строки.
RATE — полоса предоставляемая абоненту.
LEAF — указатель на то, что класс конечный и для него необходимо создать создать дисциплину, в нашем случае sfq («псевдочестное» распределение полосы)
RULE — определяем что попадает в класс.Фильтровать можно по ип адресам, подсетям ип адресов, портам. Количество записей RULE может быть более одной.

Если нам нужно шейпировать трафик и натить на том же руотере, то вместо RULE нужно использовать MARK. Единственное придется маркировать пакеты.
Пример скрипта генерирующего конфиги для htbinit в конфигурации с NATом.
#!/bin/bash
#определяем переменные
declare -a rules
inif="eth0"
outif="eth1"
vlan="10"
workdir="/home/netup"
vardir="${workdir}/var"
htb_dir="/etc/sysconfig/htb"

mysql="/usr/bin/mysql -h host -u user -ppassword -D base"
ipt="/usr/local/sbin/iptables"
IPT_UNLIM="UNLIM_"${vlan}
utm_rules="${vardir}/htb_rules_htb"
htb_rules="${vardir}/htb_rules_utm"

#подготавливаем конфиги при первом запуске
[ -e ${htb_rules} ] || touch ${htb_rules}
#полная регенерация конфигов
if [ "${1}" = "zopa" ];then
echo ""> ${htb_rules};
fi

#получаем данные (id в шестнадцатиричной системе)
echo "select id,ip,mask,speed from view_shaper order by id;"|$mysql|sed '1d' > ${utm_rules};
#если достучались к базе и есть разница с текущим конфигом
exp="${utm_rules} ${htb_rules}"
[ -s ${utm_rules} ] && if [ -n "`diff ${exp}`" ]
then

#удаляем конфиги надобность в которых отпала
for i in `diff ${exp}|awk '{if (NF==5)print $2}'|sort -n|uniq`
do
inshaper=${htb_dir}/${inif}-2:${i}.rule_${i};
[ -e ${inshaper} ] && rm ${inshaper};
outshaper=${htb_dir}/${outif}-2:${i}.rule_${i};
[ -e ${outshaper} ] && rm ${outshaper};
done;

#формируем новые конфиги
rules=(`diff ${exp}|grep "<"|awk '{if (NF==5)print $2,$3,$4,$5}'`)
for i in `seq 1 4 ${#rules[@]}`;
do
id=${rules[$i-1]};
ip=${rules[$i]};
mask=${rules[$i+1]};
rate=${rules[$i+2]};

#Формируем названия конфигов
inshaper=${htb_dir}"/"${inif}-2:${id}.rule_${id};
outshaper=${htb_dir}/${outif}-2:${id}.rule_${id};

#Рассчитываем марки для пакетов
inmark="0x"`echo "obase=16; $((0x${id}*2))"|bc`
outmark="0x"`echo "obase=16; $((0x${id}*2+1))"|bc`

#Удаляем «старые» правила маркировки
${ipt} -t mangle -S ${IPT_UNLIM}|grep -w ${ip}|awk -v ipt=${ipt} '{$1="-D";system(ipt" -t mangle "$0)}';
#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e ${inshaper} ]; then
#echo "RULE="0.0.0.0/0,"${ip}"/"${mask}">> ${inshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip} -j MARK --set-mark ${inmark}
else
echo "RATE=4096bit" > ${inshaper}
echo "CEIL="$((${rate}*1024))"bit" >>${inshaper}
echo "LEAF=sfq" >> ${inshaper}
#echo "RULE=0.0.0.0/0,"${ip}"/"${mask}>> ${inshaper};
echo "MARK="${inmark}>> ${inshaper};
${ipt} -t mangle -A ${IPT_UNLIM} -d ${ip}/${mask} -j MARK --set-mark ${inmark}
fi

#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e $outshaper ]; then
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
else
echo "RATE=4096bit" > ${outshaper}
echo "CEIL="$((${rate}*1024))"bit" >> ${outshaper}
echo "LEAF=sfq" >> ${outshaper}
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
echo "MARK="${outmark}>> $outshaper;
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
fi
echo $ip
done;
cp ${exp}
[ -e /var/cache/htb.init ] && rm /var/cache/htb.init
/usr/local/sbin/htb.init restart
fi


Для конфигураций до 1000-1500 фильтров такой вариант подойдет. Для более крупных уже нужно использовать быстрые хэш фильтры, о ни и о приоретизации трафика я расскажу в следующей статье.

Источник: http://habrahabr.ru/blogs/sysadm/88624/

Повышение производительности netfilter, использование ipset

iptables — интерфейс к файрволу Linux (netfilter). При большом количестве правил iptables нагрузка может быть достаточно высокой и создавать проблемы. В этой заметке я постараюсь описать, что влияет на производительность iptables и как ее повысить.

Основная причина нагрузки


Для начала: из-за чего вообще возникает нагрузка при большом количестве правил? Из-за того, что каждому сетевому пакету, обрабатываемому ядром, приходится проходить сравнение по всему списку правил каждой цепочки. Приведу схему, которая отражает цепочки netfilter и порядок прохождения по ним пакетов:



На схеме видно через какие цепочки пройдет тот или иной пакет и можно оценить нагрузку. Возьмем одно простейшее правило:

-A INPUT -s 10.1.1.1/32 -p tcp --dport 25 -j DROP

Это правило указывает файрволлу отбрасывать все пакеты с IP-адреса 10.1.1.1 на порт 25 локальной машины. Таблицу (-t) я не указываю, поэтому будет использоваться дефолтная (-t filter), что нам и нужно. Понятно, что действие DROP выполняется далеко не всегда. Однако, сравнение IP-адреса источника будет проходить любой входящий на локальную машину пакет. А если таких правил тысяча?

Что делать?


Теперь подумаем, как можно ускорить работу файрволла. Первый ответ очевиден — сокращать количество правил. Но вряд ли удастся серьезно оптимизировать записи, особенно если они изначально составлялись грамотно. Где-то вместо правил на несколько IP-адресов можно написать одно правило на подсеть. Где-то вместо правил на несколько портов можно использовать -m multiport и --dports/--sports a,b,c (a,b,c — номера портов). И так далее.

Ветвление правил, дополнительные цепочки


А есть еще второй вариант — использование ветвлений правил. Суть его в том, что однотипные правила группируются в отдельную цепочку, а в основной цепочке остается одно правило, которое перенаправляет пакет в отдельную цепочку в зависимости от какого-то общего признака пакетов. Приведу пример. Имеются три правила:

-A INPUT -s 10.1.1.1/32 -p icmp -j ACCEPT
-A INPUT -s 10.1.1.2/32 -p icmp -j ACCEPT
-A INPUT -s 10.1.1.3/32 -p icmp -j ACCEPT


Что объединяет эти правила? Одинаковый протокол — icmp. Вот по этому признаку и стоит сгруппировать правила. Вообще в данном случае эффективнее использовать ipset, но об этом дальше. Для группировки необходимо создать новую цепочку, а затем создать правило, которое будет отправлять пакеты в эту цепочку.
Создать цепочку PROT_ICMP:

iptables -N PROT_ICMP

Определить правила в этой цепочке:

-A PROT_ICMP -s 10.1.1.1/32 -j ACCEPT
-A PROT_ICMP -s 10.1.1.2/32 -j ACCEPT
-A PROT_ICMP -s 10.1.1.3/32 -j ACCEPT


Как видите, протокол (-p) в этой цепочке мы уже не проверяем, т.к. отправлять в эту цепочку будем только ICMP пакеты. И наконец отправить все пакеты ICMP в эту цепочку:

-A INPUT -p icmp -g PROT_ICMP

Теперь входящий пакет, если он не ICMP, будет проходить лишь через одно правило вместо трех.

ipset


А теперь предположим следующую ситуацию:

-A INPUT -s 10.1.1.1/32 -j DROP
-A INPUT -s 10.1.1.2/32 -j DROP
-A INPUT -s 10.1.1.3/32 -j DROP


Несколько однотипных правил, но сгруппировать их или сделать дополнительную цепочку не представляется возможным. В таких случаях, когда необходимо делать проверку по большому количеству IP-адресов и/или портов, на помощь приходит ipset. ipset представляет из себя модуль ядра ip_set, ряд вспомогательных библиотек и утилиту ipset для задания параметров. Наверняка есть в репозиториях вашего дистрибутива, так что с установкой не должно быть проблем.
Используется следующим образом:
* Создается список:

ipset -N dropips iphash
dropips — название списка, iphash — тип списка. Типы списков можно посмотреть в man ipset, они есть на любой вкус — для работы с ip-адресами, подсетями, портами, mac-адресами. iphash служит для хранения IP-адресов, использование хэширования предотвращает добавление в список дублирующих IP-адресов.
* Добавляется IP-адрес в список:

ipset -A dropips 10.1.1.1

* Создается правило для использования списка:

iptables -A INPUT -m set --set dropips src -j DROP
-m set указывает на использование модуля ipset, --set dropips указывает список IP-адресов, src указывает на то, что сверять нужно только IP-источника. Таким образом, будут отбрасываться все пакеты с IP-адресов, указанных в списке dropips.

В статье я не стал описывать тюнинг сетевых параметров ядра, а сделал упор на рациональную организацию правил файрволла. Информации о тюнинге очень много можно найти в сети, это различные net.*mem*, в случае большого количества соединений и использования conntrack — параметры net.netfilter.nf_conntrack_max, net.netfilter.nf_conntrack*timeout и т.д.

Источник http://habrahabr.ru/blogs/sysadm/108691/

воскресенье, 16 мая 2010 г.

Срезаем пики с RRD графиков на примере Munin

Любой linux администратор наверняка наблюдал аномальные пики на RRD графиках. Пики появляются вследствие нарушения процесса сбора отслеживаемой величины и портят картину на графике. Это нормальное явление для RRD.

На графике трафика пики могут появится после перезапуска сетевого интерфейса или после перезагрузки сервера, что по сути одно и тоже. В обоих случаях процесс подсчета будет прерван из-за остановки устройства.

image



При появлении пиков необходимо удалить аномальные значения из базы RRD, чтобы график снова стал информативен. Это можно сделать с помощью утилиты rrdtool:
а) в ручную
rrdtool dump -> xml (находим и удаляем пики) -> rrdtool restore

б) или запустив скрипт removespikes.pl, в нем происходит тоже самое, но без вашего участия.

Я использую removespikes.pl. Процесс срезания пиков занимает не более 1 минуты.
На моих серверах установлен мониторинг Munin, поэтому примеры приведены с использованием этого мониторинга. Метод будет работать с любым мониторингов на основе RRD.

Срезаем пики с графиков eth0 трафика

## переключаем пользователя (подробнее см. «Подводные камни»)
su – munin

## утасновка скрипта removespikes.pl на сервере
wget oss.oetiker.ch/rrdtool/pub/contrib/removespikes-20080226-mkn.tar.gz
tar xvzf removespikes-20080226-mkn.tar.gz
rm removespikes-20080226-mkn.tar.gz

## Корректировка rrd файлов
## Указываем маску только тех файлов в которых необходимо срезать пики и не трогаем бекапы *.rrd.old при повторных запусках.
for f in `find ~/localdomain/ -name "localhost.localdomain-if_eth0*.rrd"`
do
## я использую removespikes.pl-orig.
## в removespikes.pl добавлен новый функционал и изменен метод среза пиков так, что можно запороть всю RRD базу. (подробнее см. «Подводные камни»)
~/removespikes/removespikes.pl-orig $f;
done;


После запуска скрипта вы должны увидеть что-то вроде
Chopping peak at
Chopping peak at


Графики Munin eth0 traffic после removespikes.pl

image


Подводные камни


Камень №1
Внимание: запускайте скрипт removespikes.pl под пользователем вашего мониторинга или проверяйте права на rdd файлы созданные скриптом, иначе сбор данных станет не возможен!

На графике выше отмечен разрыв, который произошел, вследствие того что я запускал removespikes.pl из под root. Исправленные rrd файлы были созданы с владельцем root и munin не мог записывать в них данные.

Камень №2
В архиве removespikes-20080226-mkn.tar.gz две модификации скрипта: оригинальная (removespikes.pl-orig) и с доп. функциями (removespikes.pl).

Корректность работы removespikes.pl-orig неоднократно мною проверена на разных серверах.

А вот запустив removespikes.pl я получил неожиданный результат. График как утюгом разгладило :(.

image

В скрипте есть параметр removespikes.pl
# Threshhold for cutting. Exponents above it will be chopped – срезаются все точки выше этого значения.
my $THRESH=10000;, что соответствует примерно 140Мбит/с.
Мой трафик был больше 140 и попал под это ограничение.
Если у вас обычные 100Мбит/с то это ограничение не окажет влияния на конечный результат.

Заключение

Скрипт автоматически создает бекап файлы с именами *.rrd.old, так что всегда можно вернутся к исходному состоянию. Главное правильно создать шаблон поиска файлов для прохода removespikes.pl в цикле for… in.

Источники

howto-remove-spikes-from-rrd-graphs
rrdtool doc

среда, 14 апреля 2010 г.

Шейпирование трафика в Linux. Часть 2

Вторая часть статьи об управлении трафиком в Linux. В статье приведены примеры приоретизации трафика (QoS) и рассказано об использовании hash таблиц при фильтрации трафика (fast hash tables), использование которых позволяет существенно увеличить производительность.
В первой части мы остановились на генерации конфигов средней сложность для htbinit. Сегодня мы поговорим о приоретизации трафика и использовании хэш таблиц в фильтрах. Я подразумеваю, что Вы прочитали первую часть статьи .
Предположим, что нам надоели замечания пользователей о высоком пинге, надоели постоянные детские вопли на форуме о том, что в counter-strike играть невозможно: «лаги страшные», или «у меня странички медленно грузятся, вконтакте открывался 10 минут», а писать что все замеры нужно производить при отключенном «торренте» уже нету сил.
Посему тто бы наша совесть была чиста, и мы могли не кривя душой сказать: «проблема на стороне провайдера предоставляющего данный сервис»(обозначить направление движения в сторону южного полюса) — озаботимся приоретизацией трафика.

Приоритеты выставим в таком порядке:
1. icmp
2. udp
3. tcp port 80
4. bulk traffic

Рассмотрим ограничение полосы на внутреннем интерфейсе, управлять будем «скоростью скачивания».
Напомню.
В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

Пример

#!/bin/bash

#"Очищаем" интерфейс eht1
/sbin/tc qdisc del dev eth1 root handle 1: htb default 15
#Создаем заново дисциплину и указываем дефолтный класс
/sbin/tc qdisc add dev eth1 root handle 1: htb default 15
#Создаем общий для клиентов класс
/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit

#Создаем корневой класс клиента
/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 512kbit ceil 512kbit

#Создаем 4 подкласса для каждого из видов трафика
/sbin/tc class add dev eth1 parent 1:10 classid 1:11 htb rate 1kbit ceil 512kbit prio 1
/sbin/tc class add dev eth1 parent 1:10 classid 1:12 htb rate 1kbit ceil 512kbit prio 2
/sbin/tc class add dev eth1 parent 1:10 classid 1:13 htb rate 1kbit ceil 512kbit prio 3
/sbin/tc class add dev eth1 parent 1:10 classid 1:14 htb rate 1kbit ceil 512kbit prio 4

#Создаем дисциплины шейпирования для конечных классов
/sbin/tc qdisc add dev eth1 parent 1:11 handle 11: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:12 handle 12: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:13 handle 13: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:14 handle 14: sfq perturb 10

Создаем 4 фильтра, для каждого из видов трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.


Думаю из примера видно, что для реализации приоретизиции трафика мы создали для каждого отдельный класс. Далее создаем фильтры, причем чем меньше prio, тем больше у трафика приоритет. Вообще правила обрабатываются согласно тому как их добавляли, в случае с приоритетами — первыми обслуживаются правила, имеющие наивысший приоритет.
Так же вы можете каждому из классов обзначить RATE равный одной четвертой от RATE корневого класса клиента, что бы уже наверняка.
Хочу обратить внимание, на то что нам пришлось создать 4 фильтра, для оного ип, а если ип 3-4 тысячи, то получим огромный линейный список правил — в итоге производительность упадет ниже плинтуса.
Что бы этого избежать воспользуемся «быстрыми» хэш таблицами.
О том, что такое хэш таблицы Вы можете посмотреть на Википедии.
Создадим 4 таблицы по 256 ячеек, каждая из таблиц будет оценивать один из октетов ип адреса.
И в конечном итоге, вместо поиска по всему списку, как это было бы в классическом варианте, мы уменьшим количество проверок и значительно снизим нагрузку.
Пример.
#Создаем корневой фильтр
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32
#Создаем 4 хеш таблицы для каждого октета
/sbin/tc filter add dev eth1 parent 1:0 handle 10: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 11: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 12: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 13: protocol ip u32 divisor 256
#Создаем фильтр направлящий весь трафик в хеш таблицу с ID 10
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:
#Добавляем правило в 10 хеш таблицу, если первый октет равен 192, то оправляем пакет в 11 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 10:c0: match ip dst 192.0.0.0/8  hashkey mask 0xff0000 at 16 link 11:
#Добавляем правило в 11 хеш таблицу, если второй октет равен 168, то оправляем пакет в 12 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 11:a8: match ip dst 192.168.0.0/16 hashkey mask 0xff00 at 16 link 12:
#Добавляем правило в 12 хеш таблицу, если третий октет равен 2, то оправляем пакет в 13 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 12:2: match ip dst 192.168.2.0/24 hashkey mask 0xff at 16 link 13:

#Добавляем правила в 13 хеш таблицу, оцениваем 4 октет и направляем в необходимый класс, в зависимости от вида трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 ht 13:2: match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.

Ниже приведен листинг скрипка генерирующего правила для tc включающие в себя приоретизацию и хеш фильтры.
Скрип полностью рабочий, думаю не составит большого труда модифицировать его под себя.
При переходе с линейных фильтров на хеш таблицы нагрузка упала почти в 4 раза.
#!/bin/bash
mysql="mysql -ppass -u user -h host"
#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внешних интерфейсов
echo "select ext_iface from system.shaper_view group by ext_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:";
}'

#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внутренних интерфейсов
echo "select int_iface from system.shaper_view group by int_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip src 0.0.0.0/0 hashkey mask 0xff000000 at 12 link 10:";
}'


#создаем классы, фильтры,дисциплины и при необходимости заполняем таблицы хешей
echo "select user_id,ip,speed,int_iface,ext_iface from system.shaper_view order by user_id;"|$mysql|sed 1d|
awk '
BEGIN{
buf=0;
class_id=255;
tc_class="/sbin/tc class add dev";
tc_qdisc="/sbin/tc qdisc add dev";
tc_filter="/sbin/tc filter add dev";
}
{
if(buf!=$1)
  {
  printf "%s%x%s\n", "# ",class_id," "class_id" "$2;
  client_speed=$3*128;
  printf "%s%x%s\n",tc_class" "$4" parent 1:1 classid 1:",++class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  printf "%s%x%s\n",tc_class" "$5" parent 1:1 classid 1:",class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  client_class=class_id;
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  }
split($2,ip,".");
if (ht_1[ip[1]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip dst "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 16 link 11:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip src "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 12 link 11:";
ht_1[ip[1]]=1;
}
if (ht_2[ip[2]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip dst "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 16 link 12:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip src "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 12 link 12:";
ht_2[ip[2]]=1;
}
if (ht_3[ip[3]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip dst "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 16 link 13:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip src "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 12 link 13:";
ht_3[ip[3]]=1;
}
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 17 0xff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 17 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 6 0xff match ip dport 80 0xffff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 flowid 1:",client_class
buf=$1;
}'

* This source code was highlighted with Source Code Highlighter.

Надеюсь данный опус помог Вам вникнуть в основы управления трафиком в Linux.

Оригинал:  http://habrahabr.ru/blogs/sysadm/89002/