← Alle Scripts

// Bash-Scripts

VLAN-Range in Subnetze aufteilen

Berechnet aus einer VLAN-ID-Range die zugehoerigen Subnetze (Praefixlaenge frei waehlbar, Default /27) anhand einer festen VLAN-zu-Subnetz-Zuordnung.

Netzwerk
Version2.1.3
Stand2026-07-11
Getestet aufGetestet auf einem Arch Linux x86_64
LizenzMIT
Brauchtbash 5
Umfang185 Zeilen · 5.8 KB
SHA256 2f99d7a8a9f45d171758187d639d26220c41cee851698fab25163ba9e275b2b2 Nach dem Download prüfen: echo "2f99d7a8a9f45d171758187d639d26220c41cee851698fab25163ba9e275b2b2 netdivide.sh" | sha256sum -c

Erst lesen, dann laufen lassen. Der vollständige Quelltext steht weiter unten auf dieser Seite. Einen curl … | bash-Einzeiler gibt es hier bewusst nicht.

Nutzung auf eigene Gefahr — keine Haftung für Datenverlust oder Systemschäden. Siehe Nutzungsbedingungen.

Wofür das Script gut ist

In manchen Netzen ist jede VLAN-ID fest einem eigenen Subnetz zugeordnet — eine Konvention, die das Nachschlagen in Doku oder Excel-Tabelle spart, aber im Kopf trotzdem Rechnerei bedeutet, sobald man mit einer ganzen Range von VLANs oder mit unterschiedlichen Subnetzgrößen arbeitet. Das Script macht diese Umrechnung in einem Schritt.

Was es macht

  • Rechnet aus einer VLAN-Range (START-VLAN END-VLAN) die zugehörigen Subnetze aus.
  • Zeigt Start-Netz, End-Netz und die Anzahl benötigter /24-Einheiten an.
  • Basis-Netz (--base), Anchor-VLAN (--anchor, die VLAN-ID, die auf x.x.0.0/PRAEFIX

zeigt) und Präfixlänge (--prefix, 8 bis 30, Default 27) sind frei einstellbar.

  • Warnt, wenn die Range das dritte Oktett sprengt (Basis-Netz oder Präfix zu klein).
  • Liefert mit --completion eine Bash-Autocompletion für die eigenen Optionen mit (per

source <(netdivide.sh --completion) einbinden oder dauerhaft nach /etc/bash_completion.d/ legen).

Wie es das umsetzt

Statt einer Lookup-Tabelle rechnet das Script die Position rein arithmetisch aus. Jede VLAN-ID bekommt einen Index relativ zur Anchor-VLAN, und aus diesem Index ergibt sich die Lage im Adressraum direkt über Ganzzahl-Division und Modulo — abhängig davon, ob das Subnetz kleiner oder größer als ein /24 ist:

local block_size=$(( 2 ** (32 - prefix) ))

if [ "$prefix" -ge 24 ]; then
    local per_24=$(( 256 / block_size ))
    s_third=$(( s_idx / per_24 ))
    s_fourth=$(( (s_idx % per_24) * block_size ))
else
    local step3=$(( block_size / 256 ))
    s_third=$(( s_idx * step3 ))
    s_fourth=0
fi

Ab /24 passt das Subnetz komplett ins vierte Oktett, wie bei den klassischen /27- oder /26-User-Netzen. Ist das Präfix kleiner als /24 (z. B. /23 oder /22), ist das Subnetz größer als ein /24 und belegt mehrere Einheiten im dritten Oktett — dann bleibt das vierte Oktett bei 0, und die Schrittweite im dritten Oktett wächst entsprechend. Beide Fälle laufen auf dieselbe Grundidee hinaus: keine Tabelle pflegen, sondern die Lage aus der Definition der Anchor-VLAN und der Blockgröße herleiten.

Warum ich das automatisiert habe

Es kam schon öfter vor, dass ich ich eine Anzahl an /27-Subnetzen oder anderen ausrechnen musste, weil VLANs alle ein eigenes Interface bekommen musste. Und weil ich das zu unübersichtlich fand mit einem Taschenrechner auszurechnen, hatte ich es einmal für einfache Nutzung in ein Skript eingebaut und und ergänzt habe.

Aufruf

bash netdivide.sh --help
bash netdivide.sh 1001 1008
bash netdivide.sh --prefix 26 1001 1008
source <(bash netdivide.sh --completion)   # Bash-Autocompletion laden

Quelltext

netdivide.sh
#!/usr/bin/env bash
#
#  netdivide.sh - teilt eine VLAN-Range in gleich grosse Subnetze auf
#
#  Autor:   Matthias Meister — https://scripts.web.mm-core.de
#  Version: 2.0.0
#
#  Lizenz:  MIT — Copyright (c) 2026 Matthias Meister
#           Volltext: https://scripts.web.mm-core.de/lizenz/
#
set -euo pipefail

readonly VERSION="2.0.0"
readonly MIN_PREFIX=8
readonly MAX_PREFIX=30

usage() {
    cat <<'EOF'
netdivide.sh - teilt eine VLAN-Range in gleich grosse Subnetze auf

Nutzung:
  netdivide.sh [OPTIONEN] START-VLAN END-VLAN

Optionen:
  -b, --base   NETZ   Basis-Netz (erste zwei Oktette). Default: 10.100
  -a, --anchor VLAN   VLAN-ID, die auf das erste Subnetz (x.x.0.0/PRAEFIX)
                      zeigt. Default: 1001
  -p, --prefix N      CIDR-Praefixlaenge des Subnetzes je VLAN. Default: 27
                      Erlaubt: 8-30
  -h, --help          Diese Hilfe anzeigen
  -V, --version       Versionsnummer anzeigen

Logik:
  Jede VLAN-ID bekommt genau ein Subnetz der Groesse 2^(32-Praefix).

  Bei Praefix 24-30 passt das Subnetz ins vierte Oktett:
      Index      = VLAN - Anchor
      pro /24    = 256 / Blockgroesse
      3. Oktett  = Index / pro_24
      4. Oktett  = (Index % pro_24) * Blockgroesse

  Bei Praefix 8-23 ist das Subnetz groesser als ein /24 und belegt mehrere
  Einheiten im dritten Oktett:
      Schrittweite = Blockgroesse / 256
      3. Oktett    = Index * Schrittweite
      4. Oktett    = 0

Beispiele:
  netdivide.sh 1001 1008
      -> /27-Netze (Default), 10.100.0.0/27 bis 10.100.0.224/27
  netdivide.sh --prefix 26 1001 1008
      -> /26-Netze, je 64 Adressen
  netdivide.sh --prefix 23 --base 10.200 --anchor 2001 2001 2010
      -> /23-Netze, je 512 Adressen ueber zwei Einheiten im 3. Oktett

Exit-Codes:
  0  alles gut
  1  inhaltliches Problem (z. B. END-VLAN < START-VLAN)
  2  Aufruffehler (falsche/fehlende Argumente)
EOF
}

main() {
    local base_net="10.100"
    local anchor_vlan=1001
    local prefix=27
    local positional=()

    while [ "$#" -gt 0 ]; do
        case "$1" in
            -h|--help)
                usage
                return 0
                ;;
            -V|--version)
                echo "netdivide.sh ${VERSION}"
                return 0
                ;;
            -b|--base)
                [ "$#" -ge 2 ] || { echo "FEHLER: --base benoetigt ein Argument." >&2; return 2; }
                base_net="$2"
                shift 2
                ;;
            -a|--anchor)
                [ "$#" -ge 2 ] || { echo "FEHLER: --anchor benoetigt ein Argument." >&2; return 2; }
                anchor_vlan="$2"
                shift 2
                ;;
            -p|--prefix)
                [ "$#" -ge 2 ] || { echo "FEHLER: --prefix benoetigt ein Argument." >&2; return 2; }
                prefix="$2"
                shift 2
                ;;
            --)
                shift
                while [ "$#" -gt 0 ]; do
                    positional+=("$1")
                    shift
                done
                ;;
            -*)
                echo "FEHLER: Unbekannte Option '$1'" >&2
                echo "Hilfe:  netdivide.sh --help" >&2
                return 2
                ;;
            *)
                positional+=("$1")
                shift
                ;;
        esac
    done
    set -- "${positional[@]}"

    if [ "$#" -ne 2 ]; then
        echo "FEHLER: Bitte START- und END-VLAN angeben." >&2
        echo "Hilfe:  netdivide.sh --help" >&2
        return 2
    fi

    local start_vlan="$1" end_vlan="$2"

    if ! [[ "$start_vlan" =~ ^[0-9]+$ && "$end_vlan" =~ ^[0-9]+$ && "$anchor_vlan" =~ ^[0-9]+$ ]]; then
        echo "FEHLER: VLAN-IDs und Anchor-VLAN muessen ganze Zahlen sein." >&2
        return 2
    fi
    if ! [[ "$prefix" =~ ^[0-9]+$ ]] || [ "$prefix" -lt "$MIN_PREFIX" ] || [ "$prefix" -gt "$MAX_PREFIX" ]; then
        echo "FEHLER: --prefix muss eine ganze Zahl zwischen ${MIN_PREFIX} und ${MAX_PREFIX} sein." >&2
        return 2
    fi
    if [ "$end_vlan" -lt "$start_vlan" ]; then
        echo "FEHLER: END-VLAN (${end_vlan}) ist kleiner als START-VLAN (${start_vlan})." >&2
        return 1
    fi
    if [ "$start_vlan" -lt "$anchor_vlan" ]; then
        echo "FEHLER: START-VLAN (${start_vlan}) liegt unter der Anchor-VLAN (${anchor_vlan})." >&2
        return 1
    fi

    local s_idx=$(( start_vlan - anchor_vlan ))
    local e_idx=$(( end_vlan - anchor_vlan ))
    local block_size=$(( 2 ** (32 - prefix) ))

    local s_third s_fourth e_third e_fourth

    if [ "$prefix" -ge 24 ]; then
        local per_24=$(( 256 / block_size ))
        s_third=$(( s_idx / per_24 ))
        s_fourth=$(( (s_idx % per_24) * block_size ))
        e_third=$(( e_idx / per_24 ))
        e_fourth=$(( (e_idx % per_24) * block_size ))
    else
        local step3=$(( block_size / 256 ))
        s_third=$(( s_idx * step3 ))
        s_fourth=0
        e_third=$(( e_idx * step3 ))
        e_fourth=0
    fi

    if [ "$e_third" -gt 255 ]; then
        echo "WARNUNG: Range ueberschreitet das 3. Oktett (>255). Basis-Netz oder Praefix zu klein." >&2
    fi

    local start_net="${base_net}.${s_third}.${s_fourth}/${prefix}"
    local end_net="${base_net}.${e_third}.${e_fourth}/${prefix}"
    local count_vlans=$(( end_vlan - start_vlan + 1 ))
    local count24=$(( e_third - s_third + 1 ))

    echo
    echo "  Basis-Netz:   ${base_net}.x.x   (Anchor-VLAN ${anchor_vlan} = ${base_net}.0.0/${prefix})"
    echo "  VLAN-Range:   ${start_vlan} - ${end_vlan}"
    echo "  Praefix:      /${prefix}   (${block_size} Adressen je Subnetz)"
    echo
    echo "  Benoetigte Subnetze: ${count_vlans}   (verteilt auf ${count24} x /24)"
    echo
    echo "  Start-Netz:   ${start_net}   (VLAN ${start_vlan})"
    echo "  End-Netz:     ${end_net}   (VLAN ${end_vlan})"
    echo
    echo "  --------------------------------------------"
    echo "  Gesamt-Range: ${start_net} - ${end_net}"
    echo

    return 0
}

main "$@"
Anzeige