From f80b53b592ddfec77f06a752598e1db506f9982a Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sat, 1 Aug 2026 21:35:32 -0400 Subject: [PATCH] devis switch : une interface, un bloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- CHANGELOG.md | 15 +++++++++++++++ scripts/devis_reseau.py | 31 +++++++++++++++---------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 953a23d..289cf7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # 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 L'ajout du spanning-tree venait de rendre dangereuse une imprécision qui, jusque-là, n'était diff --git a/scripts/devis_reseau.py b/scripts/devis_reseau.py index 5c9430b..7937411 100644 --- a/scripts/devis_reseau.py +++ b/scripts/devis_reseau.py @@ -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}"] -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. En etoile, tous les chemins passent deja par le centre : en faire le pont racine @@ -164,17 +164,13 @@ def section_stp(underlay: dict | None, dialecte: str, ports_bord: list[str]) -> "! le decider — l'arbre logique suit alors le cablage physique.", "! Aucun lien redondant en etoile : RSTP est un filet, pas une necessite."] out += _stp_lignes(dialecte, mode, underlay_mod.STP_PRIORITE_RACINE) - if ports_bord: - out += ["!", - "! Ports terminaux (hyperviseurs, frontiere) : rien derriere eux ne", - "! participe a l'arbre. Les declarer en bord evite d'attendre la", - "! convergence a chaque montee de lien."] - for p in ports_bord: - 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.", - "! Ne l'ajouter qu'apres avoir verifie que ces ponts n'en emettent pas."] + out += ["!", + "! Les ports de bord sont declares AVEC leur interface (sections 4 et 4b),", + "! pas ici : chaque interface se lit d'un seul tenant. Les rayons de la", + "! section 4c n'en sont volontairement pas.", + "! BPDU guard non emis volontairement : un pont Linux dont le STP serait", + "! 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."] out.append("!") return out @@ -263,7 +259,7 @@ def partie_acces(underlay: dict | None, tenants: list, vlans: str, 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. 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 -----", f"! Porte le seul VLAN {transit['vlan']} ({transit['nom']}). En lien dedie,", f"! remplacer par : switchport access vlan {transit['vlan']}.", + "! Port terminal : rien derriere lui ne participe au spanning-tree.", "interface ", " switchport mode trunk", f" switchport trunk allowed vlan add {transit['vlan']}", - ] + ] + ([" spanning-tree portfast trunk"] if bord else []) 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 ") out.append(" switchport mode trunk") 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_routes(underlay) - out += section_stp(underlay, dialecte, ["", ""]) + out += section_stp(underlay, dialecte) out += ["end", "write memory"] # 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)