Proxmox LXC : réseau cassé — la checklist veth/tap qui identifie réellement la cause

Cet article vous a aidé ?

Quand un conteneur LXC « a une IP » mais ne peut pas pinguer la passerelle, ce n’est pas un mystère. C’est une information manquante. Les pannes réseau sur Proxmox sont rarement subtiles ; elles sont simplement réparties entre namespaces, bridges, couches de firewall et une case mal comprise.

Ceci est une checklist de niveau production pour la douleur spécifique : trafic veth/tap/bridge qui ne circule pas. Elle est écrite pour forcer la clarté : le paquet meurt, pourquoi, et quelle décision prendre ensuite.

Mode opératoire de diagnostic rapide

Si vous êtes d’astreinte, vous n’avez pas besoin d’une théorie. Vous avez besoin d’un entonnoir. Voici l’ordre qui permet généralement de trouver le goulot d’étranglement le plus vite.

1) Décidez : est-ce « uniquement le conteneur » ou « l’hôte aussi » ?

  • Si l’hôte peut atteindre la passerelle et Internet mais que le conteneur ne le peut pas : suspectez le bridge, le firewall, le VLAN, rp_filter, la route du conteneur ou le MTU.
  • Si l’hôte non plus ne peut pas : arrêtez de toucher LXC. Réparez d’abord le réseau physique en amont, les routes de l’hôte ou le firewall de l’hôte.

2) Confirmez que le veth existe et qu’il est attaché au bridge attendu

  • Pas de veth sur l’hôte : le conteneur n’a pas démarré proprement, erreur de config, ou la création du veth a échoué à cause d’un nom/limite.
  • veth existe mais pas sur vmbrX : mauvais nom de bridge dans la config du conteneur, ou un bridge obsolète a été renommé.

3) Vérifiez L2 d’abord, puis L3, puis la politique

  • L2 : lien up, appartenance au bridge, filtrage VLAN, apprentissage/forwarding MAC.
  • L3 : IP/masque du conteneur, route par défaut, ARP/voisin, routes de l’hôte.
  • Politique : firewall Proxmox (datacenter/node/CT), nftables/iptables, sysctls (rp_filter, forwarding).

4) Utilisez un seul « paquet connu bon » pour tester

  • Depuis le conteneur : ping de la passerelle IP, puis ping de l’IP du bridge de l’hôte, puis ping d’une IP externe.
  • Si le ping de la passerelle échoue, regardez ARP/voisin et bridge/VLAN avant de perdre du temps sur NAT/DNS.

5) Capturez des paquets des deux côtés du veth

  • Capturez sur le veth de l’hôte et sur vmbrX. Si vous voyez l’egress mais pas l’ingress, le bridge ou les règles VLAN laissent passer ou droppent.
  • Si vous ne voyez rien sur le veth de l’hôte, le conteneur n’a jamais émis le paquet (route, interface down, politique à l’intérieur du CT).

Une citation à garder en poche quand vous êtes tenté de « redémarrer pour voir » : « L’espoir n’est pas une stratégie. » — General Gordon R. Sullivan (souvent cité dans les équipes d’exploitation).

Modèle mental : veth, bridges et namespaces (sans mythologie)

Dans Proxmox LXC, le conteneur n’obtient pas une « vraie NIC ». Il reçoit une extrémité d’une paire veth. L’autre extrémité se trouve sur l’hôte et est typiquement branchée à un bridge Linux comme vmbr0. C’est tout. C’est l’astuce entière.

Où les gens se perdent, c’est que le réseau s’étend sur :

  • Le namespace réseau du conteneur (ses propres interfaces, routes, cache ARP).
  • La frontière de la paire veth (deux interfaces connectées dos à dos en permanence).
  • Le bridge de l’hôte (comportement de switch : base d’apprentissage, filtrage VLAN, réglages STP).
  • La pile IP de l’hôte (si l’hôte fait routage/NAT, ou si vous utilisez le firewall de l’hôte).
  • Le firewall Proxmox (ce n’est pas magique ; ce sont des règles qui deviennent du netfilter).
  • Le commutateur en amont (trunks VLAN, limites MAC, sécurité de port, MTU, particularités LACP).

Tap apparaît surtout avec QEMU VMs, où les devices tap relient la VM au bridge de l’hôte. LXC utilise veth par défaut. Mais les schémas de panne se recoupent : mauvais bridge, mauvais VLAN, drop du firewall, mismatch MTU, ou « c’est up mais ne forwarde pas réellement ».

Voici la simplification la plus utile :

  • veth = un câble Ethernet virtuel avec deux extrémités. Si une extrémité est up, l’autre peut quand même être down. Traitez-le comme un câble réel.
  • bridge = un switch virtuel. Si le filtrage VLAN est activé, il peut se comporter comme un switch managé et dropper silencieusement.
  • namespace = une pièce avec sa propre table de routage et son cache ARP. Vous ne pouvez pas déboguer une pièce que vous n’avez jamais visitée.

Blague #1 (courte, pertinente) : Une paire veth c’est comme un mariage : si une des deux parties arrête de parler, l’autre pense toujours que tout va « bien ».

Faits et contexte intéressants (parce que votre futur vous le mérite)

  1. Les paires veth existent dans Linux bien avant l’essor des conteneurs. Elles ont commencé comme moyen générique de connecter des namespaces et des switches virtuels ; Docker a juste popularisé le schéma.
  2. Le bridge Linux précède souvent Open vSwitch dans de nombreuses déploiements. Il est ancien, stable et très capable — surtout depuis que le filtrage VLAN et les hooks netfilter ont mûri.
  3. Le firewall Proxmox n’est pas un appliance séparé. Il génère des règles netfilter sur le nœud. Si vous exécutez vos propres règles nftables, vous co-écrivez la politique.
  4. La découverte ARP/voisin est le premier canari. Si un conteneur ne peut pas atteindre sa passerelle, 80% du temps ARP échoue à cause d’un VLAN, d’un bridge ou d’un filtrage MAC — pas d’un « problème DNS ».
  5. Le filtrage du chemin inverse (rp_filter) a été conçu pour l’anti-usurpation. Il est excellent jusqu’à ce que vous ayez du routage asymétrique, du policy routing ou du multi-homing. Alors il devient un destructeur silencieux de trafic.
  6. Les mismatches MTU cassent rarement de petits pings. Ils cassent des charges réelles : handshakes TLS, pulls d’images de conteneur, et tout ce qui déclenche fragmentation / échecs PMTUD.
  7. Le filtrage VLAN sur un bridge Linux est relativement « récent » comparé au bridging classique. Beaucoup d’équipes l’activent pour l’hygiène puis oublient que le trafic non taggé nécessite désormais une gestion explicite du PVID.
  8. Les tables conntrack sont une ressource finie. Lorsqu’elles débordent ou que les timeouts sont inappropriés, des échecs de connectivité « aléatoires » apparaissent — surtout sous NAT.

Tâches pratiques : commandes, sorties, décisions (la vraie checklist)

Ci‑dessous des tâches pratiques. Chacune est conçue pour répondre à une seule question et forcer une action suivante. Exécutez-les dans l’ordre jusqu’à trouver le premier mensonge.

Task 1 — Confirmer que le conteneur voit une interface et une IP

cr0x@server:~$ pct exec 101 -- ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0             UP             2a:7d:1c:4f:9b:12 <BROADCAST,MULTICAST,UP,LOWER_UP>

Ce que ça signifie : Si eth0 est absent ou DOWN, arrêtez. Ce n’est pas un problème de routage ; c’est la plomberie d’interface ou la config du conteneur.

Décision : Si eth0 est down, inspectez la config du conteneur et la création du veth sur l’hôte (Tâches 5–7). S’il est up, vérifiez l’IP/la route ensuite.

cr0x@server:~$ pct exec 101 -- ip -br addr show dev eth0
eth0             UP             192.0.2.50/24 fe80::287d:1cff:fe4f:9b12/64

Décision : Pas d’adresse IPv4 alors que vous en attendez une ? Corrigez la configuration DHCP/statique à l’intérieur du CT (ou la config Proxmox si vous utilisez ip=dhcp).

Task 2 — Vérifier la route par défaut à l’intérieur du conteneur

cr0x@server:~$ pct exec 101 -- ip route
default via 192.0.2.1 dev eth0
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.50

Ce que ça signifie : Si la route par défaut est manquante ou pointe vers la mauvaise passerelle, le conteneur ne peut pas sortir de son sous‑réseau.

Décision : Corrigez la passerelle. Ne touchez pas aux bridges/firewalls tant que le L3 dans le CT n’est pas sain.

Task 3 — Échelle de ping rapide (passerelle → bridge hôte → IP publique)

cr0x@server:~$ pct exec 101 -- ping -c 2 192.0.2.1
PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data.
64 bytes from 192.0.2.1: icmp_seq=1 ttl=64 time=0.512 ms
64 bytes from 192.0.2.1: icmp_seq=2 ttl=64 time=0.487 ms

--- 192.0.2.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms

Décision : Si le ping de la passerelle échoue, allez directement vérifier ARP/voisin et VLAN/bridge (Tâches 4, 8, 10, 11). Si le ping de la passerelle fonctionne mais l’IP publique échoue, vous avez probablement du routage/NAT/firewall en amont.

Task 4 — Vérifier l’état du voisin (ARP) dans le conteneur

cr0x@server:~$ pct exec 101 -- ip neigh show dev eth0
192.0.2.1 lladdr 00:11:22:33:44:55 REACHABLE

Ce que ça signifie : REACHABLE/STALE est acceptable. INCOMPLETE signifie que les requêtes ARP ne reçoivent pas de réponse (mismatch VLAN, bridge drop, switch en amont, ou mauvaise IP de passerelle).

Décision : Si vous voyez INCOMPLETE, ne touchez pas au DNS. Réparez l’adjacence L2/L3.

Task 5 — Trouver le veth côté hôte pour le conteneur

cr0x@server:~$ pct config 101 | grep -E '^net'
net0: name=eth0,bridge=vmbr0,firewall=1,hwaddr=2A:7D:1C:4F:9B:12,ip=192.0.2.50/24,gw=192.0.2.1,type=veth

Décision : Confirmez le nom du bridge. Si cela référence vmbr1 alors que vous attendiez vmbr0, vous avez trouvé votre bug.

cr0x@server:~$ ip -br link | grep -E 'veth|vmbr0'
vmbr0            UP             3a:ad:be:ef:01:23 <BROADCAST,MULTICAST,UP,LOWER_UP>
veth101i0        UP             fe:9a:1c:0f:3b:7a <BROADCAST,MULTICAST,UP,LOWER_UP>

Ce que ça signifie : Proxmox nomme typiquement le veth hôte comme veth<ctid>i0. S’il manque, le réseau du conteneur n’est pas monté.

Décision : Si absent, regardez les logs de démarrage du conteneur et les messages du kernel (Tâche 14).

Task 6 — Confirmer que le veth est esclave du bridge

cr0x@server:~$ ip link show master vmbr0
7: veth101i0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master vmbr0 state UP mode DEFAULT group default qlen 1000
    link/ether fe:9a:1c:0f:3b:7a brd ff:ff:ff:ff:ff:ff

Décision : Si le veth n’est pas listé sous vmbr0, le conteneur est connecté nulle part. Corrigez l’affectation du bridge ou recréez l’interface.

Task 7 — Vérifier l’état du port bridge et les drapeaux d’apprentissage/flooding

cr0x@server:~$ bridge link show dev veth101i0
7: veth101i0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> master vmbr0 state forwarding priority 32 cost 2

Ce que ça signifie : Si le port est blocking ou pas en forwarding, STP ou une mauvaise config de bridge empêche le trafic.

Décision : Si bloqué, inspectez STP et la prévention de boucles sur le bridge et en amont (Tâche 12).

Task 8 — Vérifier le tagging/filtrage VLAN sur le bridge

cr0x@server:~$ bridge vlan show dev veth101i0
port              vlan-id  
veth101i0          1 PVID Egress Untagged

Ce que ça signifie : Avec des bridges VLAN-aware, le port a besoin d’un PVID correct pour le trafic non taggé, ou d’une appartenance VLAN explicite pour le trafic taggé.

Décision : Si vous attendez le VLAN 20 mais ne voyez que le VLAN 1, soit définissez tag=20 dans la config réseau du conteneur, soit ajustez les règles VLAN du bridge.

Task 9 — Confirmer que la config réseau du conteneur correspond à l’intention VLAN

cr0x@server:~$ pct config 101 | grep -E '^net0'
net0: name=eth0,bridge=vmbr0,firewall=1,tag=20,hwaddr=2A:7D:1C:4F:9B:12,ip=192.0.2.50/24,gw=192.0.2.1,type=veth

Décision : Si votre port de switch est en access VLAN 20 (untagged), ne taggez pas dans Proxmox ; utilisez non taggé et définissez le PVID du bridge en conséquence. Si votre uplink est un trunk, le tagging peut être correct. Faites correspondre la réalité, pas vos souhaits.

Task 10 — Vérifier la FDB du bridge (apprentissage MAC)

cr0x@server:~$ bridge fdb show br vmbr0 | grep -i fe:9a:1c:0f:3b:7a
fe:9a:1c:0f:3b:7a dev veth101i0 master vmbr0 permanent

Ce que ça signifie : Si les MAC ne sont pas apprises dynamiquement (ou apparaissent sur le mauvais port), vous pouvez obtenir des bizarreries « ça marche pour un conteneur ».

Décision : Aucun signe des MAC du conteneur ? Le trafic peut ne pas entrer dans le bridge (le conteneur n’émet pas, le firewall droppe, ou le veth est down).

Task 11 — Inspecter l’état du firewall Proxmox aux trois niveaux

cr0x@server:~$ pve-firewall status
Status: enabled/running
cr0x@server:~$ cat /etc/pve/firewall/cluster.fw | sed -n '1,120p'
[OPTIONS]
enable: 1

[RULES]
cr0x@server:~$ cat /etc/pve/nodes/$(hostname)/host.fw | sed -n '1,160p'
[OPTIONS]
enable: 1
policy_in: DROP
policy_out: ACCEPT

Ce que ça signifie : Un DROP par défaut sur le firewall de l’hôte peut casser le forwarding des conteneurs si vous n’autorisez pas explicitement le trafic du bridge.

Décision : Si vous ne comprenez pas complètement vos politiques de firewall, désactivez temporairement le firewall du CT pour un test contrôlé, pas comme « correction ».

Task 12 — Vérifier si STP/réglages du bridge empêchent silencieusement le forwarding

cr0x@server:~$ cat /etc/network/interfaces | sed -n '1,220p'
auto lo
iface lo inet loopback

auto eno1
iface eno1 inet manual

auto vmbr0
iface vmbr0 inet static
        address 192.0.2.10/24
        gateway 192.0.2.1
        bridge-ports eno1
        bridge-stp off
        bridge-fd 0
        bridge-vlan-aware yes
        bridge-vids 2-4094

Décision : Si STP est activé et que vous ne l’attendiez pas, vous pourriez attendre des délais de forwarding ou subir un port bloqué. Si VLAN-aware est activé, vous devez gérer l’appartenance VLAN volontairement.

Task 13 — Valider les sysctls hôtes qui affectent le forwarding et l’asymétrie

cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv4.conf.all.rp_filter net.ipv4.conf.vmbr0.rp_filter
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.vmbr0.rp_filter = 1

Ce que ça signifie : Si vous faites du routage/NAT sur l’hôte et avez des chemins asymétriques (uplinks multiples, policy routing, VRFs), rp_filter=1 peut dropper du trafic valide.

Décision : Si vous soupçonnez rp_filter, testez avec rp_filter=2 (loose) sur les interfaces concernées, puis sécurisez avec un routage correct. Ne le laissez pas à « ce qui fait marcher » sans comprendre.

Task 14 — Chercher des indices kernel : veth, bridge, nf_tables, MTU

cr0x@server:~$ dmesg -T | tail -n 30
[Thu Dec 26 09:14:02 2025] device veth101i0 entered promiscuous mode
[Thu Dec 26 09:14:02 2025] vmbr0: port 7(veth101i0) entered blocking state
[Thu Dec 26 09:14:03 2025] vmbr0: port 7(veth101i0) entered forwarding state

Décision : Si vous voyez des erreurs comme « failed to create veth », « RTNETLINK answers: File exists », ou des avertissements liés au MTU, vous avez un problème côté hôte : collisions de nom, épuisement de ressources, ou mauvais ordre de config.

Task 15 — Tracer les paquets avec tcpdump des deux côtés

cr0x@server:~$ tcpdump -ni veth101i0 arp or icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on veth101i0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:18:10.102938 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Décision : Si les requêtes ARP quittent le veth mais que vous ne voyez jamais de réponses, vérifiez le VLAN et le switch en amont. Si vous voyez des réponses sur vmbr0 mais pas sur veth101i0, quelque chose sur l’hôte filtre entre le bridge et le port (filtrage bridge VLAN, règles ebtables/nft bridge, firewall Proxmox).

cr0x@server:~$ tcpdump -ni vmbr0 arp or icmp
listening on vmbr0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:18:10.102944 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Décision : Voir la même requête sur vmbr0 est bon : le paquet entre dans le domaine du bridge. Maintenant trouvez où la réponse meurt.

Task 16 — Vérifier que nftables/iptables ne tue pas le trafic du bridge

cr0x@server:~$ nft list ruleset | sed -n '1,200p'
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
  }
  chain forward {
    type filter hook forward priority 0; policy drop;
  }
}

Ce que ça signifie : Un DROP par défaut sur forward cassera le trafic des conteneurs routés/NATés. Le trafic bridge peut aussi être impacté selon les sysctls et les réglages bridge netfilter.

Décision : Si vous dépendez du routage/NAT hôte, ajoutez des accept explicites pour la sous‑réseau du conteneur et l’interface de sortie. Si vous faites du pur bridging, inspectez bridge-nf-call-iptables (Tâche 17).

Task 17 — Vérifier les sysctls bridge netfilter (le multiplicateur de politique silencieux)

cr0x@server:~$ sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.bridge.bridge-nf-call-arptables
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-arptables = 0

Ce que ça signifie : Quand activés, les paquets pontés peuvent traverser les hooks iptables/nft. Ça peut être utile (sécurité) ou catastrophique (drops surprises).

Décision : Si vous n’aviez pas l’intention de firewaller le trafic ponté, mettez ces valeurs à 0 et appuyez‑vous sur des limites L2/L3 correctes — ou écrivez des règles en connaissance de cause.

Task 18 — Valider le MTU entre conteneur, veth, bridge et uplink

cr0x@server:~$ ip -br link show dev veth101i0 vmbr0 eno1
veth101i0         UP             fe:9a:1c:0f:3b:7a <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
vmbr0             UP             3a:ad:be:ef:01:23 <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
eno1              UP             58:11:22:aa:bb:cc <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000

Ce que ça signifie : Un uplink à 9000 et un bridge à 1500 n’est pas toujours faux, mais c’est un terrain favorable aux cas limites PMTUD si du routage/NAT est impliqué.

Décision : Standardisez le MTU de bout en bout pour le segment, ou prouvez avec des captures que la fragmentation / les ICMP « frag needed » fonctionnent.

Task 19 — Confirmer que le DNS du conteneur n’est pas le bouc émissaire

cr0x@server:~$ pct exec 101 -- getent hosts example.com
2606:2800:220:1:248:1893:25c8:1946 example.com
93.184.216.34 example.com

Décision : Si le ping de la passerelle fonctionne mais que le DNS échoue, corrigez les resolvers (le /etc/resolv.conf à l’intérieur du CT ou la gestion systemd-resolved). Ne réécrivez pas la config du bridge pour un problème DNS.

Task 20 — Tester la connectivité hôte→conteneur (sanity locale)

cr0x@server:~$ ping -c 2 192.0.2.50
PING 192.0.2.50 (192.0.2.50) 56(84) bytes of data.
64 bytes from 192.0.2.50: icmp_seq=1 ttl=64 time=0.221 ms
64 bytes from 192.0.2.50: icmp_seq=2 ttl=64 time=0.213 ms

--- 192.0.2.50 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms

Décision : Si l’hôte ne peut pas pinguer le conteneur mais que le conteneur peut pinguer le bridge de l’hôte, suspectez une politique de firewall sur l’hôte, ou un filtrage ebtables/nft au niveau du bridge.

Erreurs courantes : symptôme → cause racine → correctif

1) « Le conteneur a une IP mais ne peut pas pinguer la passerelle »

Cause racine : Mismatch VLAN ou bridge VLAN-aware qui droppe des trames non taggées ; parfois le port switch en amont est en access VLAN X mais Proxmox tagge VLAN X (double tagging ou mauvais tagging).

Correctif : Rendre l’intention VLAN explicite. Si l’uplink est en trunk et que le conteneur doit être sur le VLAN 20, mettez tag=20 et assurez-vous que vmbr0 autorise le VLAN 20. Si l’uplink est en access VLAN 20, ne taggez pas dans Proxmox ; assurez-vous que le PVID du port correspond.

2) « Ça marche pendant quelques minutes, puis ça meurt ; redémarrer le conteneur règle le problème »

Cause racine : Churn de la table voisin/ARP dû à une IP dupliquée, MAC dupliqué (CT cloné), ou limite MAC/port-security en amont qui arrête l’apprentissage.

Correctif : Assurer une MAC unique par CT ; ne jamais cloner et oublier de changer la MAC. Vérifiez la sécurité MAC du switch en amont. Vérifiez qu’il n’y a pas d’IP dupliquée sur le segment.

3) « Le conteneur peut pinguer des IPs mais pas résoudre des noms »

Cause racine : Mauvaise configuration DNS, problèmes systemd-resolved stub, ou Proxmox injectant de mauvais resolvers. Parfois le firewall bloque UDP/53 alors que ICMP passe.

Correctif : Validez le /etc/resolv.conf à l’intérieur du CT et exécutez getent hosts. Si le firewall est actif, autorisez explicitement le DNS.

4) « Seuls les gros téléchargements échouent ; les pings fonctionnent »

Cause racine : Mismatch MTU + PMTUD cassé (ICMP « frag needed » bloqué), ou réseaux overlay interagissant avec des jumbo frames.

Correctif : Standardisez le MTU ; autorisez ICMP type 3 code 4 là où c’est pertinent ; confirmez avec tcpdump et un grand curl ou un ping -M do -s test.

5) « Le trafic fonctionne jusqu’à ce qu’on active le firewall Proxmox »

Cause racine : DROP par défaut dans les politiques node/host/CT avec des règles d’accept manquantes pour le forwarding du bridge ; ou les sysctls bridge netfilter envoient le trafic ponté dans des règles L3 par surprise.

Correctif : Auditez les politiques aux niveaux datacenter/node/CT. Décidez où le filtrage doit se faire. Gardez les sysctls bridge-nf intentionnels.

6) « Le conteneur peut joindre l’hôte mais rien d’autre ; le NAT est configuré (en principe) »

Cause racine : net.ipv4.ip_forward de l’hôte désactivé, chaîne forward en DROP, ou règles NAT écrites pour iptables alors que le système utilise nftables (ou inversement).

Correctif : Validez le sysctl de forwarding, assurez-vous que la chaîne forward accepte, et que vous écrivez les règles vers le backend de firewall actif.

7) « Après migration d’un CT vers un autre nœud, le réseau a cassé »

Cause racine : Dérive de config du nœud : noms de vmbr différents, réglages VLAN-aware différents, MTU ou defaults firewall différents.

Correctif : Traitez le réseau des nœuds comme un contrat d’API. Standardisez /etc/network/interfaces entre les nœuds et vérifiez avec une checklist pré-migration.

Blague #2 (courte, pertinente) : Les bugs VLAN sont comme des paillettes — une fois présents, vous les retrouverez dans des endroits que vous n’avez pas touchés.

Checklists / plan étape par étape

Checklist A — « Le conteneur ne peut pas atteindre la passerelle » (le plus fréquent)

  1. Dans le CT : ip -br addr et ip route. Corriger IP/route manquante d’abord.
  2. Dans le CT : ip neigh. Si la passerelle est INCOMPLETE, c’est L2/VLAN/bridge.
  3. Sur l’hôte : confirmer que le veth existe et est sur le bridge attendu (ip -br link, ip link show master vmbr0).
  4. Sur l’hôte : vérifier l’appartenance VLAN (bridge vlan show). Comparez au mode du switchport (access vs trunk) et au tag= Proxmox.
  5. Capturez l’ARP sur le veth hôte et le vmbr. Si la requête sort mais que la réponse n’arrive jamais, montez en amont (config switch, sécurité MAC, câblage, problèmes de hashing LACP).

Checklist B — « La passerelle fonctionne, Internet non »

  1. Pinguer une IP publique (pas un nom). Si ça échoue, c’est du routage/NAT/firewall, pas du DNS.
  2. Confirmer que l’hôte a la connectivité et la route par défaut correcte.
  3. Si vous utilisez le routage/NAT de l’hôte : vérifier net.ipv4.ip_forward=1, la politique de la chaîne forward, et que les règles NAT sont appliquées dans le backend de firewall correct.
  4. Vérifier rp_filter si plusieurs chemins existent.
  5. Une fois la connectivité IP stable : valider le DNS.

Checklist C — « Intermittent ou lié aux performances »

  1. Vérifier le MTU sur uplink, bridge, veth et conteneur.
  2. Vérifier la pression sur la table conntrack (symptômes : drops aléatoires sous charge).
  3. Capturer et chercher des retransmissions, ICMP frag-needed, ou anomalies TCP MSS.
  4. Auditer les règles firewall pour les timeouts stateful et les drops inattendus.

Trois mini-histoires du monde corporate (pour ne pas les répéter)

Histoire 1 — L’incident causé par une fausse hypothèse

Ils avaient un plan « simple » : migrer un ensemble de services legacy de VMs vers LXC pour économiser de la mémoire. Le réseau était « le même », parce que tout était encore sur vmbr0. Cette phrase est le début des incidents.

Le premier conteneur a démarré avec une IP et répondait aux pings depuis l’hôte. Depuis le réseau extérieur ? Mort. L’équipe a supposé que le firewall en amont n’aimait pas la nouvelle MAC, alors ils ont ouvert des tickets et attendu. Pendant ce temps, les services étaient down et le canal d’incident faisait ce que font les canaux d’incident : générer de la chaleur, pas des données.

Le vrai problème était un mismatch VLAN introduit par une hypothèse « évidente » : le port du switch était un port access pour le VLAN 30, ils ont donc mis tag=30 sur le conteneur. Sur ce port, les trames étaient déjà untagged VLAN 30. Le conteneur envoyait donc des trames VLAN 30 taggées sur un port access qui les a rejetées. ARP n’a jamais abouti. Pas de passerelle, pas de joie.

Ce qui a empiré la situation : l’hôte avait lui‑même une IP sur ce VLAN access et pouvait atteindre la passerelle, donc « l’hôte marche » était pris comme preuve que le conteneur devrait fonctionner. Mais l’hôte était non taggé ; le conteneur était taggé. Réalités différentes, même câble.

La correction fut ennuyeuse : supprimer le tag, garder le conteneur non taggé, et documenter le mode du switchport dans la norme réseau du cluster. Ensuite ils ont ajouté un test pré‑vol : exécuter bridge vlan show et comparer à la config du switchport avant migration.

Histoire 2 — L’optimisation qui s’est retournée contre eux

Une autre organisation était fière de sa posture de sécurité. Ils ont activé le firewall Proxmox partout, mis des politiques par défaut à DROP, et déployé ça pendant une fenêtre de changements qui semblait généreuse sur le calendrier. En réalité elle ne l’était pas.

Les pannes de connectivité n’étaient pas totales. Certains conteneurs pouvaient parler à leur base de données ; d’autres non. Le DNS fonctionnait parfois. L’ICMP était incohérent. Ce sont le genre d’échecs qui font douter de la physique.

L’« optimisation » consistait à activer les hooks bridge netfilter parce qu’ils voulaient filtrer le trafic « même s’il est ponté ». Ils ont activé net.bridge.bridge-nf-call-iptables=1 et appliqué un ensemble de règles L3 qui supposaient du trafic routé. Soudain, les trames pontées étaient soumises à une politique forward DROP. Certains flux survivaient grâce au state tracking ; les nouveaux non. Cela semblait aléatoire parce que c’était une politique stateful rencontrant une topologie pour laquelle elle n’était pas conçue.

Le chemin le plus rapide pour s’en sortir a été de décider : filtrer aux frontières L3 routées, ou filtrer intentionnellement au L2/bridge, mais pas par accident. Ils ont désactivé bridge netfilter sur les nœuds où le design était du pur bridging, gardé le firewall Proxmox pour les interfaces de management, et déplacé le contrôle est‑ouest vers un endroit qui comprenait vraiment le modèle de trafic.

Après l’incident, le meilleur changement n’était pas technique. Il était procédural : tout changement de firewall devait être testé avec un conteneur « connu bon » exécutant une série fixe de tests (ping passerelle, résolution DNS, connexion TCP) avant tout déploiement plus large.

Histoire 3 — La pratique ennuyeuse mais correcte qui a sauvé la journée

Une société proche de la finance (du genre qui traite l’indisponibilité comme un événement carrière) avait une norme de cluster qui agaçait les ingénieurs : chaque nœud avait des noms de bridge identiques, réglages VLAN-aware identiques et MTU identiques. Aucune exception. Si un nœud avait besoin d’un traitement spécial, il avait son propre cluster.

Pendant un refresh hardware, ils ont migré des conteneurs nœud-à-nœud toute la journée. Une migration a échoué : un conteneur a perdu la connectivité externe immédiatement après le démarrage sur le nouveau nœud. L’ingénieur d’astreinte n’a pas spéculé. Il a exécuté la checklist standard : confirmer que le veth existe, vérifier l’appartenance au bridge, vérifier l’appartenance VLAN, tcpdump ARP des deux côtés.

En quelques minutes, ils ont vu les requêtes ARP quitter le veth mais ne jamais apparaître sur l’uplink physique. Ça a réduit le champ aux branchements bridge/uplink, pas au conteneur. Ensuite, ip link show master vmbr0 a révélé que le veth était sur vmbr0, mais vmbr0 n’était pas effectivement attaché à la NIC qu’ils pensaient. Le nom de l’interface avait changé à cause de mises à jour firmware/BIOS et du predictable network interface naming qui fait ce qu’il promet : être prévisible, juste pas de la manière qu’ils attendaient.

Parce qu’ils avaient de la gestion de configuration, ils ont redéployé la config réseau du nœud avec le nom de NIC corrigé et c’était réglé. Pas de debugging unique, pas de « peut‑être redémarrer ». La pratique qui les a sauvés était ennuyeuse : imposer la standardisation, et traiter la config réseau des nœuds comme du code de production.

FAQ

1) Est‑ce que Proxmox LXC utilise des devices tap ou veth ?

Typiquement veth pour LXC. Tap est courant pour les VMs QEMU. Le dépannage se recoupe sur les points bridge, VLAN, firewall et MTU.

2) Comment trouver quel veth appartient à quel conteneur ?

Commencez par pct config <ctid> pour la MAC/bridge. Puis listez ip -br link | grep veth. Les noms ressemblent généralement à veth<ctid>i0.

3) Mon conteneur peut pinguer l’hôte mais pas la passerelle. Que cela implique‑t‑il ?

Vous avez probablement une connectivité locale bridge mais une adjacence L2/L3 en amont cassée : mismatch VLAN, sécurité de port du switch en amont, ou mauvais tagging/PVID.

4) Activer le firewall Proxmox bloque‑t‑il automatiquement les conteneurs ?

Ça peut, selon les politiques par défaut et les jeux de règles aux niveaux datacenter/node/CT. Surveillez aussi les sysctls bridge netfilter ; ils peuvent faire passer le trafic ponté dans des règles L3 par surprise.

5) Quelle est la façon la plus rapide de prouver que c’est lié au VLAN ?

Vérifiez bridge vlan show dev vethXYZ et comparez avec le tag= du conteneur et le mode du switchport en amont. Ensuite capturez l’ARP sur vmbr et l’uplink.

6) Pourquoi les pings fonctionnent mais HTTPS échoue ?

Classique : échec MTU/PMTUD ou problèmes TCP MSS. Les echo ICMP sont petits ; les handshakes TLS et transferts de données ne le sont pas. Vérifiez le MTU et cherchez des ICMP « frag needed ».

7) Quand suspecter rp_filter ?

Quand vous avez plusieurs uplinks, du policy routing, des VRFs ou des chemins de retour asymétriques. Si le trafic disparaît sans drop clair du firewall, rp_filter est un suspect de premier plan.

8) Puis‑je « corriger » ça en passant du bridging au routage/NAT ?

Vous pouvez, mais ce n’est pas une correction ; c’est un changement d’architecture. Si vous routez/NATez, vous devez maîtriser les sysctls de forwarding, la politique de la chaîne forward et les règles NAT. Faites‑le intentionnellement.

9) Mes conteneurs perdent le réseau après migration ou restauration. Pourquoi ?

Dérive de config des nœuds : noms de bridge différents, réglages VLAN-aware, defaults firewall ou MTU. Standardisez le réseau des nœuds et validez avant migrations.

Étapes suivantes (ce qu’il faut changer après correction)

Une fois que vous avez trouvé la cause, ne vous arrêtez pas à « ça marche ». Les systèmes de production régressent parce que l’ambiguïté sous‑jacente reste en place.

  1. Standardiser le réseau des nœuds. Même noms de vmbr, mêmes réglages VLAN-aware, même MTU. Traitez‑le comme un contrat API pour les workloads.
  2. Documenter l’intention VLAN en un seul endroit. Pour chaque bridge/uplink : trunk vs access, VLANs autorisés, et si les conteneurs doivent tagger.
  3. Rendre le firewalling délibéré. Décidez si vous filtrez le trafic ponté. Si oui, écrivez des règles en tenant compte de cette topologie. Si non, désactivez les hooks bridge netfilter.
  4. Conserver un conteneur connu bon. Un petit CT qui peut pinguer la passerelle, résoudre le DNS et atteindre un endpoint TCP. Exécutez‑le après tout changement réseau/firewall.
  5. Culture du « capture first ». En cas de doute, tcpdump des deux côtés du veth et du bridge. Si vous ne voyez pas le paquet, vous discutez avec un fantôme.
← Précédent
Oublier l’autocollant du refroidisseur : la cause d’overchauffe la plus drôle
Suivant →
Debian 13 « Broken pipe » : quand c’est sans danger et quand c’est votre premier avertissement (cas n°75)

Laisser un commentaire