Enrutamiento de múltiples rutas en núcleos posteriores a 3.6

16

Como probablemente todos sepan, la caché de ruta ipv4 se eliminó en la serie 3.6 del kernel de Linux, lo que tuvo un grave impacto en el enrutamiento de múltiples rutas. El código de enrutamiento IPv4 (a diferencia del IPv6 uno) selecciona el siguiente salto de forma circular, por lo que los paquetes de la IP de origen dada a la IP de destino dada no siempre pasan por el mismo siguiente salto. Antes de 3.6, el caché de enrutamiento estaba corrigiendo esa situación, ya que el siguiente salto, una vez seleccionado, permanecía en el caché, y todos los paquetes adicionales del mismo origen al mismo destino pasaban por el siguiente salto. Ahora el siguiente salto se vuelve a seleccionar para cada paquete, lo que conduce a cosas extrañas: con 2 rutas predeterminadas de igual costo en la tabla de enrutamiento, cada una apuntando a un proveedor de Internet, ni siquiera puedo establecer una conexión TCP, porque SYN inicial y ACK final ir por diferentes rutas,

¿Hay alguna forma relativamente fácil de restaurar el comportamiento normal del enrutamiento de múltiples rutas, de modo que el siguiente salto se seleccione por flujo en lugar de por paquete? ¿Hay parches para hacer la selección de próximo salto de IPv4 basada en hash, como lo es para IPv6? ¿O cómo lidian con eso?

Eugene
fuente
¿Tiene una configuración de "acceso dividido" similar a esta aquí: lartc.org/howto/lartc.rpdb.multiple-links.html ? Si es así, ¿cómo se ve su conjunto de reglas y rutas?
the-wabbit
intente usar "ip route get 173.194.112.247" varias veces y publique la salida
c4f4t0r
Gracias por la sabrosa pregunta. :) en primer lugar, no nos diste un ejemplo. Entonces, supongo que tienes algo como ¿ ip ro add 8.8.8.8/32 nexthop via 1.2.3.4 nexthop via 1.2.3.5es esa suposición correcta?
poige
Sí, eso es correcto, pero por lo general es ruta IP agregue 0.0.0.0/0 con múltiples saltos siguientes.
Eugene
el-wabbit, sí, exactamente así. "proveedor 1" y "proveedor2" en mi caso son enrutadores fronterizos conectados a mi red interna y a la red del proveedor, y tienen origen NAT. En mi enrutador interno, solo tengo una puerta de enlace predeterminada con 2 saltos que apuntan al proveedor1 y al proveedor2, no hay otras rutas. Las reglas de firewall solo permiten algunos servicios (como HTTP) para máquinas cliente y bloquean todo lo demás.
Eugene

Respuestas:

8

Si es posible, actualice a Linux Kernel> = 4.4 ....

Se ha introducido el enrutamiento multirruta basado en hash , que en muchos aspectos es mejor que el comportamiento anterior a 3.6. Está basado en el flujo, tomando un hash de las IP de origen y destino (los puertos se ignoran) para mantener la ruta estable para conexiones individuales. Una desventaja es que creo que había varios algoritmos / modos de configuración disponibles antes de 3.6, ¡pero ahora obtienes lo que te dan !. Sin weightembargo, puede usar afectar la elección de la ruta .

Si estás en mi situación, entonces realmente quieres el 3.6 >= behaviour < 4.4pero ya no es compatible.

Si actualiza a> = 4.4, esto debería funcionar, sin todos los otros comandos:

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

Alternativamente por dispositivo:

ip route add default  proto static scope global \
 nexthop  dev <if_1> weight 1 \
 nexthop  dev <if_2> weight 1
bao7uo
fuente
Para cualquiera que venga a esta solución, eche un vistazo también a: net.ipv4.fib_multipath_use_neigh para deshabilitar automáticamente el nexthop / gateway "descartado".
Rostislav Kandilarov
6

"Relativamente fácil" es un término difícil, pero podría

  1. configure tablas de enrutamiento para cada uno de sus enlaces: una tabla por enlace, con una única puerta de enlace predeterminada
  2. use netfilter para estampar marcas idénticas en todos los paquetes de una sola secuencia
  3. use la tabla de reglas ip para enrutar los paquetes a través de diferentes tablas de enrutamiento dependiendo de la marca
  4. use una ruta ponderada multi-nexthop para equilibrar los primeros paquetes de una sesión sobre sus puertas de enlace / enlaces.

Ha habido una discusión en la lista de correo de netfilter sobre este tema donde estoy robando los listados de:

1. Reglas de enrutamiento (RPDB y 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. Reglas de firewall (usando ipset para forzar un modo LB de "flujo")

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

Es posible que desee seguir la discusión de la lista de correo netfilter para algunas variaciones de lo anterior.

el wabbit
fuente
No estoy seguro, pero podría ser más fácil de u32obtener parámetros importantes hash y luego "etiqueta" asignado a ip rule's
poige
Gracias, pero parece una solución bastante compleja. Lo que no entiendo es qué pieza es responsable de "estampar marcas idénticas en todos los paquetes de una sola secuencia". ¿Cómo funciona esa magia de ipset? Pensé que ipset es solo un conjunto de IP en particular que está en hash y puede coincidir con las reglas.
Eugene
Tiene razón ipset: solo se trata de crear conjuntos que se completan usando --add-sety se combinan con el uso --match-set, pero esto es principalmente para las conexiones en estado NUEVO. Para las conexiones de estado ESTABLECIDAS, la marca se estampa en los paquetes utilizando el --restore-markparámetro del CONNMARKobjetivo; esta directiva copia la marca de la conexión en el paquete. La marca de la conexión se establece previamente utilizando --save-marken la POSTROUTINGcadena (donde pasarían los paquetes pertenecientes a NUEVAS conexiones). El guión me parece demasiado complicado, pero transmite la idea.
the-wabbit
1
Sí, ahora tengo la idea, creo. La última pregunta: ¿entiendes por qué los desarrolladores de kernel no introducen la selección de próximo salto basada en hash para ipv4? ¿Hay alguna razón para no implementarlo junto con la eliminación de la caché de ruta? Una solución similar para ipv6 funciona bastante bien. ¿No es toda esa magia connmark una exageración para una tarea tan simple?
Eugene
1
@Eugene desafortunadamente, estoy lejos de estar lo suficientemente cerca del desarrollo de la pila de IP (o del desarrollo del kernel de Linux en general) para responder con autoridad a cualquiera de sus preguntas, pero especularía que las rutas múltiples con diferentes proveedores con IPv4 se consideraron demasiado una caja de esquina para poner más trabajo en ello. El uso de netfilter CONNMARK obviamente parece un error desagradable, pero incluso podría haber sido considerado como una "solución alternativa utilizable" en la decisión de descartar el código de caché de ruta.
the-wabbit