Bridge et VLAN sur Ubuntu 24.04 pour la virtualisation : réparer « la VM n’a pas d’internet » correctement

Cet article vous a aidé ?

Vous lancez une VM. Elle démarre. Elle reçoit une IP. Le DNS semble correct. Et pourtant : pas d’internet. Le ping vers la passerelle tombe comme s’il faisait grève. Vous commencez à marmonner sur « les changements réseau d’Ubuntu » et « peut-être l’image est cassée », et avant même de vous en rendre compte vous avez redémarré libvirtd trois fois sans rien apprendre.

Cela vient presque toujours d’un problème de couche : conception de pont erronée, gestion de VLAN incorrecte, route par défaut mal configurée, ou le pare-feu de l’hôte qui fait trop bien son travail en silence. La solution n’est pas de « tester des configs au hasard jusqu’à ce que ça marche ». Il faut construire le pont/VLAN correctement, puis vérifier comme un SRE : un saut, une table, une décision à la fois.

Un modèle mental sain : ce qui doit être vrai pour qu’une VM atteigne Internet

Quand une VM « n’a pas d’internet », il est tentant de la considérer comme un seul problème. Ce n’en est pas un. C’est une chaîne de conditions. Brisez un maillon et votre VM redevient un localhost très coûteux.

La chaîne non négociable

  • Le lien invité est opérationnel : carte NIC virtio/e1000 présente, carrier actif, MAC correcte, pilote adéquat.
  • L’invité a une configuration IP correcte : IP/masque, route par défaut, DNS.
  • Le trafic sort de l’invité : ARP/ND fonctionne, les paquets quittent l’interface NIC de l’invité.
  • L’hôte relaie correctement au niveau L2 : l’interface tap/vnet de la VM est esclavagisée au bon bridge ; le bridge est up et forwarde.
  • Le marquage VLAN correspond à la réalité : trames non taggées vs taggées exactement comme l’attend le switch en amont.
  • L’hôte dispose d’un uplink vers le réseau réel : le bridge est attaché à la NIC physique (ou à la bonne sous-interface VLAN), avec carrier.
  • Le port du switch en amont est correct : access vs trunk, VLANs autorisés, comportement du VLAN natif connu (ne pas supposer).
  • Le filtrage ne bloque pas en silence : nftables/iptables de l’hôte, filtres libvirt, pare-feu cloud-init de l’invité, ou rp_filter.
  • Le chemin au-delà de la passerelle fonctionne : NAT, routage ou ACL en amont autorisent le trafic.

La plupart des pannes se situent au milieu : le bridge de l’hôte est correct mais le tagging VLAN est faux, ou la VM est branchée sur le mauvais bridge, ou NAT libvirt est utilisé alors que vous pensez être en mode pont.

Un principe opérationnel : arrêtez de deviner où le paquet est mort. Mettez des yeux sur chaque saut jusqu’à trouver le premier point où la réalité diverge de votre modèle mental. C’est là qu’est la correction.

Faits et contexte intéressants (parce que le passé est toujours sur votre réseau)

  1. Le bridging Linux existe depuis le début des années 2000, et il a évolué avec la virtualisation ; KVM n’a pas inventé le besoin, il l’a juste industrialisé.
  2. Le marquage VLAN est plus ancien que la plupart des « produits réseau cloud ». IEEE 802.1Q est apparu à la fin des années 1990 et reste simple : un câble, plusieurs réseaux.
  3. Le réseau par défaut de Libvirt (virbr0) est en NAT. Utile pour les portables, catastrophique pour « ma VM doit être sur le même LAN que tout le monde ».
  4. Netplan n’est pas un démon réseau. C’est un traducteur de configuration qui cible typiquement systemd-networkd sur les serveurs (ou NetworkManager sur les postes).
  5. Les bridges Linux peuvent filtrer et tagger les VLANs (bridge VLAN filtering). Vous pouvez obtenir un comportement « type switch » dans le noyau, avec une appartenance VLAN par port.
  6. Le Spanning Tree Protocol (STP) n’est pas réservé aux switches physiques. Un bridge Linux peut y participer, et activer STP au mauvais endroit peut ajouter des secondes de « pourquoi rien ne passe ? » après la montée du lien.
  7. Le reverse path filtering (rp_filter) a causé plus d’incidents « le ping marche dans un sens » qu’on ne veut l’admettre, surtout sur des hôtes multi-homés.
  8. La pile réseau de systemd a beaucoup mûri la dernière décennie. Ce qui nécessitait jadis du collage manuel dans /etc/network/interfaces est maintenant déclaratif et prévisible—si vous déclarez la bonne chose.
  9. Le comportement « native » d’un VLAN varie selon le fournisseur et la configuration. Le mot « native » est souvent l’endroit où les hypothèses meurent.

Et : les VLAN sont comme les organigrammes. Tout le monde pense qu’ils sont simples jusqu’à devoir en changer un.

Idée paraphrasée : Werner Vogels pousse souvent l’idée « vous le construisez, vous l’exploitez » — la boucle de rétroaction opérationnelle fait partie de l’ingénierie, pas un après-coup.

Guide de diagnostic rapide

Voici le flux « il me faut un signal en cinq minutes ». Il suppose que la VM doit être en pont sur un réseau réel, éventuellement via un VLAN.

Première étape : prouver que la VM est réellement sur le bridge que vous croyez

  • Vérifiez que l’interface vnet/tap de la VM existe sur l’hôte.
  • Confirmez qu’elle est esclavagisée au bon bridge (pas sur virbr0, pas sur un bridge orphelin).
  • Confirmez que le bridge a l’uplink physique attaché (ou la bonne sous-interface VLAN attachée).

Deuxième étape : trouver le premier saut ayant échoué depuis l’intérieur de la VM

  • Pinger la passerelle par défaut.
  • Si ça échoue, regardez la table ARP/voisins et capturez le trafic sur l’interface VM et l’uplink.
  • Si la passerelle répond mais que l’internet ne marche pas, vérifiez DNS vs routage vs ACL en amont.

Troisième étape : valider les attentes VLAN sur l’hôte et le switch

  • Si la VM est non taggée, le bridge/uplink doit être en access/native sur le bon VLAN.
  • Si la VM est taggée, soit l’invité tagge les trames (802.1Q dans la VM), soit le bridge applique les tags (bridge VLAN filtering). Choisissez une approche et tenez-vous-en.
  • Confirmez la liste des VLANs autorisés sur le port du switch ; un « trunk » sans « allowed » est la façon dont les VLANs disparaissent.

Quatrième étape : éliminer le pare-feu et les réglages noyau

  • Vérifiez le jeu de règles nftables pour des drops sur le trafic bridge.
  • Confirmez les réglages bridge netfilter ; vous pouvez filtrer le transit L2 sans vous en rendre compte.
  • Vérifiez rp_filter sur l’hôte si multi-homing ou routage par politiques existent.

Si vous suivez cette séquence, vous trouvez généralement le coupable avant que votre café ne refroidisse.

Tâches pratiques : commandes, sorties attendues et décision suivante

Ce sont des tâches opérationnelles réelles. Exécutez-les dans l’ordre jusqu’à ce que la sortie vous indique où le paquet s’arrête. Chaque tâche inclut : commande(s), ce que la sortie signifie, et la décision à prendre.

Tâche 1 : Identifier l’uplink de l’hôte et l’état du lien

cr0x@server:~$ ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp3s0           UP             3c:ec:ef:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
br0              UP             3c:ec:ef:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
vnet3            UP             fe:54:00:aa:bb:cc <BROADCAST,MULTICAST,UP,LOWER_UP>

Sens : enp3s0 a le carrier (LOWER_UP). br0 existe et est UP. Si votre NIC physique est DOWN/NO-CARRIER, arrêtez ici ; vous n’avez pas d’uplink.

Décision : Si l’uplink est down, corrigez le câblage/le switch/le pilote d’abord. S’il est up, passez à l’appartenance au bridge.

Tâche 2 : Confirmer l’appartenance au bridge (qui est branché sur br0)

cr0x@server:~$ bridge link
3: enp3s0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> master br0
5: vnet3 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> master br0

Sens : La NIC physique et l’interface VM vnet3 sont sur br0. Si vnet3 est sur virbr0 ou sans master, la VM n’est pas sur le réseau prévu.

Décision : Si la VM n’est pas esclavagisée au bon bridge, corrigez l’attachement réseau libvirt avant de toucher aux VLANs ou au pare-feu.

Tâche 3 : Vérifier que la configuration IP de l’hôte vit sur le bridge (pas sur la NIC physique)

cr0x@server:~$ ip -br addr show br0 enp3s0
br0              UP             192.0.2.10/24 fe80::3eec:efff:fe12:3456/64
enp3s0           UP             fe80::3eec:efff:fe12:3456/64

Sens : L’adresse IPv4 de l’hôte est sur br0. C’est ce que vous voulez pour un design pont simple. Si l’IPv4 est sur enp3s0 alors que br0 est en jeu, vous êtes en territoire « ça peut marcher jusqu’à ce que ça casse ».

Décision : Si l’IP de l’hôte est sur la mauvaise interface, corrigez netplan pour que le bridge possède l’IP.

Tâche 4 : Vérifier que la VM voit une IP, une route et un DNS

cr0x@server:~$ virsh domifaddr vm1
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet3      fe:54:00:aa:bb:cc    ipv4         192.0.2.50/24

Sens : La VM a une adresse IPv4. Cela ne prouve pas qu’elle peut atteindre la passerelle, mais confirme que DHCP (ou la config statique) a eu lieu.

Décision : S’il n’y a pas d’adresse, déboguez le DHCP/VLAN invité avant d’accuser le pare-feu de l’hôte.

Tâche 5 : Depuis la VM, tester le premier saut (passerelle) et le deuxième saut (IP publique)

cr0x@server:~$ ping -c 3 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.547 ms
64 bytes from 192.0.2.1: icmp_seq=2 ttl=64 time=0.510 ms
64 bytes from 192.0.2.1: icmp_seq=3 ttl=64 time=0.522 ms

--- 192.0.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms

cr0x@server:~$ ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=12.1 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=12.0 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=55 time=12.2 ms

Sens : Si le ping vers la passerelle échoue, vous êtes face à L2/VLAN/appartenance au bridge ou un pare-feu local. Si la passerelle répond mais que l’IP publique échoue, c’est routage/NAT/ACL amont.

Décision : Choisissez la branche. Ne dépannez pas le DNS quand vous ne pouvez même pas atteindre la passerelle.

Tâche 6 : Inspecter la table ARP/voisins pour la MAC de la passerelle

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

Sens : REACHABLE avec une MAC signifie que l’ARP s’est bien passé. Si c’est INCOMPLETE/FAILED, la VM crie dans le vide (ou un mismatch VLAN avale les trames).

Décision : Si l’ARP est incomplet, capturez le trafic et vérifiez le tagging VLAN.

Tâche 7 : Capturer le trafic sur l’interface vnet de l’hôte (la VM émet-elle de l’ARP ?)

cr0x@server:~$ sudo tcpdump -ni vnet3 -c 10 arp or icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vnet3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:00:01.000000 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28
12:00:02.000000 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Sens : La VM envoie de l’ARP. Si vous ne voyez jamais d’ARP ici, le problème est dans l’invité (mauvaise interface, lien down, route incorrecte) ou la VM n’est pas réellement connectée.

Décision : Si l’ARP existe sur vnet mais qu’aucune réponse n’arrive, la chute est entre le bridge et l’uplink (VLAN, port du switch, ou filtrage hôte).

Tâche 8 : Capturer sur l’uplink de l’hôte (l’ARP sort-il de la machine ?)

cr0x@server:~$ sudo tcpdump -ni enp3s0 -c 10 arp
listening on enp3s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:00:01.000100 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Sens : Voir l’ARP sur enp3s0 signifie que le bridge l’a forwardée. Si vous la voyez sur vnet3 mais pas sur enp3s0, le bridge bloque ou le filtrage VLAN est mal configuré.

Décision : Si ça ne sort pas de la machine, inspectez le bridge VLAN filtering et l’état STP.

Tâche 9 : Inspecter la table de forwarding du bridge (FDB) et l’apprentissage MAC

cr0x@server:~$ bridge fdb show br br0 | head
fe:54:00:aa:bb:cc dev vnet3 master br0
00:11:22:33:44:55 dev enp3s0 master br0

Sens : Le bridge a appris la MAC de la VM sur vnet3 et la MAC de la passerelle sur enp3s0. Si la MAC de la passerelle n’apparaît jamais, les réponses en amont n’arrivent pas (switchport/VLAN) ou sont filtrées.

Décision : Pas de MAC apprise = regardez le mismatch VLAN ou STP bloquant.

Tâche 10 : Vérifier la configuration VLAN sur l’hôte (interfaces VLAN + bridge VLAN filtering)

cr0x@server:~$ ip -d link show br0 | sed -n '1,12p'
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 3c:ec:ef:12:34:56 brd ff:ff:ff:ff:ff:ff
    bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 1 vlan_protocol 802.1Q

cr0x@server:~$ bridge vlan show
port              vlan-id
enp3s0             10 PVID Egress Untagged
vnet3              10 PVID Egress Untagged
br0                10 PVID Egress Untagged

Sens : vlan_filtering=1 signifie que le bridge se comporte comme un switch sensible aux VLANs. PVID 10 untagged sur les deux ports signifie que le trafic non taggé est traité comme VLAN 10 et sort non taggé.

Décision : Si votre switch attend du taggé VLAN 10 mais que vous envoyez non taggé, corrigez soit le port du switch soit les réglages VLAN du bridge. Choisissez une vérité.

Tâche 11 : Vérifier les réglages netfilter/bridge qui peuvent silencieusement bloquer le trafic ponté

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

Sens : Avec bridge-nf-call-iptables=1, votre pare-feu hôte peut filtrer des trames bridgées transit. C’est acceptable, mais c’est une cause fréquente de « pourquoi seules les VMs cassent ? ».

Décision : Si vous comptez sur nftables pour la sécurité hôte, gardez cela activé mais assurez-vous que vos règles autorisent le trafic VM. Sinon, désactivez-le délibérément et documentez pourquoi.

Tâche 12 : Inspecter les règles nftables pour des drops affectant le forwarding

cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    iif "lo" accept
    ct state established,related accept
    tcp dport 22 accept
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "br0" oifname "br0" accept
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

Sens : Une policy drop sur forward est acceptable si des accept explicites existent. Ici, la chain forward par défaut drop est correcte, mais le trafic br0 → enp3s0 n’est pas explicitement autorisé (car oifname n’est pas br0). Cela tuera l’egress des VMs.

Décision : Ajoutez une règle pour autoriser le forwarding br0 → uplink (ou une règle plus précise par VLAN/subnet). N’utilisez pas un « policy accept » pour éviter de réfléchir.

Tâche 13 : Confirmer le type de réseau libvirt (bridgé vs NAT)

cr0x@server:~$ virsh domiflist vm1
 Interface   Type     Source   Model    MAC
-------------------------------------------------------
 vnet3       bridge   br0      virtio   fe:54:00:aa:bb:cc

Sens : Type=bridge Source=br0 signifie que la VM est réellement en pont. Si vous voyez Type=network Source=default, vous êtes en NAT libvirt (virbr0).

Décision : Si c’est du NAT alors que vous attendez du pont, changez la source réseau de la NIC de la VM.

Tâche 14 : Vérifier les routes sur l’hôte (si l’hôte est aussi routeur/NAT)

cr0x@server:~$ ip route
default via 192.0.2.1 dev br0 proto dhcp src 192.0.2.10 metric 100
192.0.2.0/24 dev br0 proto kernel scope link src 192.0.2.10

Sens : Cas simple : la route par défaut de l’hôte passe par la passerelle LAN. Si votre design utilise l’hôte pour router des VLANs VM, vous aurez besoin de routage additionnel et d’IP forwarding.

Décision : Si l’hôte doit router entre VLANs, activez ip_forward et confirmez les routes de retour qui indiquent en amont où se trouvent les sous-réseaux VM.

Tâche 15 : Vérifier IP forwarding et rp_filter sur l’hôte (cas routage)

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

Sens : ip_forward=0 signifie que l’hôte ne routage pas. rp_filter=1 peut bloquer le trafic asymétrique (commun avec le policy routing ou plusieurs uplinks).

Décision : Si l’hôte est routeur, activez ip_forward et réglez rp_filter de façon appropriée (souvent 2 pour le mode loose en multi-homed).

Tâche 16 : Valider que le DHCP vient bien du VLAN attendu

cr0x@server:~$ sudo tcpdump -ni enp3s0 -c 20 udp port 67 or udp port 68
listening on enp3s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:05:01.000000 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request
12:05:01.050000 IP 192.0.2.2.67 > 192.0.2.50.68: BOOTP/DHCP, Reply

Sens : Vous voyez le serveur DHCP répondre. Si DHCP marche mais l’ARP vers la passerelle échoue, il se peut que vous receviez DHCP d’un relais ou d’un VLAN différent de ce que vous pensiez.

Décision : Si l’IP du serveur DHCP vous surprend, arrêtez-vous et réconciliez la configuration VLAN et le port du switch.

Blague #1 : Le DHCP, c’est comme le café du bureau : quand il manque, tout le monde devient soudainement ingénieur réseau.

Modèles de conception corrects (bridge + VLAN) pour les hôtes Ubuntu 24.04

Il existe trois modèles qui fonctionnent de façon fiable. Le mauvais modèle est « un peu de chaque » parce que vous avez copié un bout de code de trois blogs différents à 2h du matin.

Pattern A : bridge non taggé (VLAN unique / port access)

Utiliser quand : votre hôte de virtualisation et vos VMs vivent sur un seul réseau, et le port du switch est en access (ou trunk avec un VLAN natif bien défini que vous contrôlez réellement).

Conception : NIC physique → bridge br0 ; br0 porte l’IP hôte ; les VMs se raccordent à br0. Pas de VLAN filtering. Pas de sous-interfaces VLAN.

Pourquoi c’est bien : moins de pièces mobiles. Moins de risques de mauvais tagging. Moins de discussions « allowed VLANs » avec l’équipe réseau.

Mode de défaillance : quelqu’un change le port du switch en trunk ou vous déplace sur un VLAN différent sans prévenir ; vous restez non taggé et atterrissez au mauvais endroit.

Pattern B : sous-interface VLAN sur l’uplink + bridge par VLAN

Utiliser quand : vous voulez des VMs dans plusieurs VLANs, mais préférez garder la logique VLAN simple et explicite.

Conception : enp3s0 est en trunk sur le switch. Créez des interfaces VLAN sur l’hôte (enp3s0.10, enp3s0.20). Créez des bridges br10 et br20, chacun attaché à la sous-interface VLAN correspondante. Attachez les VMs à br10 ou br20.

Pourquoi c’est bien : très facile à raisonner. Vous voyez ce qui est taggé où. Facile aussi de firewaller par bridge si nécessaire.

Mode de défaillance : les gens oublient d’autoriser le VLAN sur le trunk du switch. Ou ils attachent la VM à br0 (mauvais bridge) et jurent que les VLANs sont « cassés ».

Pattern C : bridge conscient des VLANs avec bridge VLAN filtering

Utiliser quand : vous voulez un seul bridge et que vous souhaitez qu’il se comporte comme un petit switch : uplink trunk, ports access pour les VMs, éventuellement trunks vers des VMs spéciales, et appartenance VLAN contrôlée sur l’hôte.

Conception : enp3s0 est attaché directement à br0 ; br0 a vlan_filtering=1. Vous assignez l’appartenance VLAN par port (enp3s0 et vnetX). Les VMs peuvent être non taggées (access) ou taggées (trunk) selon la configuration.

Pourquoi c’est bien : puissant, évolutif, topologie propre. Un bridge, plusieurs VLANs, moins d’interfaces.

Mode de défaillance : le pouvoir facilite l’erreur. Un PVID manquant ou une règle d’egress mal configurée fait disparaître le trafic sans drame ni excuse.

Mon biais opérationnel : si vous êtes petit à moyen et voulez moins de surprises, Pattern B est le juste milieu. Si vous construisez une plateforme et pouvez vous permettre une gestion de configuration disciplinée et des tests, Pattern C est excellent.

Blague #2 : Les VLANs ne « cassent » pas aléatoirement. Ils cassent de façon parfaitement déterministe—simplement pas toujours documentée.

Exemples Netplan qui fonctionnent (et pourquoi)

Ubuntu 24.04 utilise typiquement netplan pour générer la configuration systemd-networkd sur les serveurs. L’erreur la plus commune est de mélanger des hypothèses NetworkManager avec la réalité networkd, ou de laisser des interfaces à moitié configurées.

Exemple 1 : bridge simple non taggé br0

Port switch : access VLAN X (non taggé).
Hôte : l’IP vit sur br0 via DHCP ou statique.

cr0x@server:~$ sudo cat /etc/netplan/01-br0.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [enp3s0]
      dhcp4: yes
      parameters:
        stp: false
        forward-delay: 0

Pourquoi : enp3s0 n’a pas d’IP ; br0 en a une. STP off évite plus de 30 secondes de « pourquoi je ne peux rien atteindre après un reboot ? » sur des topologies simples.

Exemple 2 : bridges par VLAN (Pattern B)

Port switch : trunk ; VLANs 10 et 20 autorisés/taggés.
Hôte : gestion sur VLAN 10 ; VMs sur VLAN 20.

cr0x@server:~$ sudo cat /etc/netplan/01-vlan-bridges.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  vlans:
    enp3s0.10:
      id: 10
      link: enp3s0
    enp3s0.20:
      id: 20
      link: enp3s0
  bridges:
    br10:
      interfaces: [enp3s0.10]
      dhcp4: yes
      parameters:
        stp: false
        forward-delay: 0
    br20:
      interfaces: [enp3s0.20]
      dhcp4: no
      dhcp6: no
      parameters:
        stp: false
        forward-delay: 0

Pourquoi : br10 et br20 sont explicites. Votre VM va sur br20, et vous ne pouvez pas accidentellement atterrir sur le réseau de gestion sauf si vous le choisissez.

Exemple 3 : bridge conscient VLAN (Pattern C) avec IP de gestion hôte seulement

C’est la manœuvre avancée. L’IP de l’hôte se trouve sur une interface VLAN (VLAN de gestion), tandis que le bridge transporte plusieurs VLANs pour les VMs.

cr0x@server:~$ sudo cat /etc/netplan/01-vlan-aware-bridge.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [enp3s0]
      dhcp4: no
      parameters:
        stp: false
        forward-delay: 0
  vlans:
    br0.10:
      id: 10
      link: br0
      dhcp4: yes

Pourquoi : br0 est purement L2 ; br0.10 est la présence L3 de gestion de l’hôte. Les VMs peuvent être attachées à br0 et placées dans des VLANs via bridge VLAN filtering (configuré en dehors de netplan, typiquement via networkd ou des commandes bridge explicites au démarrage).

Avertissement opérationnel : netplan n’exprime pas tout ce que vous pouvez vouloir pour le bridge VLAN filtering par port. Si vous choisissez Pattern C, traitez-le comme une petite plateforme de commutation : configurez-la de façon cohérente et testez après chaque changement.

Appliquer netplan en toute sécurité

cr0x@server:~$ sudo netplan try
Do you want to keep these settings?

Press ENTER before the timeout to accept the new configuration
Changes will revert in 120 seconds

Sens : netplan try vous donne une fenêtre de rollback. Utilisez-le sur des systèmes distants à moins d’aimer les consoles hors bande.

Décision : Si la connectivité tombe, attendez le rollback et corrigez votre YAML calmement.

Libvirt/KVM attachement : éviter le piège « c’est sur virbr0 »

Les valeurs par défaut de Libvirt sont optimisées pour « un développeur sur portable lance une VM avec internet via NAT ». En production, vous voulez généralement du bridged pour que votre VM soit un citoyen de première classe sur le LAN/VLAN.

Vérifier quels réseaux existent

cr0x@server:~$ virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

Sens : Le réseau NAT par défaut libvirt existe. Ce n’est pas mal en soi ; c’est juste souvent pas ce que vous voulez.

Décision : Décidez explicitement : NAT (par défaut) vs bridge (br0/br10/br20). Ne laissez pas libvirt décider par accident.

Attacher une NIC de VM à un bridge (exemple)

cr0x@server:~$ virsh attach-interface --domain vm1 --type bridge --source br20 --model virtio --config
Interface attached successfully

Sens : La configuration persistante a changé. Vous devrez peut-être détacher l’ancienne NIC ou redémarrer selon la gestion du hotplug par l’invité.

Décision : Après modifications, vérifiez avec domiflist puis validez depuis la VM.

Confirmer que la NIC de la VM est bien là où prévu

cr0x@server:~$ virsh domiflist vm1
 Interface   Type     Source   Model    MAC
-------------------------------------------------------
 vnet3       bridge   br20     virtio   fe:54:00:aa:bb:cc

Sens : Vous êtes maintenant en pont sur br20. Si l’internet échoue encore, ce n’est pas parce que vous êtes resté accidentellement sur virbr0.

Décision : Continuez avec les contrôles VLAN et pare-feu.

Erreurs courantes : symptôme → cause racine → correction

1) La VM reçoit une IP mais ne peut pas pinger la passerelle

Symptôme : DHCP fonctionne, mais le ping premier saut échoue.
Cause racine : Le DHCP provient d’ailleurs (relay, VLAN erroné), ou la passerelle est dans un VLAN différent de celui effectif de la VM.
Correction : Capturez l’ARP sur vnet et sur l’uplink. Confirmez le tagging VLAN et le mode du port switch. Alignez l’access/native VLAN avec le bridge non taggé, ou taggez correctement le VLAN.

2) La VM peut pinger la passerelle mais pas les IP publiques

Symptôme : L2 est OK ; L3 au-delà de la passerelle échoue.
Cause racine : Problème de routage/NAT/ACL en amont, ou route par défaut erronée dans l’invité.
Correction : Vérifiez la table de routage de la VM. Vérifiez les ACL en amont. Si l’hôte fait routage/NAT, activez ip_forward et ajoutez des règles NAT intentionnellement.

3) La VM atteint les IP publiques mais le DNS échoue

Symptôme : ping 1.1.1.1 marche, ping d’un nom échoue.
Cause racine : DNS injoignables, resolv.conf/systemd-resolved mal configuré dans l’invité, ou UDP/TCP 53 bloqué.
Correction : Interrogez le DNS directement ; vérifiez le pare-feu pour UDP/TCP 53. Validez systemd-resolved dans l’invité.

4) Seuls certains VLANs fonctionnent ; d’autres sont morts

Symptôme : VLAN 10 OK, VLAN 20 mort sur toutes les VMs.
Cause racine : Le trunk switch autorise pas le VLAN 20, ou la table VLAN du bridge hôte manque l’appartenance pour VLAN 20.
Correction : Ajoutez le VLAN à la liste autorisée du switch et à la configuration VLAN de l’hôte. Vérifiez avec bridge vlan show et tcpdump avec filtre vlan.

5) Internet marche jusqu’au reboot ; ensuite les VMs sont isolées

Symptôme : Des modifications manuelles du bridge/VLAN ont marché, mais n’ont pas persisté.
Cause racine : Les commandes bridge en runtime n’ont pas été encodées dans netplan/systemd-networkd ; le reboot efface l’état.
Correction : Rendre la configuration déclarative (netplan + networkd drop-ins) et la versionner. Testez avec un reboot comme partie du changement.

6) L’hôte peut atteindre le réseau ; les VMs non

Symptôme : L’hôte ping fonctionne ; la VM ping échoue ; le bridge semble OK.
Cause racine : La policy forward de nftables droppe le forwarding des frames bridge, ou bridge netfilter interagit avec les règles du pare-feu.
Correction : Inspectez la chain forward de nft et les sysctls bridge-nf. Ajoutez des accept explicites pour les sous-réseaux/bridges VM.

7) Le trafic VM est intermittent ; ARP flappe

Symptôme : Parfois la passerelle est joignable ; parfois non ; les adresses MAC semblent migrer.
Cause racine : IP dupliquées, filtres anti-spoofing MAC sur le switch, ou plusieurs bridges uplinkés créant une boucle (et STP ne vous protège pas).
Correction : Cherchez des réponses ARP dupliquées, auditez les fonctions de sécurité du switch, et assurez-vous d’avoir exactement un chemin L2 vers le VLAN sauf si vous avez une redondance intentionnelle.

8) Tout fonctionne, mais les performances sont terribles

Symptôme : Latence élevée, faible débit, pertes sous charge.
Cause racine : Mismatch MTU (surtout avec le tagging VLAN), bizarreries d’offload, ou CPU hôte saturé par le pare-feu/conntrack sur le trafic bridge.
Correction : Vérifiez le MTU de bout en bout. Évaluez les paramètres d’offload. Ne mettez pas un pare-feu stateful inattendu dans le chemin de forwarding sans dimensionnement.

Checklists / plan étape par étape

Étape par étape : Construire un réseau VM en pont sur un seul VLAN (ennuyeux et correct)

  1. Choisissez Pattern A (non taggé) si vous n’avez besoin que d’un VLAN.
  2. Configurez netplan pour que la NIC physique n’ait pas d’IP et soit esclavagisée à br0.
  3. Appliquez netplan avec netplan try.
  4. Vérifiez : ip -br addr montre l’IP sur br0.
  5. Attachez la NIC de la VM à br0 (type bridge dans libvirt).
  6. Vérifiez : bridge link montre vnetX master br0.
  7. Testez dans la VM : ping passerelle, puis IP publique, puis DNS.
  8. En cas d’échec : tcpdump sur vnetX et l’uplink pour trouver la première trame manquante.

Étape par étape : Ajouter des VLANs sans rendre le futur-vous misérable

  1. Choisissez Pattern B sauf si vous avez une bonne raison pour le bridging conscient VLAN.
  2. Faites configurer le port switch en trunk avec une liste explicite de VLANs autorisés.
  3. Créez des sous-interfaces VLAN sur l’hôte (enp3s0.10, enp3s0.20).
  4. Créez des bridges par VLAN (br10, br20). Placez la gestion hôte sur un seul VLAN.
  5. Attachez les VMs au bridge correct pour leur VLAN. N’utilisez pas « br0 pour tout ».
  6. Documentez le mapping VLAN → bridge dans le dépôt qui stocke les configs netplan.
  7. Testez avec reboot. Toujours.

Checklist de validation (exécuter après chaque changement)

  • Hôte : appartenance au bridge correcte (bridge link).
  • Hôte : IP sur le bridge (ou sur l’interface VLAN du bridge, volontairement).
  • Hôte : appartenance VLAN alignée avec les attentes du port switch.
  • Hôte : le pare-feu autorise les flux requis dans la chaîne forward.
  • Invité : route + DNS corrects.
  • Paquet : ARP sort de la VM, sort de l’hôte, et les réponses reviennent.

Trois mini-récits d’entreprise depuis les tranchées réseau

Mini-récit n°1 : L’incident causé par une mauvaise hypothèse

Dans une organisation, un cluster de virtualisation était « standardisé » sur un uplink en trunk : VLAN 10 pour la gestion, VLAN 20 pour les workloads. L’ingénieur qui a construit le premier hôte a supposé que le port du switch avait un VLAN natif de 20 parce que « c’est ce que nous faisons d’habitude ». Ils ont construit le Pattern A : br0 non taggé, VMs attachées, aucun tagging VLAN nulle part.

Ça a fonctionné dans leur baie. Ça a échoué dans la baie suivante. Même modèle de serveur, même fichier netplan, même build hyperviseur. La moitié des VMs avait internet ; l’autre moitié ne pouvait même pas ARP la passerelle. L’équipe réseau jurait que rien n’avait changé. Puis quelqu’un a posé la seule question pertinente : « Les ports switch sont-ils réellement identiques ? »

Ils ne l’étaient pas. Une baie avait VLAN natif 20. Une autre avait VLAN natif 10. Une troisième n’avait pas du tout la même configuration native car un autre template avait été utilisé des mois plus tôt. Le trafic non taggé atterrissait là où le switch décidait, ce qui est une manière polie de dire « vous n’êtes pas maître de la situation ».

La réparation n’a pas été « plus d’essais » ou « nouvelles images VM ». Ils ont cessé de dépendre du comportement du VLAN natif. Ils sont passés au Pattern B : sous-interfaces VLAN explicites et bridges par VLAN. Cela a pris une fenêtre de maintenance, mais après cela, les baies ont cessé d’être des exceptions. Le postmortem a eu une ligne clé : les hypothèses sont une configuration, simplement non documentée.

Mini-récit n°2 : L’optimisation qui a foiré

Une autre organisation voulait réduire le nombre d’interfaces sur leurs hôtes. Ils avaient un bridge par VLAN, et quelqu’un a jugé que « trop d’appareils ». Ils sont passés à un bridge unique conscient des VLANs avec filtrage, configuré via des scripts runtime exécutés au boot. C’était propre : un bridge, uplink trunk, VMs affectées dynamiquement.

Puis le premier vrai incident : après une mise à jour du noyau et un reboot, un sous-ensemble d’hôtes est revenu avec des entrées VLAN manquantes sur certains ports vnet. Personne n’a tout de suite remarqué car les hôtes eux-mêmes fonctionnaient sur le VLAN de gestion. Mais les VMs locataires sur certains VLANs étaient isolées. Les symptômes étaient classiques : timeouts DHCP, ARP incomplet, pas d’accès à la passerelle.

La cause racine n’était pas que Linux « oubliait les VLANs ». C’était leur propre scripting et l’ordre d’exécution. systemd-networkd amenait le bridge, libvirt lançait les VMs tôt, et le script d’appartenance VLAN s’exécutait après que les VMs soient déjà attachées—sans rétro-assigner correctement les règles de port. Certaines ports avaient le PVID, d’autres pas. Une condition de course est devenue une politique réseau.

Ils sont revenus à Pattern B pour la plupart des clusters et ont conservé Pattern C seulement là où ils ont pu encoder les règles VLAN d’une manière déterministe, versionnée et sûre pour l’ordre de boot. L’optimisation n’a pas échoué parce que le bridging conscient VLAN est mauvais. Elle a échoué parce que la méthode de déploiement n’était pas assez ennuyeuse.

Mini-récit n°3 : La pratique ennuyeuse mais correcte qui a sauvé la mise

Une équipe de services financiers faisait tourner KVM sur Ubuntu avec networking en pont et VLAN. Rien de glamour. Mais ils avaient l’habitude suivante : après chaque changement réseau, ils exécutaient un script de validation standard qui capturait trois choses—appartenance au bridge, table VLAN, et la politique forward de nftables—et rangeaient la sortie avec le ticket de changement.

Un matin, un ensemble de VMs a perdu la connectivité sortante. L’hôte semblait « up ». Le bridge était « up ». Le port switch était « up ». C’est là que les équipes commencent à rebooter tout jusqu’à ce que quelque chose change. Ils ne l’ont pas fait. Ils ont comparé la dernière sortie connue bonne avec la sortie actuelle.

Le diff était petit et décisif : la policy forward était passée en drop, et la règle accept pour br0 → uplink avait disparu. Il s’est avéré qu’un rôle de durcissement hôte avait été mis à jour et appliqué largement ; il était correct pour des serveurs standalone et incorrect pour des hôtes de virtualisation qui forwardent du trafic bridge.

La correction a pris des minutes : ajouter la règle accept manquante (bien ciblée), redéployer le rôle de durcissement avec conscience du type d’hôte, et restaurer le service. La pratique ennuyeuse n’était pas du génie. C’était simplement de l’évidence. L’évidence bat la panique à chaque fois.

FAQ

1) Dois-je utiliser NetworkManager ou systemd-networkd sur des serveurs Ubuntu 24.04 ?

Utilisez systemd-networkd (via netplan) pour les serveurs sauf si vous avez une raison spécifique de standardiser sur NetworkManager. Les mélanges sont la source de « configs fantômes ».

2) Ma VM est attachée à br0, mais elle utilise encore des adresses 10.0.2.0/24. Pourquoi ?

C’est typiquement le NAT libvirt (réseau par défaut). Vérifiez virsh domiflist. Si la source est default et le type est network, vous n’êtes pas en pont.

3) Ai-je besoin de STP sur un bridge Linux ?

Généralement non pour un uplink unique, un bridge unique, sans boucles. STP peut ajouter des délais de forwarding et de la confusion. Activez-le seulement si vous savez avoir des chemins L2 redondants et voulez la protection.

4) Quelle est la façon la plus nette de placer des VMs dans différents VLANs ?

Les bridges par VLAN (Pattern B) sont les plus propres opérationnellement. Le bridge conscient VLAN (Pattern C) est puissant mais demande une configuration plus disciplinée.

5) L’invité peut-il faire lui-même le tagging VLAN ?

Oui. Vous pouvez présenter un trunk à une VM et la laisser créer des sous-interfaces VLAN côté invité. C’est approprié pour des appliances routeur/pare-feu ou des nœuds Kubernetes qui gèrent leurs propres VLANs. Pour des VMs ordinaires, gardez la logique VLAN sur l’hôte ou le réseau en amont.

6) Pourquoi DHCP marche mais ARP vers la passerelle échoue ?

Parce que DHCP peut réussir via des relais ou des acceptations mal taggées d’une manière qui ne garantit pas l’adjacence L2 à la passerelle. Prouvez la correction VLAN avec tcpdump et l’état ARP, pas avec « elle a eu une IP ».

7) Est-il sûr de filtrer le trafic VM avec nftables sur l’hôte ?

Oui, si vous le faites intentionnellement et comprenez si les trames bridgées traversent iptables/nftables via les réglages bridge-nf. La version dangereuse est « policy drop » sans accepts de forwarding.

8) Comment savoir si le problème vient du port switch ou de l’hôte ?

Capturez de chaque côté du bridge hôte : interface vnet et uplink physique. Si les paquets sortent de vnet mais pas de l’uplink, c’est côté hôte. S’ils sortent de l’uplink mais que les réponses ne reviennent jamais, c’est en amont (switch/VLAN/ACL).

9) Mon hôte doit-il avoir une adresse IP sur chaque VLAN utilisé par mes VMs ?

Non. Dans un design purement L2 en pont, l’hôte n’a pas besoin d’une présence L3 sur les VLANs VM. Ajoutez des IP hôtes seulement quand vous avez un besoin opérationnel clair (monitoring, routage, services) et pouvez le sécuriser.

10) Qu’en est-il du MTU et du surcoût VLAN ?

Le tag 802.1Q ajoute de l’overhead ; des MTU mismatches peuvent provoquer des échecs partiels (surtout si PMTUD est bloqué). Si vous utilisez des jumbo frames, vérifiez le MTU de bout en bout sur la NIC hôte, le bridge, la NIC VM et le port du switch.

Conclusion : prochaines étapes qui ne feront pas de mal plus tard

Si votre VM Ubuntu 24.04 « n’a pas d’internet », résistez à la tentation de tout reconfigurer d’un coup. Votre travail est de trouver le premier saut brisé, puis de corriger le design pour qu’il reste corrigé.

  1. Choisissez un pattern : A (non taggé), B (bridges par VLAN), ou C (bridge conscient VLAN). Ne les mélangez pas à la légère.
  2. Rendez la configuration hôte déclarative : netplan + networkd, appliqué avec netplan try.
  3. Prouvez l’appartenance au bridge : interface vnet sur le bon bridge ; uplink physique attaché.
  4. Prouvez la réalité VLAN : la table VLAN du bridge correspond au mode du port switch et aux VLANs autorisés.
  5. Prouvez que le forwarding n’est pas bloqué : chaîne forward nftables et réglages bridge-nf alignés avec votre intention.
  6. Opérationnalisez la validation : gardez un petit ensemble de commandes à lancer après chaque changement et conservez les sorties.

En procédant ainsi, « la VM n’a pas d’internet » cesse d’être un mystère et redevient ce qu’elle aurait dû être : un exercice d’isolation de panne simple avec une correction permanente à la fin.

← Précédent
Checkpoint zpool ZFS : le bouton d’annulation d’urgence (aux bords tranchants)
Suivant →
Ubuntu 24.04 « Échec de démarrage … » : le flux de triage systemd le plus rapide (cas n°2)

Laisser un commentaire