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:
parent
6a80e5b55c
commit
89dc5ed3d4
4 changed files with 56 additions and 11 deletions
26
CHANGELOG.md
26
CHANGELOG.md
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue