#!/usr/bin/env bash
set -euo pipefail

MODE="${1:-}"
SW="m4-sw"
R1="m4-r1"
HOSTS=("m4-admin1" "m4-admin2" "m4-users" "m4-srv")

usage() {
  cat <<'EOF'
Usage:
  sudo ./module4-segmentation-lab.sh switch
  sudo ./module4-segmentation-lab.sh router
  sudo ./module4-segmentation-lab.sh cleanup

switch : VLAN 10/20/30 avec le même préfixe IPv4 pour prouver l'isolation L2.
router : VLAN 10/20/30, trunk 802.1Q et routeur-on-a-stick.
EOF
}

kill_namespace_processes() {
  local ns="$1"
  local pids
  pids="$(ip netns pids "$ns" 2>/dev/null || true)"
  if [[ -n "$pids" ]]; then
    kill $pids 2>/dev/null || true
    sleep 0.2
  fi
}

cleanup() {
  for ns in "${HOSTS[@]}" "$R1" "$SW"; do
    kill_namespace_processes "$ns"
    ip netns del "$ns" 2>/dev/null || true
  done
  rm -f /tmp/m4-filter.nft
}

need_root() {
  if [[ ${EUID} -ne 0 ]]; then
    echo "Exécute ce script avec sudo." >&2
    exit 1
  fi
}

create_ns() {
  local ns="$1"
  ip netns add "$ns"
  ip -n "$ns" link set lo up
}

create_access_link() {
  local host_ns="$1"
  local root_host_if="$2"
  local sw_if="$3"

  ip link add "$root_host_if" type veth peer name "$sw_if"
  ip link set "$root_host_if" netns "$host_ns"
  ip link set "$sw_if" netns "$SW"

  ip -n "$host_ns" link set "$root_host_if" name eth0
  ip -n "$host_ns" link set eth0 up

  ip -n "$SW" link set "$sw_if" master br0
  ip -n "$SW" link set "$sw_if" up
}

set_access_vlan() {
  local port="$1"
  local vid="$2"

  ip netns exec "$SW" bridge vlan del dev "$port" vid 1 2>/dev/null || true
  ip netns exec "$SW" bridge vlan add dev "$port" vid "$vid" pvid untagged
}

build_switch() {
  cleanup
  create_ns "$SW"
  for ns in "${HOSTS[@]}"; do
    create_ns "$ns"
  done

  ip -n "$SW" link add br0 type bridge vlan_filtering 1
  ip -n "$SW" link set br0 up

  create_access_link "m4-admin1" a1eth swa1
  create_access_link "m4-admin2" a2eth swa2
  create_access_link "m4-users"  usreth swusr
  create_access_link "m4-srv"    srveth swsrv

  set_access_vlan swa1 10
  set_access_vlan swa2 10
  set_access_vlan swusr 20
  set_access_vlan swsrv 30
}

configure_switch_mode() {
  ip -n m4-admin1 addr add 10.40.0.11/24 dev eth0
  ip -n m4-admin2 addr add 10.40.0.12/24 dev eth0
  ip -n m4-users  addr add 10.40.0.21/24 dev eth0
  ip -n m4-srv    addr add 10.40.0.31/24 dev eth0

  cat <<'EOF'
Laboratoire VLAN prêt.

Tests :
  sudo ip netns exec m4-admin1 ping -c 2 10.40.0.12   # VLAN 10 : succès
  sudo ip netns exec m4-admin1 ping -c 2 10.40.0.21   # VLAN 20 : échec attendu
  sudo ip netns exec m4-sw bridge vlan show
EOF
}

configure_router_mode() {
  create_ns "$R1"

  ip link add r1eth type veth peer name swr1
  ip link set r1eth netns "$R1"
  ip link set swr1 netns "$SW"

  ip -n "$R1" link set r1eth name eth0
  ip -n "$R1" link set eth0 up

  ip -n "$SW" link set swr1 master br0
  ip -n "$SW" link set swr1 up
  ip netns exec "$SW" bridge vlan del dev swr1 vid 1 2>/dev/null || true
  for vid in 10 20 30; do
    ip netns exec "$SW" bridge vlan add dev swr1 vid "$vid"
  done

  for vid in 10 20 30; do
    ip -n "$R1" link add link eth0 name "eth0.${vid}" type vlan id "$vid"
    ip -n "$R1" link set "eth0.${vid}" up
  done

  ip -n "$R1" addr add 10.40.10.1/24 dev eth0.10
  ip -n "$R1" addr add 10.40.20.1/24 dev eth0.20
  ip -n "$R1" addr add 10.40.30.1/24 dev eth0.30
  ip netns exec "$R1" sysctl -qw net.ipv4.ip_forward=1

  ip -n m4-admin1 addr add 10.40.10.11/24 dev eth0
  ip -n m4-admin2 addr add 10.40.10.12/24 dev eth0
  ip -n m4-users  addr add 10.40.20.21/24 dev eth0
  ip -n m4-srv    addr add 10.40.30.31/24 dev eth0

  ip -n m4-admin1 route add default via 10.40.10.1
  ip -n m4-admin2 route add default via 10.40.10.1
  ip -n m4-users  route add default via 10.40.20.1
  ip -n m4-srv    route add default via 10.40.30.1

  cat <<'EOF'
Laboratoire inter-VLAN prêt.

Tests :
  sudo ip netns exec m4-admin1 ping -c 2 10.40.20.21
  sudo ip netns exec m4-users ping -c 2 10.40.30.31
  sudo ip netns exec m4-sw bridge vlan show
  sudo ip -n m4-r1 -d link show type vlan
EOF
}

need_root

case "$MODE" in
  switch)
    build_switch
    configure_switch_mode
    ;;
  router)
    build_switch
    configure_router_mode
    ;;
  cleanup)
    cleanup
    echo "Laboratoire supprimé."
    ;;
  *)
    usage
    exit 1
    ;;
esac
