devis switch : une interface, un bloc

La partie A déclarait ses ports de bord deux fois — l'interface en section
4, son portfast en section 6 — alors que la partie B posait tout dans le
même bloc. Deux conventions pour la même chose dans un seul document.

Le portfast est posé avec son interface (sections 4 et 4b). La section 6 se
réduit au global — mode, priorité du pont racine — plus les deux
avertissements : les rayons de la 4c n'en sont volontairement pas, et
pourquoi BPDU guard n'est pas émis.

Vérifié : aucune interface déclarée deux fois dans une même partie,
3 portfast avec `stp`, 0 sans lui, 0 sur un rayon.

Preuves : 24 OK, 0 échec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-08-01 21:35:32 -04:00
parent 92d31c0406
commit f80b53b592
2 changed files with 30 additions and 16 deletions

View file

@ -1,5 +1,20 @@
# CHANGELOG — Set-OPS # CHANGELOG — Set-OPS
## 2026-08-01 (suite 10) — une interface, un bloc
La partie A déclarait ses ports de bord deux fois : l'interface en section 4, son `portfast`
en section 6. La partie B, elle, posait tout dans le même bloc. Deux conventions pour la même
chose dans un seul document — un opérateur qui applique la partie A section par section
configurait la même interface à deux endroits.
Le `portfast` est désormais posé **avec son interface** (sections 4 et 4b). La section 6 se
réduit à ce qui est global — mode, priorité du pont racine — plus les deux avertissements :
que les rayons de la section 4c n'en sont volontairement pas, et pourquoi BPDU guard n'est
pas émis.
Vérifié : aucune interface n'est déclarée deux fois dans une même partie, trois `portfast`
avec `stp`, zéro sans lui, zéro sur un rayon.
## 2026-08-01 (suite 9) — rayons de l'étoile séparés des ports terminaux ## 2026-08-01 (suite 9) — rayons de l'étoile séparés des ports terminaux
L'ajout du spanning-tree venait de rendre dangereuse une imprécision qui, jusque-là, n'était L'ajout du spanning-tree venait de rendre dangereuse une imprécision qui, jusque-là, n'était

View file

@ -142,7 +142,7 @@ def _stp_lignes(dialecte: str, mode: str, priorite: int) -> list[str]:
return [f"spanning-tree mode {mode}", f"spanning-tree priority {priorite}"] return [f"spanning-tree mode {mode}", f"spanning-tree priority {priorite}"]
def section_stp(underlay: dict | None, dialecte: str, ports_bord: list[str]) -> list[str]: def section_stp(underlay: dict | None, dialecte: str) -> list[str]:
"""Spanning-tree du switch routeur : il est la racine, par construction. """Spanning-tree du switch routeur : il est la racine, par construction.
En etoile, tous les chemins passent deja par le centre : en faire le pont racine En etoile, tous les chemins passent deja par le centre : en faire le pont racine
@ -164,15 +164,11 @@ def section_stp(underlay: dict | None, dialecte: str, ports_bord: list[str]) ->
"! le decider — l'arbre logique suit alors le cablage physique.", "! le decider — l'arbre logique suit alors le cablage physique.",
"! Aucun lien redondant en etoile : RSTP est un filet, pas une necessite."] "! Aucun lien redondant en etoile : RSTP est un filet, pas une necessite."]
out += _stp_lignes(dialecte, mode, underlay_mod.STP_PRIORITE_RACINE) out += _stp_lignes(dialecte, mode, underlay_mod.STP_PRIORITE_RACINE)
if ports_bord:
out += ["!", out += ["!",
"! Ports terminaux (hyperviseurs, frontiere) : rien derriere eux ne", "! Les ports de bord sont declares AVEC leur interface (sections 4 et 4b),",
"! participe a l'arbre. Les declarer en bord evite d'attendre la", "! pas ici : chaque interface se lit d'un seul tenant. Les rayons de la",
"! convergence a chaque montee de lien."] "! section 4c n'en sont volontairement pas.",
for p in ports_bord: "! BPDU guard non emis volontairement : un pont Linux dont le STP serait",
out += [f"interface {p}",
" spanning-tree portfast trunk"]
out += ["! BPDU guard non emis volontairement : un pont Linux dont le STP serait",
"! active enverrait des BPDU et ferait tomber le port cote hyperviseur.", "! active enverrait des BPDU et ferait tomber le port cote hyperviseur.",
"! Ne l'ajouter qu'apres avoir verifie que ces ponts n'en emettent pas."] "! Ne l'ajouter qu'apres avoir verifie que ces ponts n'en emettent pas."]
out.append("!") out.append("!")
@ -263,7 +259,7 @@ def partie_acces(underlay: dict | None, tenants: list, vlans: str,
return out return out
def section_frontiere(transit: dict | None) -> list[str]: def section_frontiere(transit: dict | None, bord: bool = False) -> list[str]:
"""Port du switch vers le pare-feu de bordure. Porte le VLAN de transit, et lui seul. """Port du switch vers le pare-feu de bordure. Porte le VLAN de transit, et lui seul.
Distinct du trunk vers Proxmox : les hyperviseurs n'ont aucune interface sur le Distinct du trunk vers Proxmox : les hyperviseurs n'ont aucune interface sur le
@ -277,10 +273,11 @@ def section_frontiere(transit: dict | None) -> list[str]:
"! ----- 4b. Port vers la frontiere nord/sud -----", "! ----- 4b. Port vers la frontiere nord/sud -----",
f"! Porte le seul VLAN {transit['vlan']} ({transit['nom']}). En lien dedie,", f"! Porte le seul VLAN {transit['vlan']} ({transit['nom']}). En lien dedie,",
f"! remplacer par : switchport access vlan {transit['vlan']}.", f"! remplacer par : switchport access vlan {transit['vlan']}.",
"! Port terminal : rien derriere lui ne participe au spanning-tree.",
"interface <PORT-VERS-FRONTIERE>", "interface <PORT-VERS-FRONTIERE>",
" switchport mode trunk", " switchport mode trunk",
f" switchport trunk allowed vlan add {transit['vlan']}", f" switchport trunk allowed vlan add {transit['vlan']}",
] ] + ([" spanning-tree portfast trunk"] if bord else [])
def section_routes(underlay: dict | None) -> list[str]: def section_routes(underlay: dict | None) -> list[str]:
@ -445,10 +442,12 @@ def generer(tenants: list[tuple[str, str, dict]], dialecte: str | None = None) -
out.append("interface <PORT-VERS-PROXMOX>") out.append("interface <PORT-VERS-PROXMOX>")
out.append(" switchport mode trunk") out.append(" switchport mode trunk")
out.append(f" switchport trunk allowed vlan add {vlans}") out.append(f" switchport trunk allowed vlan add {vlans}")
out += ["!"] + section_frontiere(transit) if underlay_mod.stp(underlay):
out.append(" spanning-tree portfast trunk")
out += ["!"] + section_frontiere(transit, bord=bool(underlay_mod.stp(underlay)))
out += ["!"] + section_rayons(underlay, ",".join(vlans_underlay + vlans_tenants)) out += ["!"] + section_rayons(underlay, ",".join(vlans_underlay + vlans_tenants))
out += ["!"] + section_routes(underlay) out += ["!"] + section_routes(underlay)
out += section_stp(underlay, dialecte, ["<PORT-VERS-PROXMOX>", "<PORT-VERS-FRONTIERE>"]) out += section_stp(underlay, dialecte)
out += ["end", "write memory"] out += ["end", "write memory"]
# Les switches d'acces : memes VLANs, aucun SVI de zone, aucune ACL, aucune route. # Les switches d'acces : memes VLANs, aucun SVI de zone, aucune ACL, aucune route.
out += partie_acces(underlay, tenants, ",".join(vlans_underlay + vlans_tenants), dialecte) out += partie_acces(underlay, tenants, ",".join(vlans_underlay + vlans_tenants), dialecte)