Ограничение полосы пропускания для исходящего/входящего трафика с задержкой для конкретного порта с использованием TC

Вопрос или проблема

Я пытаюсь ограничить входящую и исходящую пропускную способность с задержкой через определенный порт, используя TC, но не могу заставить это работать на 100%. Я не уверен, правильно ли я это сделал.

Когда я пингую Google, задержка увеличивается. Я использовал iperf для тестирования пропускной способности через порт 5001. Ограничение пропускной способности, похоже, работает на клиенте, где я применил указанные ниже настройки (клиент как iperf -s, входящий), однако, если я использую этот клиент (исходящий) для подключения к другому, пропускная способность ограничивается 1–2 мбит, вместо ожидаемых 5 мбит.

То, что я хотел бы, например, установить задержку на 100 мс, исходящую/входящую пропускную способность ограничить до 5 мбит, и применить все эти правила к порту 5001. Я на правильном пути или неправильно понимаю концепцию tc?

Ip link add name ifb0 type ifb 2>/dev/null || :
Ip link set dev ifb0 up
Tc qdisc add dev ifb0 root handle 1: htb
Tc class dev ifb0 parent 1: classid 1:20 htb rate 5mbit
Tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
Tc filter add dev ifb0 parent 1: protocol ip prio 1 basic match ‘cmp(u16 at 2 layer transport eq 5001)’ flowid 1:20
Tc qdisc add dev ens192 root netem delay 200ms
Tc qdisc add dev ens192 ingress
Tc filter add add dev ens192 ingress protocol ip basic match ‘cmp(u16 at 2 layer transport eq 5001)’ action mirred egress redirect dev ifb0

Вот сценарий, который я использовал, когда у моего интернет-провайдера были проблемы с буферизацией несколько лет назад. Его необходимо запускать как root для start и stop, но вы можете запускать status без root.

#!/bin/bash
# Скрипт управления трафиком (AQM, fq_codel+tbf)
# Автор: Mikko Rantalainen <[email protected]>
# Лицензия: MIT (X11)
# Использование:
#   21/0.8 Mbps соединение (ADSL2): DOWNLINK_RATE=21.7Mbit UPLINK_RATE=0.8Mbit TBF_LATENCY=500ms DOWNLINK_BURST=1500 UPLINK_BURST=1500 bin/traffic-shaping start
#   100/100 Mbps соединение: ./traffic-shaping
#   1/1 GBps соединение: DOWNLINK_RATE=1Gbit UPLINK_RATE=1Gbit TBF_LATENCY=15ms bin/traffic-shaping start
# Обратите внимание, что использование низкой TBF_LATENCY требует мощного процессора.
#
# См. также: https://www.bufferbloat.net/projects/codel/wiki/Best_practices_for_benchmarking_Codel_and_FQ_Codel/
# См. также: http://www.jfcarter.net/~jimc/documents/voip-qos-1609.html
# TODO: man 7 tc-hfcs (вместо tbf)
# TODO: попробуйте ограничить пропускную способность, используя только fq_codel (без tbf) - https://gist.github.com/eqhmcow/939373/8d2e8ad745a7e0a8ddb21abde42538034c2ea65b
#   
set -e # прервать, если команда возвращает не нулевой статус (ошибка)
#set -x # подробное выполнение

# Примечание: ip route иногда выводит несколько строк с префиксом "default", используйте первую
DEV="${DEV:=$(ip route | grep "^default " | head -n1 | grep -Po "(?<=dev )[^ ]+")}"

# входящие:
DOWNLINK_RATE="${DOWNLINK_RATE:=103000kbit}" # или, например, "21.5Mbit"
# исходящие:
UPLINK_RATE="${UPLINK_RATE:=102000kbit}"

CODEL_INTERVAL="${CODEL_INTERVAL:=100ms}" # обычно 100ms, высокоскоростные соединения с низкой задержкой могут требовать меньших значений
CODEL_TARGET="${CODEL_TARGET:=5ms}" # единица "us" также доступна, обычно 5%-10% от CODEL_INTERVAL
CODEL_LIMIT="${CODEL_LIMIT:=1001}" # уменьшите, чтобы снизить задержку, слишком низкие значения будут ограничивать пропускную способность
CODEL_FLOWS="${CODEL_FLOWS:=1024}"

# установите всплеск как можно выше, не вызывая потерь пакетов в начале соединений
DOWNLINK_BURST="${DOWNLINK_BURST:=8000}"
UPLINK_BURST="${UPLINK_BURST:=55000}"

TBF_LATENCY="${TBF_LATENCY:=10ms}" # установите на более низкую задержку, чтобы улучшить контроль над ограничением пропускной способности, байты UPLINK_BURST должны быть отправлены за это время


IFB="$DEV.in" # логически это должно быть $DEV.ingress, но максимальный лимит может быть превышен (например, dev = enp0s29u1u6 -> enp0s29u1u6.ingress слишком длинное)

INITCWND="${INITCWND:=15}" # начальное окно заторов, уменьшите, если наблюдается потеря пакетов
INITRWND="${INITRWND:=30}" # начальное окно приема (рекламируемое от клиента к серверам), может быть довольно высоким, если у вас много пропускной способности (Windows и OS X имеют это около 40)

# См. также: https://www.cdnplanet.com/blog/tune-tcp-initcwnd-for-optimum-performance/

# См. также: https://www.acc.umu.se/~maswan/linux-netperf.txt

# См. также: http://intronetworks.cs.luc.edu/1/html/newtcps.html

# См. также: https://www.ietf.org/proceedings/84/slides/slides-84-iccrg-1.pdf

configure_shaping()
{
    # ИСХОДЯЩИЙ (исходящий трафик, "загрузки"):

    # настройка ограничения пропускной способности:
    tc qdisc add dev "$DEV" root handle 1: tbf rate "$UPLINK_RATE" burst "$UPLINK_BURST" latency "$TBF_LATENCY"

    # настройка fq_codel для формирования пропускной способности
    tc qdisc add dev "$DEV" parent 1: fq_codel quantum 300 limit "$CODEL_LIMIT" target "$CODEL_TARGET" interval "$CODEL_INTERVAL" flows "$CODEL_FLOWS" noecn

    # ВХОДЯЩИЙ (входящий трафик, "загрузки"):

    ip link show ifb0 >&/dev/null && HAD_IFB0=1 || HAD_IFB0=0
    ip link show ifb1 >&/dev/null && HAD_IFB1=1 || HAD_IFB1=0

    # настройка ограничения пропускной способности (входящее ограничение требует IFB или Intermediate Functional Block, см. https://wiki.linuxfoundation.org/networking/ifb):
    tc qdisc add dev "$DEV" handle ffff: ingress
    ip link add name "$IFB" type ifb
    tc qdisc add dev "$IFB" root handle 1: tbf rate "$DOWNLINK_RATE" burst "$DOWNLINK_BURST" latency "$TBF_LATENCY"

    # настройка fq_codel для формирования пропускной способности
    tc qdisc add dev "$IFB" parent 1: fq_codel quantum 300 limit "$CODEL_LIMIT" target "$CODEL_TARGET" interval "$CODEL_INTERVAL" flows "$CODEL_FLOWS" ecn
    ip link set dev "$IFB" up

    # подключение фильтрации входящего трафика к фактическому WAN устройству
    tc filter add dev "$DEV" parent ffff: protocol all prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev "$IFB"

    # Настройка initcwnd и initrwnd
    # Обратите внимание, что "ip route" иногда выводит несколько строк с префиксом "default" — мы всегда будем использовать первую
    ip route change $(ip route | grep ^default | head -n1) initcwnd "$INITCWND" initrwnd "$INITRWND"

    ## настройка алгоритма управления заторами CDG
    ##modprobe tcp_cdg && echo cdg > /proc/sys/net/ipv4/tcp_congestion_control
    
    # кубический алгоритм, кажется, в целом лучше с AQM, давайте настроим его
    echo cubic > /proc/sys/net/ipv4/tcp_congestion_control || true
    echo 13 > /sys/module/tcp_cubic/parameters/hystart_low_window

    echo 0 > /proc/sys/net/ipv4/tcp_slow_start_after_idle
    
    # TODO: попробуйте modprobe tcp_westwood
    
    # Удалить все отключения, которые увеличивают задержку (обратите внимание, что если у вас недостаточно мощности процессора, это может снизить максимальную пропускную способность!)
    # Обратите внимание, что из-за ошибок ethtool названия, используемые здесь, не совпадают с ethtool --show-offload, смотрите 'man ethtool' для подробностей!
    # игнорировать возможные ошибки и продолжать
    ethtool --offload "$DEV" gso off || true
    ethtool --offload "$DEV" gro off || true
    ethtool --offload "$DEV" tx off || true
    ethtool --offload "$DEV" rx off || true
    ethtool --offload "$DEV" rxvlan off || true
    ethtool --offload "$DEV" txvlan off || true
    
    # очистить поврежденные ip links add ... type ifb, иногда создавая дополнительные ifb links (называемые "ifb0" и "ifb1")
    test "$HAD_IFB0" = "0" && ip link show ifb0 >&/dev/null && ip link del ifb0
    test "$HAD_IFB1" = "0" && ip link show ifb1 >&/dev/null && ip link del ifb1
}

remove_shaping()
{
#set -x
    tc qdisc list | grep -q "ingress" && tc qdisc del dev "$DEV" ingress || true
    # Примечание: мы должны избегать удаления корневого qdisc, если данный ядро по умолчанию использует fq_codel, "qdisc list" выведет "fq_codel 0:" для корневого qdisc, поэтому мы ищем что-то другое
    tc qdisc list | grep -q "fq_codel [1-9]" && tc qdisc del dev "$DEV" root || true
    ip link show | grep -q "$IFB" && ip link del "$IFB" || true

    # настройка алгоритма управления заторами CDG
    modprobe tcp_cdg && echo cdg > /proc/sys/net/ipv4/tcp_congestion_control || true
#set +x
}

status()
{
        echo "─── Конфигурация дисциплины очереди: ──────────────────"
        tc qdisc list
        echo "   ПОДСКАЗКА: используйте, например, 'sudo tc qdisc del dev $DEV ingress', чтобы удалить фильтрацию входящего трафика"
        echo "   ПОДСКАЗКА: используйте, например, 'sudo tc qdisc del dev $DEV root', чтобы удалить фильтрацию исходящего трафика"
        echo "─── ip link show: ────────────────────────────────────"
        ip link show
        echo "   ПОДСКАЗКА: используйте, например, 'sudo ip link del $IFB', чтобы удалить устройство входящего трафика"
}

color_status()
{
    status | grep --color=auto -E "^|$DEV|$IFB|rate [^ ]+"
}

# Обработка параметров

ACTION="$1"
shift || true

while [ ! -z "$1" ]
do
    case "$1" in
        -v|--verbose)
            echo "Устройство: $DEV"
            echo "Скорость загрузки (входящая): $DOWNLINK_RATE"
            echo "Скорость выгрузки (исходящая): $UPLINK_RATE"
            set -x
            ;;
        *)
            if [ ! -z "$2" ]; then
                echo "Неизвестный параметр: '$2'" 1>&2
                exit 1
            fi
            ;;
    esac
    shift || true
done

case "$ACTION" in
    start)
        remove_shaping
        configure_shaping
        ;;
    stop)
        remove_shaping
        ;;
    status)
        color_status
        ;;
    restart)
        remove_shaping
        configure_shaping
        ;;
    *)
        echo "Неизвестное действие: $1" 1>&2
        echo "Использование: $0 <start|stop|restart|status> [--verbose|-v]" 1>&2
        exit 1
esac

Чтобы использовать этот сценарий, сохраните его, например, как traffic-shaping и выполните chmod a+x traffic-shaping, чтобы включить бит выполнения. Затем вы можете либо изменить значения по умолчанию в файле, либо использовать переменные окружения для настройки сценария. Например, если у вас соединение 100/100 Mbps, вы можете выполнить

DOWNLINK_RATE=95Mbit UPLINK_RATE=95Mbit TBF_LATENCY=25ms ./traffic-shaping start

как root. И чтобы восстановить настройки по умолчанию, выполните

./traffic-shaping stop

и чтобы показать текущее состояние, выполните

./traffic-shaping stop

Обратите внимание, что указанные выше настройки не являются постоянными, поэтому вам нужно будет повторно запускать сценарий после каждой перезагрузки. Я использовал это с Ubuntu low-latency (PREEMPT) ядром Linux и TBF_LATENCY=10ms, поэтому я не знаю, какую задержку можно ожидать с generic ядром. Вам, возможно, придется установить TBF_LATENCY=40ms, если вы запускаете его с generic ядром. Если вы запустите start без каких-либо установленных переменных окружения, вы получите мою собственную конфигурацию, которую я использовал для соединения 100/100 Mbps FTTH с low-latency ядром. Если у вас соединение менее 20 Mbps, вам, вероятно, нужно установить DOWNLINK_BURST=1500 UPLINK_BURST=1500, чтобы избежать появления резких всплесков в начале новых соединений, которые могут вызвать потерю пакетов. Для медленной выгрузки вам также может потребоваться уменьшить INITCWND (по умолчанию 15), если вы страдаете от потери пакетов / высокой задержки в начале соединения с быстрыми серверами (например, трафик веб-браузеров). Значения в диапазоне 7-10 должны быть приемлемыми для 1 Mbps соединения.

Ответ или решение

Для настройки ограничения пропускной способности и задержки с использованием tc (Traffic Control) в Linux, с целью управления трафиком через определённый порт, вам необходимо правильно настроить правила и очереди. Давайте разберём ваш случай более подробно.

Шаг 1: Настройка интерфейса IFB

Следуйте следующим шагам для создания и настройки интерфейса ifb (Intermediate Functional Block), который будет использоваться для ограничения входящего трафика.

ip link add name ifb0 type ifb
ip link set dev ifb0 up

Шаг 2: Ограничение пропускной способности и задержки

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

# Ограничение исходящего трафика
tc qdisc add dev ens192 root handle 1: htb default 30
tc class add dev ens192 parent 1: classid 1:20 htb rate 5mbit
tc qdisc add dev ens192 parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev ens192 root netem delay 100ms

# Настройка фильтра для исходящего трафика
tc filter add dev ens192 protocol ip parent 1: pref 1 basic match 'cmp(u16 at 2 layer transport eq 5001)' flowid 1:20

# Настройка входящего трафика
tc qdisc add dev ens192 ingress
tc filter add dev ens192 parent ffff: protocol ip basic match 'cmp(u16 at 2 layer transport eq 5001)' action mirred egress redirect dev ifb0

# Ограничение входящего трафика
tc qdisc add dev ifb0 root handle 1: htb default 30
tc class add dev ifb0 parent 1: classid 1:20 htb rate 5mbit
tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10

Шаг 3: Проверка и диагностика

После выполнения вышеуказанных команд вы можете проверить настройки с помощью команды:

tc -s qdisc show dev ens192
tc -s qdisc show dev ifb0

Эти команды позволят вам увидеть текущие настройки и статистику использования полосы пропускания.

Объяснение кода

  1. Создание и настройка IFB: Мы создаём интерфейс ifb0 и устанавливаем его в активное состояние.

  2. Параметры для исходящего трафика: Используем htb (Hierarchical Token Bucket) для классификации пакетов по классу с максимальной пропускной способностью 5 Mbit. Для имитации задержки добавляем netem.

  3. Фильтры: Создаём фильтр на исходящий и входящий трафик, который будет направлять пакеты, уходящие и приходящие на порт 5001, в соответствующие очереди.

Заключение

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

Используйте такие инструменты, как iperf, для мониторинга похоже на ожидаемое поведение вашей сети, проверяя, что пропускная способность и задержка настроены правильно.

Оцените материал
Добавить комментарий

Капча загружается...