vlsm.py

Note de lecture générée automatiquement

Le vrai fichier est scripts/reseaux/vlsm.py (Obsidian n’affiche pas les scripts eux-mêmes). Ne modifie pas cette note : modifie le script, puis relance python3 generer_vues_obsidian.py dans le dossier scripts.

Code

#!/usr/bin/env python3
"""
vlsm.py — Calculateur VLSM (découpage en sous-réseaux de tailles différentes).
 
Utilisation :
    python3 vlsm.py 192.168.1.0/24 Commercial=100 Compta=50 Serveurs=25 Liaison=2
 
Le script applique la règle d'or : du PLUS GROS besoin au PLUS PETIT.
Il affiche un tableau prêt à recopier dans un compte rendu.
"""
import ipaddress
import math
import sys
 
 
def prefixe_necessaire(nb_hotes: int) -> int:
    # On cherche le plus petit nombre de bits hôte tel que 2^bits - 2 >= besoin
    bits_hote = max(2, math.ceil(math.log2(nb_hotes + 2)))
    return 32 - bits_hote
 
 
def calculer_vlsm(reseau_depart: str, besoins: dict) -> None:
    reseau = ipaddress.ip_network(reseau_depart, strict=True)
    adresse_courante = int(reseau.network_address)
 
    entete = f"{'Nom':<14}{'Besoin':>7}  {'Réseau':<19}{'Masque':<17}{'1re IP':<16}{'Dernière IP':<16}{'Broadcast':<16}{'Dispo':>6}"
    print(entete)
    print("-" * len(entete))
 
    for nom, nb_hotes in sorted(besoins.items(), key=lambda b: b[1], reverse=True):
        prefixe = prefixe_necessaire(nb_hotes)
        sous_reseau = ipaddress.ip_network(f"{ipaddress.ip_address(adresse_courante)}/{prefixe}")
        if not sous_reseau.subnet_of(reseau):
            sys.exit(f"\nErreur : plus assez d'adresses pour '{nom}' ({nb_hotes} hôtes).")
        hotes = list(sous_reseau.hosts())
        print(f"{nom:<14}{nb_hotes:>7}  {str(sous_reseau):<19}{str(sous_reseau.netmask):<17}"
              f"{str(hotes[0]):<16}{str(hotes[-1]):<16}{str(sous_reseau.broadcast_address):<16}{len(hotes):>6}")
        adresse_courante = int(sous_reseau.broadcast_address) + 1
 
    fin = int(reseau.broadcast_address)
    if adresse_courante <= fin:
        print(f"\nEspace encore libre : {ipaddress.ip_address(adresse_courante)} -> {reseau.broadcast_address}"
              f" ({fin - adresse_courante + 1} adresses)")
 
 
if __name__ == "__main__":
    if len(sys.argv) < 3:
        sys.exit(__doc__)
    besoins_saisis = {}
    for argument in sys.argv[2:]:
        nom, valeur = argument.split("=")
        besoins_saisis[nom] = int(valeur)
    calculer_vlsm(sys.argv[1], besoins_saisis)