Routage à chemins multiples dans les noyaux post-3.6

16

Comme vous le savez probablement tous, le cache de route ipv4 a été supprimé dans la série de noyaux Linux 3.6, ce qui a eu un impact sérieux sur le routage par trajets multiples. Le code de routage IPv4 (contrairement à IPv6) sélectionne le prochain saut de manière circulaire, de sorte que les paquets d'une IP source donnée à une IP de destination donnée ne passent pas toujours par le même saut suivant. Avant 3.6, le cache de routage corrigeait cette situation, car le saut suivant, une fois sélectionné, restait dans le cache, et tous les autres paquets de la même source vers la même destination passaient par ce saut suivant. Maintenant, le prochain saut est re-sélectionné pour chaque paquet, ce qui conduit à des choses étranges: avec 2 routes par défaut à coût égal dans la table de routage, chacune pointant vers un fournisseur Internet, je ne peux même pas établir de connexion TCP, car SYN initial et ACK final passer par différents itinéraires,

Existe-t-il un moyen relativement simple de restaurer le comportement normal du routage par trajets multiples, de sorte que le saut suivant soit sélectionné par flux plutôt que par paquet? Existe-t-il des correctifs pour que la sélection du prochain saut IPv4 soit basée sur le hachage, comme pour IPv6? Ou comment gérez-vous tous cela?

Eugène
la source
Avez-vous une configuration "à accès partagé" similaire à celle-ci ici: lartc.org/howto/lartc.rpdb.multiple-links.html ? Si oui, à quoi ressemble votre ensemble de règles et vos itinéraires?
le-wabbit du
essayez d'utiliser "ip route get 173.194.112.247" plusieurs fois et affichez la sortie
c4f4t0r
Merci pour cette question savoureuse. :) tout d'abord, vous ne nous avez pas donné d'exemple. Donc je suppose que vous avez quelque chose comme ip ro add 8.8.8.8/32 nexthop via 1.2.3.4 nexthop via 1.2.3.5cette hypothèse correcte?
poige
Oui c'est correct, mais généralement c'est ip route add 0.0.0.0/0 avec plusieurs prochains sauts.
Eugene
le-wabbit, oui, exactement comme ça. "fournisseur 1" et "fournisseur 2" dans mon cas sont des routeurs frontaliers connectés à mon réseau interne et au réseau du fournisseur et ils font du NAT. Sur mon routeur interne, j'ai juste une passerelle par défaut avec 2 sauts pointant vers provider1 et provider2, pas d'autre route. Les règles de pare-feu autorisent simplement certains services (comme HTTP) pour les machines clientes et bloquent tout le reste.
Eugene

Réponses:

8

Si possible, passez à Linux Kernel> = 4.4 ....

Le routage par trajets multiples basé sur le hachage a été introduit, ce qui est à bien des égards meilleur que le comportement antérieur à 3.6. Il est basé sur le flux, prenant un hachage des IP source et de destination (les ports sont ignorés) pour garder le chemin stable pour les connexions individuelles. Un inconvénient est que je crois qu'il y avait différents algorithmes / modes de configuration disponibles avant la 3.6, mais maintenant vous obtenez ce que vous avez! Vous pouvez cependant utiliser le choix du chemin weight.

Si vous êtes dans ma situation, vous voulez vraiment le 3.6 >= behaviour < 4.4mais il n'est plus pris en charge.

Si vous effectuez une mise à niveau vers> = 4.4, cela devrait faire l'affaire, sans toutes les autres commandes:

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

Alternativement par appareil:

ip route add default  proto static scope global \
 nexthop  dev <if_1> weight 1 \
 nexthop  dev <if_2> weight 1
bao7uo
la source
Pour toute personne venant à cette solution - jetez un œil également à: net.ipv4.fib_multipath_use_neigh pour désactiver automatiquement le nexthop / passerelle "abandonné".
Rostislav Kandilarov
6

"Relativement facile" est un terme difficile, mais vous pourriez

  1. configurer des tables de routage pour chacun de vos liens - une table par lien, avec une seule passerelle par défaut
  2. utiliser netfilter pour tamponner des marques identiques sur tous les paquets d'un même flux
  3. utilisez la table de règles ip pour router les paquets via différentes tables de routage en fonction de la marque
  4. utilisez une route pondérée multi-nexthop pour équilibrer les premiers paquets en session sur vos passerelles / liens.

Il y a eu une discussion à la liste de diffusion netfilter sur ce sujet où je vole les listes de:

1. Règles de routage (RPDB et 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. Règles de pare-feu (en utilisant ipset pour forcer un mode LB "flow")

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

Vous voudrez peut-être suivre la discussion de la liste de diffusion netfilter pour quelques variantes de ce qui précède.

le-wabbit
la source
Pas sûr, mais il pourrait être plus simple d' u32obtenir des paramètres importants hachés et ensuite "label" attribué pour ip rule's
poige
Merci, mais cela ressemble à une solution assez complexe. Ce que je ne comprends pas vraiment, c'est quelle pièce ici est responsable de "tamponner des marques identiques sur tous les paquets d'un même flux"? Comment fonctionne cette magie d'ipset? Je pensais que l'ipset n'est qu'un ensemble d'adresses IP particulières qui sont hachées et peuvent être associées dans des règles.
Eugene
Vous avez raison ipset- il s'agit simplement de créer des ensembles qui sont remplis à l'aide --add-setet comparés à l'utilisation --match-set- mais cela concerne principalement les connexions à l'état NOUVEAU. Pour les connexions d'état ESTABLISHED, la marque est estampillée sur les paquets en utilisant le --restore-markparamètre de la CONNMARKcible - cette directive copie la marque de la connexion dans le paquet. La marque de la connexion est précédemment définie en utilisant --save-markdans la POSTROUTINGchaîne (où les paquets appartenant aux NOUVELLES connexions passeraient). Le script me semble trop alambiqué, mais il véhicule l'idée.
le-wabbit du
1
Oui, maintenant j'ai compris l'idée, je pense. La dernière question: comprenez-vous pourquoi les développeurs du noyau n'introduisent pas la sélection du prochain saut basée sur le hachage pour ipv4? Y a-t-il une raison pour ne pas l'implémenter avec la suppression du cache de routage? Une solution similaire pour ipv6 fonctionne très bien. Toute cette magie connmark n'est-elle pas une exagération pour une tâche aussi simple?
Eugene
1
@Eugene malheureusement, je suis loin d'être assez proche du développement de la pile IP (ou du développement du noyau Linux en général) pour répondre avec autorité à toutes vos questions, mais je suppose que le multipathing utilisant différents fournisseurs avec IPv4 a été considéré comme trop une valise d'angle pour y mettre plus de travail. L'utilisation de netfilter CONNMARK ressemble évidemment à un méchant coup de tête, mais pourrait même avoir été considérée comme une «solution de contournement utilisable» dans la décision de supprimer le code de cache de route.
the-wabbit