Назад | Перейти на главную страницу

Многопутевая маршрутизация в ядрах post-3.6

Как вы все, наверное, знаете, кеш маршрута ipv4 был удален в серии ядер Linux 3.6, что серьезно повлияло на многопутевую маршрутизацию. Код маршрутизации IPv4 (в отличие от IPv6) выбирает следующий переход по циклической схеме, поэтому пакеты с заданного IP-адреса источника на данный IP-адрес назначения не всегда проходят через один и тот же следующий переход. До версии 3.6 кэш маршрутизации исправлял эту ситуацию, так как следующий однажды выбранный переход оставался в кэше, а все последующие пакеты из того же источника в то же место назначения проходили через этот следующий переход. Теперь следующий переход выбирается повторно для каждого пакета, что приводит к странным вещам: с двумя маршрутами по умолчанию с одинаковой стоимостью в таблице маршрутизации, каждый из которых указывает на одного интернет-провайдера, я даже не могу установить TCP-соединение, потому что начальный SYN и окончательный ACK проходят по разным маршрутам, и из-за NAT на каждом пути они прибывают в пункт назначения в виде пакетов из разных источников.

Есть ли относительно простой способ восстановить нормальное поведение многопутевой маршрутизации, чтобы следующий переход выбирался для каждого потока, а не для каждого пакета? Есть ли патчи, чтобы сделать выбор следующего перехода IPv4 на основе хэша, как это делается для IPv6? Или как вы все с этим справляетесь?

Если возможно, обновитесь до Linux Kernel> = 4.4 ....

Многопутевая маршрутизация на основе хеша была введена, что во многих отношениях лучше, чем поведение до версии 3.6. Он основан на потоке и принимает хеш-значения IP-адресов источника и назначения (порты игнорируются), чтобы обеспечить постоянство пути для отдельных подключений. Одним из недостатков является то, что я считаю, что до 3.6 были доступны различные алгоритмы / режимы конфигурации, но теперь вы получаете то, что вам дают! Вы можете использовать влияние на выбор пути с помощью weight хотя.

Если ты в моя ситуация тогда вы действительно хотите 3.6 >= behaviour < 4.4 но он больше не поддерживается.

Если вы обновитесь до> = 4.4, это должно сработать без всех остальных команд:

ip route add default  proto static scope global \
nexthop  via <gw_1> weight 1 \
nexthop  via <gw_2> weight 1

Альтернативно по устройству:

ip route add default  proto static scope global \
 nexthop  dev <if_1> weight 1 \
 nexthop  dev <if_2> weight 1

"Относительно легко" - сложный термин, но вы можете

  1. настроить таблицы маршрутизации для каждой из ваших ссылок - по одной таблице на ссылку, с одним шлюзом по умолчанию
  2. используйте netfilter для отметки одинаковых меток на всех пакетах одного потока
  3. использовать таблицу правил IP для маршрутизации пакетов через разные таблицы маршрутизации в зависимости от отметки
  4. используйте взвешенный маршрут с несколькими переходами, чтобы сбалансировать пакеты первого в сеансе через ваши шлюзы / ссылки.

Был обсуждение в списке рассылки netfilter по этой теме, где я краду объявления из:

1. Правила маршрутизации (RPDB и FIB)

ip route add default via <gw_1> lable link1
ip route add <net_gw1> dev <dev_gw1> table link1
ip route add default via <gw_2> table link2
ip route add <net_gw2> dev <dev_gw2> table link2

/sbin/ip route add default  proto static scope global table lb \
 nexthop  via <gw_1> weight 1 \
 nexthop  via <gw_2> weight 1

ip rule add prio 10 table main
ip rule add prio 20 from <net_gw1> table link1
ip rule add prio 21 from <net_gw2> table link2
ip rule add prio 50 fwmark 0x301 table link1
ip rule add prio 51 fwmark 0x302 table link2
ip rule add prio 100 table lb

ip route del default

2. Правила брандмауэра (с использованием ipset для принудительного включения "потокового" режима LB)

ipset create lb_link1 hash:ip,port,ip timeout 1200
ipset create lb_link2 hash:ip,port,ip timeout 1200

# Set firewall marks and ipset hash
iptables -t mangle -N SETMARK
iptables -t mangle -A SETMARK -o <if_gw1> -j MARK --set-mark 0x301
iptables -t mangle -A SETMARK -m mark --mark 0x301 -m set !
--match-set lb_link1 src,dstport,dst -j SET \
          --add-set lb_link1 src,dstport,dst
iptables -t mangle -A SETMARK -o <if_gw2> -j MARK --set-mark 0x302
iptables -t mangle -A SETMARK -m mark --mark 0x302 -m set !
--match-set lb_link2 src,dstport,dst -j SET \
          --add-set lb_link2 src,dstport,dst

# Reload marks by ipset hash
iptables -t mangle -N GETMARK
iptables -t mangle -A GETMARK -m mark --mark 0x0 -m set --match-set
lb_link1 src,dstport,dst -j MARK --set-mark 0x301
iptables -t mangle -A GETMARK -m mark --mark 0x0 -m set --match-set
lb_link2 src,dstport,dst -j MARK --set-mark 0x302

# Defining and save firewall marks
iptables -t mangle -N CNTRACK
iptables -t mangle -A CNTRACK -o <if_gw1> -m mark --mark 0x0 -j SETMARK
iptables -t mangle -A CNTRACK -o <if_gw2> -m mark --mark 0x0 -j SETMARK
iptables -t mangle -A CNTRACK -m mark ! --mark 0x0 -j CONNMARK --save-mark
iptables -t mangle -A POSTROUTING -j CNTRACK

# Reload all firewall marks
# Use OUTPUT chain for local access (Squid proxy, for example)
iptables -t mangle -A OUTPUT -m mark --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A OUTPUT -m mark --mark 0x0 -j GETMARK
iptables -t mangle -A PREROUTING -m mark --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark --mark 0x0 -j GETMARK

Возможно, вы захотите следить за обсуждением в списке рассылки netfilter некоторых вариантов вышеизложенного.