управление трафиком
Jun. 11th, 2010 04:11 pmДанная запись будет интересна не всем.
Камрад
alogic таки сподвиг меня рассказать об управлении входящим трафиком в linux.
Окей, начну издалека. Как вы все прекрасно знаете, не всегда имеющиеся каналы связи могут протолкнуть все посылаемые в них данные. Ну просто физически не могут, ширина канала-то, как правило, фиксирована,а население растет. Нет, кое-каким приложениям можно объяснить и указать явно, сколько килобит они могут принимать или отправлять в секунду. Самой программе управлять скоростью своих отправляемых данных проще некуда: не отправляй больше чем нужно и все. Управлять скоростью принимаемых данных тоже можно научиться: на уровне протокола TCP говоришь «ша, не так быстро» (уменьшаешь размер «скользящего окна» до нуля), потом разрешаешь — и в среднем принимаешь данные со скоростью не выше указанной.
Но «пастухам трафика» приходится работать не с разумными приложениями, а с каналами в целом. Как правильно разрулить пакеты, чьими пожертвовать, какие проталкивать вне очереди, какую вообще длину очереди выставить и по какому принципу эту очередь сокращать...
Цисководам проще, у них (нас) перебрасывать пакеты — основная задача, всё заточено под это дело, нужные рецепты нагугливаются в пять минут. «Всё уже украдено до нас.» С линуксом всё и сложнее, и проще. Сложнее в том плане, что готовые рецепты помогают только тем, кто более-менее разобрался, как вся эта мутотень работает, и проще в том плане, что линукс он ведь везде одинаковый. И на собственном компе, и на коробочке-шлюзе за $40, и на провайдерском мега-раутере можно тонко настроить приоритеты и выбранные полосы для разных классов трафика, не надеясь на лимиты в приложениях.
Ладно, слишком длинное вступление. Под катом треп про управление только входящим трафиком, ingress policing. Рецепты для управления исходящим стоит искать на Linux Advanced Routing and Traffic Control, эта магия уже общеизвестна.
Начнем с того, что обычно входящим трафиком управлять не нужно. Зачем с ним что-то делать, если он уже пришел? Передай его приложению, и дело с концом. Иногда приходится от чего-то закрываться, но это можно сделать посредством правил Netfilter в filter:INPUT.
Самое узкое место у абсолютного числа пользователей — линк от провайдера. И никакого контроля над данными, отправляемыми к вам провайдером, у вас нет. Максимум, что можно сделать, — избавиться от очереди пакетов на стороне провайдера, перенести эту очередь к себе. В wondershaper от LARTC для этого используется ingress-фильтр, который тупо отбрасывает все пакеты свыше 0.9 * $DOWNLINK, то есть чуть меньше гарантированной полосы от провайдера. Это уменьшает задержку для приоритетного трафика типа icmp и syn/ack.
Бывают случаи, когда на ingress все-таки требуется повесить фильтры на несколько разных классов. Например, когда провайдер гарантирует такую-то скорость из внешнего интернета, и намного большую — из локальных сетей, для p2p-трафика. Продвинутый линуксоид в этом случае использует промежуточное сетевое устройсто IFB. Оно теперь вместо IMQ, что-то вроде буфера-отстойника для пакетов, на который можно повесить такие же шейперы, как и на исходящий трафик. Довольно умное решение, можно использовать давно проверенные qdisc для входящего трафика, те же самые HTB/TBF/ESFQ. Неплохо также бывает завернуть трафик, приходящий с нескольких интерфейсов, в одно устройство IFB и работать уже с общим трафиком.

Однако это все решения для пользователя. Ну а что делать если ты сам провайдер? Как ограничить трафик от клиента, если твой BRAS раздает инет в 300-500 пользовательских PPP-соединений? К клиенту ограничить проблем нет: HTB на его ppp-интерфейс, класс для инета, класс для p2p. Никаких хитростей, обычные модули ipset+mark. А вот с восходящим трафиком пришлось городить сложности: нельзя просто дропать всё что выше лимита, как он своё p2p раздавать будет в локалку соседям?
Устройств IFB не напасешься, на каждый-то ppp создавать. Создавать u32-фильтр на каждую подсеть p2p замучаешься, их сотни в пиринге. Ограничивать полосу от клиента уже на аплинке BRASа тоже не выход - клиентов тысячи, постоянно перестраивать дерево фильтров накладно. Остается работать с интерфейсом клиента. Выход нашелся такой: не дропать лишнее на ingress, а только помечать. Дропать уже в iptables после того, как выяснилось что нужный пакет идет не в p2p:
Есть, конечно, опасность, что гарантированная восходящая полоса забьется p2p трафиком, и инета клиенту достанется меньше, но тут уж забота клиента — более важный трафик вперед пускать, пусть правильно настроит свои output qdisc :-) А для p2p-любивых неумех можно вставить вперед дополнительный ingress-фильтр, отдельную гарантированную полосу под маленькие пакеты типа DNS и SYN/ACK. Что-то вроде:
tc filter add dev $PPP parent ffff: protocol ip prio 10 u32 магическая проверка на размер пакета police rate $EXTRARATE burst 10k continue flowid :1
Внимание! При переходе на xtables в lenny поломали action ipt, пришлось взять из etch /usr/lib/tc/* и /lib/iptables/*
Надеюсь это кому-нибудь пригодится.
Камрад
Окей, начну издалека. Как вы все прекрасно знаете, не всегда имеющиеся каналы связи могут протолкнуть все посылаемые в них данные. Ну просто физически не могут, ширина канала-то, как правило, фиксирована,
Но «пастухам трафика» приходится работать не с разумными приложениями, а с каналами в целом. Как правильно разрулить пакеты, чьими пожертвовать, какие проталкивать вне очереди, какую вообще длину очереди выставить и по какому принципу эту очередь сокращать...
Цисководам проще, у них (нас) перебрасывать пакеты — основная задача, всё заточено под это дело, нужные рецепты нагугливаются в пять минут. «Всё уже украдено до нас.» С линуксом всё и сложнее, и проще. Сложнее в том плане, что готовые рецепты помогают только тем, кто более-менее разобрался, как вся эта мутотень работает, и проще в том плане, что линукс он ведь везде одинаковый. И на собственном компе, и на коробочке-шлюзе за $40, и на провайдерском мега-раутере можно тонко настроить приоритеты и выбранные полосы для разных классов трафика, не надеясь на лимиты в приложениях.
Ладно, слишком длинное вступление. Под катом треп про управление только входящим трафиком, ingress policing. Рецепты для управления исходящим стоит искать на Linux Advanced Routing and Traffic Control, эта магия уже общеизвестна.
Начнем с того, что обычно входящим трафиком управлять не нужно. Зачем с ним что-то делать, если он уже пришел? Передай его приложению, и дело с концом. Иногда приходится от чего-то закрываться, но это можно сделать посредством правил Netfilter в filter:INPUT.
Самое узкое место у абсолютного числа пользователей — линк от провайдера. И никакого контроля над данными, отправляемыми к вам провайдером, у вас нет. Максимум, что можно сделать, — избавиться от очереди пакетов на стороне провайдера, перенести эту очередь к себе. В wondershaper от LARTC для этого используется ingress-фильтр, который тупо отбрасывает все пакеты свыше 0.9 * $DOWNLINK, то есть чуть меньше гарантированной полосы от провайдера. Это уменьшает задержку для приоритетного трафика типа icmp и syn/ack.
Бывают случаи, когда на ingress все-таки требуется повесить фильтры на несколько разных классов. Например, когда провайдер гарантирует такую-то скорость из внешнего интернета, и намного большую — из локальных сетей, для p2p-трафика. Продвинутый линуксоид в этом случае использует промежуточное сетевое устройсто IFB. Оно теперь вместо IMQ, что-то вроде буфера-отстойника для пакетов, на который можно повесить такие же шейперы, как и на исходящий трафик. Довольно умное решение, можно использовать давно проверенные qdisc для входящего трафика, те же самые HTB/TBF/ESFQ. Неплохо также бывает завернуть трафик, приходящий с нескольких интерфейсов, в одно устройство IFB и работать уже с общим трафиком.

Однако это все решения для пользователя. Ну а что делать если ты сам провайдер? Как ограничить трафик от клиента, если твой BRAS раздает инет в 300-500 пользовательских PPP-соединений? К клиенту ограничить проблем нет: HTB на его ppp-интерфейс, класс для инета, класс для p2p. Никаких хитростей, обычные модули ipset+mark. А вот с восходящим трафиком пришлось городить сложности: нельзя просто дропать всё что выше лимита, как он своё p2p раздавать будет в локалку соседям?
Устройств IFB не напасешься, на каждый-то ppp создавать. Создавать u32-фильтр на каждую подсеть p2p замучаешься, их сотни в пиринге. Ограничивать полосу от клиента уже на аплинке BRASа тоже не выход - клиентов тысячи, постоянно перестраивать дерево фильтров накладно. Остается работать с интерфейсом клиента. Выход нашелся такой: не дропать лишнее на ingress, а только помечать. Дропать уже в iptables после того, как выяснилось что нужный пакет идет не в p2p:
- на устройство вешается ingress qdisc: tc qdisc add dev $PPP handle ffff: ingress
- создается фильтр с фиксированной полосой: tc filter add dev $PPP parent ffff: protocol ip prio 10 u32 match ip dst 0.0.0.0/0 police rate $INETRATE burst $BURST continue flowid :1
Обратите внимание, что action для превышения полосы — continue, а не drop, как обычно - всё, что выше лимита, помечается через iptables: tc filter add dev $PPP parent ffff: protocol ip prio 10 u32 match u32 0 0 flowid :1 action ipt -j MARK --set-mark 0x23
- уже в filter/FORWARD все помеченные пакеты проверяются на принадлежность к p2p через ipset:
iptables -A FORWARD -m mark --mark 0x23 -j checkp2p iptables -A checkp2p -m ipset --set p2pnets dst -j ACCEPT (или RETURN) iptables -A checkp2p -j DROP
- PROFIT!!!
Есть, конечно, опасность, что гарантированная восходящая полоса забьется p2p трафиком, и инета клиенту достанется меньше, но тут уж забота клиента — более важный трафик вперед пускать, пусть правильно настроит свои output qdisc :-) А для p2p-любивых неумех можно вставить вперед дополнительный ingress-фильтр, отдельную гарантированную полосу под маленькие пакеты типа DNS и SYN/ACK. Что-то вроде:
tc filter add dev $PPP parent ffff: protocol ip prio 10 u32 магическая проверка на размер пакета police rate $EXTRARATE burst 10k continue flowid :1
Внимание! При переходе на xtables в lenny поломали action ipt, пришлось взять из etch /usr/lib/tc/* и /lib/iptables/*
Надеюсь это кому-нибудь пригодится.
no subject
Date: 2010-06-14 03:03 pm (UTC)no subject
Date: 2010-06-15 07:35 am (UTC)* создаем устройство IFB, ставим редирект с ingress на IFB
* ставим примерно такие классы HTB на IFB:
1) корневой: 0.9 от ширины downlink, rate=ceil, остальные классы - внутри него
2) приоритетный: rate 0.9 от скорости корневого, ceil==корневому, в него сливаем dst port ssh + src port ssh (возможно придется смотреть на поле TOS, у scp и у интерактивной сессии они разные), сюда же можно завернуть ответы DNS и SYN/ACK от удаленных хостов
3) собственный: rate 0.5 от корневого, ceil==корневому, под хост "я"
4) "остальной": rate 0.49 от корневого, ceil==коневому, под всех остальных
5) остаточный: 0.01 от корневого, ceil==0.9 корневого (или меньше), под торренты
Основная проблема - отличить на этапе выборки из IFB, куда предназначаются пакеты. Насколько я помню, на этом этапе еще неизвестно, какому из внутренних IP предназначаются пакеты, это как бы еще ingress, не де-маскированный
Торренты отличить можно легко, у них диапазон фиксированный, ssh тоже, а вот хост "я" от остальных - не представляю как, без внутреннего-то ip
Исходящий в ppp трафик можно резать на те же самые классы, только root неограниченный, без зарезания полосы на 90% от номинала. Тут намного легче, еще в mangle:FORWARD можно пометить какому классу какой пакет достанется.
Боюсь что торренты все равно забьют входящий канал, еще на стороне провайдера, тут без активного "кондиционирования" путем манипулирования искусственной задержкой для ACK-пакетов (от вас к пирам) не обойтись. Такое коммерческие хрени делают, я магию такого уровня еще не пробовал.
no subject
Date: 2010-11-09 06:49 pm (UTC)Если простыми сравнениями - оно-то да, при десятке подсетей, при нескольких сотнях - уже будут проблемы, при тысячах - все накроется медным тазом ввиду никакой производительности. Маркировать через iptables увы не выйдет (не IMQ ведь). Кто-то на наге вроде патч для tc для поддержки ipset собирался выкладывать - но пока что не выложил.
P.S. Предстоит подобная задача - разве что без ната, и шейпить в итоге можно будет на eth0...
no subject
Date: 2010-11-09 11:47 pm (UTC)