underlay : le MTU du modèle était faux, et la garde le validait

En préparant le déplacement des VTEP, la lecture des interfaces a montré que
`underlay.yml` annonçait 9000 alors que vmbr3 est à 1500. La garde P23
exigeait >= 1550 et passait parce que le fichier mentait. Une garde qui
valide une déclaration plutôt qu'une réalité donne un faux confort — pire
qu'une garde absente, qui au moins n'endort personne.

Le seuil ne peut pas être fixe non plus : 1550 aurait rejeté à tort un
transport à 1500 portant un overlay à 1450, qui tient exactement. Il dérive
d'un `mtu_overlay` déclaré : transport >= overlay + 50. Exercé.

Trouvé aussi : vmbr3 n'est pas VLAN-aware. L'adresse du VTEP y est non
étiquetée et vit dans le VLAN natif du port. Déplacer le VTEP n'est donc pas
un changement d'adresse — il faut un VLAN natif 10 ou une interface étiquetée
dédiée. C'est pourquoi le déplacement n'a pas été effectué.

Preuves : 24 OK, 0 échec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-03 10:28:16 -04:00
parent 6a80e5b55c
commit 89dc5ed3d4
4 changed files with 56 additions and 11 deletions

View file

@ -1,5 +1,31 @@
# CHANGELOG — Set-OPS # CHANGELOG — Set-OPS
## 2026-08-03 (suite 7) — le modèle déclarait un MTU que le matériel n'a pas
En préparant le déplacement des adresses de VTEP, la lecture des interfaces a montré deux
choses que le modèle ignorait.
### `underlay.yml` annonçait 9000, `vmbr3` est à 1500
La garde P23 validait donc **une déclaration fausse** : elle exigeait ≥ 1550 et passait parce
que le fichier disait 9000. **Une garde qui valide une déclaration plutôt qu'une réalité donne
un faux confort** — c'est pire qu'une garde absente, qui au moins n'endort personne.
Le seuil ne peut pas non plus être fixe : 1550 aurait rejeté à tort un transport à 1500
portant un overlay à 1450, qui tient exactement. Il **dérive** désormais d'un
`mtu_overlay` déclaré (1450 par défaut) : transport ≥ overlay + 50.
Le fichier dit maintenant la vérité — 1500 — et la garde passe pour la bonne raison. Exercé :
un overlay porté à 1500 sur ce transport est refusé.
### `vmbr3` n'est pas *VLAN-aware*
Pas de `bridge_vlan_aware`, contrairement à `vmbr2`. L'adresse du VTEP y est **non
étiquetée** : elle vit dans le VLAN natif du port de commutateur. Déplacer le VTEP vers
l'underlay n'est donc pas un changement d'adresse — il faut soit un VLAN natif 10, soit une
interface étiquetée dédiée (`bond3.10`).
C'est la raison pour laquelle le déplacement n'a **pas** été effectué : le geste demandé
suppose une décision de câblage qui n'est pas prise.
## 2026-08-03 (suite 6) — les hyperviseurs entrent au modèle, à leur adresse cible ## 2026-08-03 (suite 6) — les hyperviseurs entrent au modèle, à leur adresse cible
Redresser les pairs EVPN vers l'underlay suppose d'abord que les hyperviseurs **existent dans Redresser les pairs EVPN vers l'underlay suppose d'abord que les hyperviseurs **existent dans

View file

@ -91,8 +91,8 @@ le tenant : c'est le genre de configuration qui s'applique sans erreur et ne fon
lien de transit, donc la sortie de l'**underlay**, indépendante du routage tenant. Ce sont lien de transit, donc la sortie de l'**underlay**, indépendante du routage tenant. Ce sont
deux choses distinctes qu'il ne faut pas confondre. deux choses distinctes qu'il ne faut pas confondre.
**L'overlay est plafonné à 1450** (décision du 2026-08-03), donc le transport doit dépasser **L'overlay est plafonné à 1450** (décision du 2026-08-03) parce que le transport réel — le
1500. Conséquence à ne pas manquer : sous 1500, **tout ce qui traverse la frontière dépend de pont `vmbr3` des hyperviseurs — est à **1500** : 1450 + 50 de VXLAN y tient exactement. Conséquence à ne pas manquer : sous 1500, **tout ce qui traverse la frontière dépend de
la découverte de MTU de chemin**, qui a besoin de l'ICMP « fragmentation nécessaire ». la découverte de MTU de chemin**, qui a besoin de l'ICMP « fragmentation nécessaire ».
Or le registre des flux ne connaissait que TCP et UDP : ce message ne pouvait pas être Or le registre des flux ne connaissait que TCP et UDP : ce message ne pouvait pas être
@ -154,6 +154,11 @@ garde détecte la faute avant qu'on ne la documente.
dernier octet conservé comme sur `vmbr0`. Le déplacement réel de l'adresse sur les nœuds reste dernier octet conservé comme sur `vmbr0`. Le déplacement réel de l'adresse sur les nœuds reste
à faire : c'est une modification du réseau d'un hyperviseur en service. à faire : c'est une modification du réseau d'un hyperviseur en service.
**Le pont `vmbr3` n'est pas *VLAN-aware*** (pas de `bridge_vlan_aware`, contrairement à
`vmbr2`). L'adresse du VTEP y est donc **non étiquetée** : elle vit dans le VLAN natif du port
de commutateur. Déplacer le VTEP vers l'underlay suppose soit un VLAN natif 10, soit une
interface étiquetée dédiée (`bond3.10`) — ce n'est pas qu'un changement d'adresse.
**`vishnu` n'est pas câblé.** Son `vmbr3` n'a **aucun port physique** : le pont existe, porte **`vishnu` n'est pas câblé.** Son `vmbr3` n'a **aucun port physique** : le pont existe, porte
une adresse, et ne mène nulle part. Un pair VXLAN pointé sur lui ne fonctionnera jamais. une adresse, et ne mène nulle part. Un pair VXLAN pointé sur lui ne fonctionnera jamais.

View file

@ -82,10 +82,18 @@ STP_TOPOLOGIES = ("etoile", "anneau", "maille")
ROUTAGE_TENANTS = ("switch", "sdn") ROUTAGE_TENANTS = ("switch", "sdn")
# VXLAN ajoute 50 octets d'encapsulation. Sous ce seuil, le transport casse # VXLAN coute 50 octets d'encapsulation : le TRANSPORT doit valoir au moins l'overlay
# PARTIELLEMENT : le ping passe, les transferts echouent — la panne la plus couteuse # plus cette surcharge. Sous ce seuil, il casse PARTIELLEMENT — le ping passe, les
# a diagnostiquer. On refuse donc un underlay qui ne peut pas porter le SDN. # transferts echouent — la panne la plus couteuse a diagnostiquer.
MTU_MINIMAL_VXLAN = 1550 SURCOUT_VXLAN = 50
MTU_OVERLAY_DEFAUT = 1450 # ce que voit une VM ; regle par zone dans Proxmox SDN
def mtu_overlay(underlay: dict | None) -> int:
"""MTU annonce aux VM par les VNet. Declare, parce qu'il commande le minimum du
transport : un overlay a 1450 tient dans un transport a 1500, pas un overlay a 1500."""
v = (underlay or {}).get("mtu_overlay")
return int(v) if isinstance(v, int) else MTU_OVERLAY_DEFAUT
def routage_tenants(underlay: dict | None) -> str: def routage_tenants(underlay: dict | None) -> str:
@ -386,15 +394,16 @@ def valider(underlay: dict | None,
if rt is not None and str(rt) not in ROUTAGE_TENANTS: if rt is not None and str(rt) not in ROUTAGE_TENANTS:
erreurs.append(f"routage_tenants '{rt}' inconnu (attendu : {', '.join(ROUTAGE_TENANTS)})") erreurs.append(f"routage_tenants '{rt}' inconnu (attendu : {', '.join(ROUTAGE_TENANTS)})")
if routage_tenants(underlay) == "sdn": if routage_tenants(underlay) == "sdn":
# Le transport du VXLAN doit encaisser l'encapsulation, sinon panne partielle. # Le transport doit valoir l'overlay DECLARE plus la surcharge d'encapsulation.
minimal = mtu_overlay(underlay) + SURCOUT_VXLAN
fab = fabric_du_routeur(underlay) fab = fabric_du_routeur(underlay)
for r in reseaux_de_fabric(underlay, fab): for r in reseaux_de_fabric(underlay, fab):
mtu = int(r.get("mtu") or 1500) mtu = int(r.get("mtu") or 1500)
if mtu < MTU_MINIMAL_VXLAN: if mtu < minimal:
erreurs.append( erreurs.append(
f"reseau '{r.get('nom','?')}': MTU {mtu} < {MTU_MINIMAL_VXLAN} alors que " f"reseau '{r.get('nom','?')}': MTU {mtu} < {minimal} "
f"`routage_tenants: sdn` — VXLAN ajoute 50 octets ; sous ce seuil le ping " f"(overlay {mtu_overlay(underlay)} + {SURCOUT_VXLAN} de VXLAN) — sous ce "
f"passe et les transferts echouent") f"seuil le ping passe et les transferts echouent")
d = dialecte(underlay) d = dialecte(underlay)
if d and d not in DIALECTES: if d and d not in DIALECTES:

View file

@ -35,6 +35,11 @@ underlay:
# MTU >= 1550 (VXLAN ajoute 50 octets) — `make underlay` le refuse sinon. # MTU >= 1550 (VXLAN ajoute 50 octets) — `make underlay` le refuse sinon.
#routage_tenants: switch #routage_tenants: switch
# MTU annonce aux VM par les VNet, en mode `sdn`. Il commande le minimum du TRANSPORT :
# `make underlay` refuse un reseau de fabric sous `mtu_overlay + 50` (surcout VXLAN).
# 1450 tient dans un transport a 1500 ; viser 1500 d'overlay exige du jumbo.
#mtu_overlay: 1450
# Isolation inter-tenant par ACL de commutateur. `true` par defaut. # Isolation inter-tenant par ACL de commutateur. `true` par defaut.
# Mettre `false` quand le materiel ne sait pas lier une ACL a une interface de # Mettre `false` quand le materiel ne sait pas lier une ACL a une interface de
# routage : le devis cesse alors d'emettre des ACL qui ne seraient jamais liees. # routage : le devis cesse alors d'emettre des ACL qui ne seraient jamais liees.