Ouais ça sent le truc bien vicieux. Un flapping BGP sans raison claire c'est souvent très bas niveau. Première chose à regarder c'est dmesg. Est-ce que tu vois des erreurs de carte réseau ou des warning sur les buffers réseau ?
Ensuite, les compteurs de drops avec ip -s link show dev et netstat -s. C'est le point de départ pour ce genre de truc.
dmesg est vierge de tout warning ou erreur sur le NIC. Le ip -s link ne montre pas d'erreurs d'interface non plus. Tout est à zéro. Par contre netstat -s c'est pas la même histoire.
TcpExt:ListenOverflows: 4567
TcpExt:ListenDrops: 2134
TcpExt:RcvbufErrors: 301
Ces compteurs augmentent bien pendant les phases de flapping. C'est quoi RcvbufErrors exactement ?
ListenOverflows et ListenDrops. Classique. Ça veut dire que ton kernel n'arrive pas à créer les sockets assez vite ou que la queue de connexion est pleine. Ça arrive si net.core.somaxconn ou net.ipv4.tcp_max_syn_backlog sont trop bas pour ton trafic de renouvellement de sessions.
RcvbufErrors c'est un paquet reçu par le NIC, mais le buffer du socket applicatif était plein. Le kernel a dû le jeter. C'est souvent un souci de l'appli qui ne lit pas assez vite, ou le kernel n'a pas pu scheduler la lecture du socket à temps.
Ok je check les sysctls. Alors net.core.somaxconn est à 4096 et net.ipv4.tcp_max_syn_backlog à 2048. C'est déjà bien plus haut que les défauts. On a une centaine de peers BGP, pas des milliers. Ça me paraît suffisant.
On utilise pas tcp_tw_reuse ou tcp_tw_recycle. Ça aurait pu être une source de problèmes avec les TIME_WAIT.
Si tes sysctls de backlog sont déjà bien réglés, et que tu as des RcvbufErrors, ça pointe vers la gestion des buffers de réception. Vérifie aussi net.core.netdev_max_backlog. Ça c'est la queue entre le driver NIC et le réseau IP. Si elle est trop petite, le kernel droppe des paquets avant même qu'ils atteignent TCP.
Si FRR tourne bien et n'est pas CPU-bound, le souci est probablement dans le kernel qui ne peut pas traiter les paquets assez vite.
net.core.netdev_max_backlog est à 1000. C'est le défaut mais je ne pensais pas que ça bloquerait. FRR est loin d'être CPU-bound, il est à 5% max. RAM ok. Disque ok.
Le problème ne se déclenche que quand il y a un gros volume de routes qui arrivent ou sont retirées rapidement. Genre quand un peer devient instable ou qu'on switch de lien. Pas sur le trafic de données normal.
Ah le 'gros volume de routes qui arrivent'. Ça génère beaucoup de trafic de contrôle, de Keepalives TCP qui se renouvellent vite.
Le fait que tu aies des RcvbufErrors et que FRR soit pas CPU-bound, ça sent le 'softirq starvation'. Le traitement des paquets réseau est géré par les softirqs. Si tes ksoftirqd ne tournent pas assez souvent ou sont preemptés, les paquets s'accumulent et sont droppés.
Exactement. Vérifie la distribution des softirqs sur tes cœurs CPU. cat /proc/softirqs. Tu vas voir les NET_RX et NET_TX.
Si un seul cœur est surchargé par les softirqs et que ce même cœur est utilisé par FRR, ou pire, si irqbalance bouge les IRQ du NIC partout, tu perds le contrôle.
Wow, c'est super pertinent. J'ai regardé /proc/softirqs. Le NET_RX est très majoritairement sur le CPU0, et il spike à plus de 40% pendant la charge. Et FRR aussi tourne sur le CPU0 par défaut.
CPU0 CPU1 CPU2 CPU3
NET_RX: 123456789 0 0 0
Je n'ai pas touché à irqbalance, il est actif.
C'est ta coupable. Le CPU0 est noyé sous les softirqs et l'application FRR. Le scheduler n'arrive plus à suivre pour vider les buffers rapidement. Le kernel est obligé de dropper les paquets, d'où les ListenDrops et RcvbufErrors.
Désactive irqbalance. Ensuite tu dois pin manuellement les IRQ de ton NIC à un cœur dédié, et FRR à un autre cœur. Utilise smp_affinity_list pour les IRQ et taskset pour FRR.
Pour désactiver irqbalance sur systemd :
systemctl stop irqbalance
systemctl disable irqbalance
Pour l'affinité IRQ du NIC (exemple eth0, IRQ 123) et softirq :
echo 4 > /proc/irq/123/smp_affinity_list # CPU2
echo 4 > /sys/class/net/eth0/queues/rx-0/rps_cpus # Pour RSS si multi-queue
Et pour FRR (pid 4567) :
taskset -pc 8 4567 # CPU3
Redémarre FRR après ça pour être sûr qu'il prenne le taskset.
J'ai fait tout ça. irqbalance est down. Le NIC IRQ (eth0) est maintenant sur CPU2, et le processus FRR sur CPU3. Je viens de relancer le stress test avec le même pattern de churn.
Une heure plus tard : Zéro flapping BGP. Les compteurs ListenOverflows et RcvbufErrors sont stables, ils n'ont pas bougé d'un poil. Le CPU2 est bien à 90% softirq pendant les pics, et CPU3 est dédié à FRR.
Incroyable c'était bien la famine de softirqs qui faisait tout capoter. Merci pour le coup de main sur ce coup-là c'était chirurgical !
Vous devez être connecté pour poster un message !
Recevoir les derniers articles gratuitement en créant un compte !
S'inscrire
roger-hamon
Membre depuis le 11/12/2020actif
Salut l'équipe. On a un problème super chiant avec nos routeurs BGP basés sur Linux et FRR. Les sessions BGP flappent de manière totalement aléatoire, surtout quand on a beaucoup de changements de routes qui arrivent de nos peers.
Les logs FRR sont clean. Aucune erreur de session explicite, juste des transitions Established -> Idle -> Active -> Established. On dirait que le kernel network stack drop des paquets ou truc du genre. Pas de crash.
Des idées sur ce qui pourrait se passer à bas niveau ?