Skip to content

#27 — htb-fq-codel

PLANIFIÉ

Priorité: 🔴 CRITIQUE · Type: TYPE E · Conteneur: rgz-gateway · Code: scripts/qos/htb_setup.sh

Dépendances: #7 rgz-gateway


Description

L'outil HTB + fq_codel implémente la classification et le contrôle de débit au niveau du noyau Linux via les primitives tc (Traffic Control) d'iproute2. Il s'exécute exclusivement dans le conteneur rgz-gateway et constitue le plan de données QoS de l'ensemble du réseau ACCESS.

HTB (Hierarchical Token Bucket) est la discipline de mise en file d'attente (qdisc) racine. Elle permet d'organiser le trafic en une hiérarchie de classes avec débit garanti (CIR — Committed Information Rate) et débit maximal autorisé (MIR). Les classes peuvent emprunter de la bande passante inutilisée par les autres classes de même niveau, garantissant ainsi une utilisation optimale de la capacité WAN disponible.

fq_codel (Fair Queue Controlled Delay) est l'AQM (Active Queue Management) attaché à chaque classe HTB feuille. Il implémente l'algorithme CoDel pour maintenir une latence faible même en conditions de charge élevée, en combattant activement le bufferbloat. L'aspect "Fair Queue" garantit que chaque flux TCP bénéficie d'un accès équitable à la bande passante de sa classe, empêchant un seul flux de monopoliser la capacité.

Le script htb_setup.sh est exécuté au démarrage du conteneur rgz-gateway, après la configuration nftables (#7, #32) et le marquage DSCP (#28). Il lit les variables d'environnement pour adapter les débits à la capacité WAN réelle de chaque déploiement sans modification du code.

Architecture Interne

Interface eth0 (WAN-side) — débit total : QOS_TOTAL_MBPS (ex: 100Mbit)

└──► qdisc HTB root handle 1: (default class 1:30 pour trafic non classifié)

         └──► class 1:1 — Root HTB rate=100mbit (parent de toutes les sous-classes)

                  ├──► class 1:10  MGMT        rate=10mbit  ceil=100mbit  prio=1
                  │         Trafic : SSH(22), RADIUS(1812/1813/3799), Prometheus(9090),
                  │                  Grafana(3000), Alertmanager, SNMP(161)
                  │         DSCP match : CS6 (48), CS7 (56)
                  │         qdisc : fq_codel handle 10:  (latence cible 5ms)

                  ├──► class 1:20  Interactive  rate=5mbit   ceil=80mbit   prio=2
                  │         Trafic : HTTP(80), HTTPS(443), DNS(53), portail captif,
                  │                  NTP(123), WhatsApp, KKiaPay, Letexto
                  │         DSCP match : CS3 (24), AF41 (34)
                  │         qdisc : fq_codel handle 20:  (latence cible 20ms)

                  └──► class 1:30  Bulk         rate=1mbit   ceil=100mbit  prio=3
                            Trafic : tout le reste — downloads, streaming, P2P,
                                     trafic non marqué (default)
                            DSCP match : CS1 (8), BE (0)
                            qdisc : fq_codel handle 30:  (latence cible 100ms)

Filtres tc (u32) : lecture DSCP → redirection vers classe correspondante
    ip dscp CS6/CS7  → flowid 1:10
    ip dscp CS3/AF41 → flowid 1:20
    ip dscp CS1/BE   → flowid 1:30
    (défaut)         → flowid 1:30  (class default du qdisc root)

Configuration

Variables d'environnement

VariableValeur exempleDescription
QOS_INTERFACEeth0Interface réseau WAN à contrôler
QOS_TOTAL_MBPS100Débit WAN total disponible (Mbit/s)
QOS_MGMT_RATE_MBPS10CIR classe MGMT garanti (Mbit/s)
QOS_INTER_RATE_MBPS5CIR classe Interactive garanti (Mbit/s)
QOS_BULK_RATE_MBPS1CIR classe Bulk garanti (Mbit/s)
QOS_INTER_CEIL_MBPS80MIR classe Interactive (Mbit/s)
QOS_FQCODEL_TARGET5msLatence cible fq_codel (classe MGMT)
QOS_FQCODEL_INTERVAL100msIntervalle mesure fq_codel

Script htb_setup.sh

bash
#!/bin/sh
# scripts/qos/htb_setup.sh
# HTB + fq_codel QoS setup pour rgz-gateway
# Lancé par docker/gateway/entrypoint.sh au démarrage

set -e

IFACE="${QOS_INTERFACE:-eth0}"
TOTAL="${QOS_TOTAL_MBPS:-100}"
MGMT_RATE="${QOS_MGMT_RATE_MBPS:-10}"
INTER_RATE="${QOS_INTER_RATE_MBPS:-5}"
BULK_RATE="${QOS_BULK_RATE_MBPS:-1}"
INTER_CEIL="${QOS_INTER_CEIL_MBPS:-80}"

echo "[QoS] Suppression règles tc existantes sur ${IFACE}..."
tc qdisc del dev "${IFACE}" root 2>/dev/null || true

echo "[QoS] Configuration HTB root..."
tc qdisc add dev "${IFACE}" root handle 1: htb default 30

echo "[QoS] Classe root 1:1..."
tc class add dev "${IFACE}" parent 1: classid 1:1 \
    htb rate "${TOTAL}mbit"

echo "[QoS] Classe MGMT 1:10 (prio=1, ${MGMT_RATE}mbit garanti)..."
tc class add dev "${IFACE}" parent 1:1 classid 1:10 \
    htb rate "${MGMT_RATE}mbit" ceil "${TOTAL}mbit" prio 1

echo "[QoS] Classe Interactive 1:20 (prio=2, ${INTER_RATE}mbit garanti)..."
tc class add dev "${IFACE}" parent 1:1 classid 1:20 \
    htb rate "${INTER_RATE}mbit" ceil "${INTER_CEIL}mbit" prio 2

echo "[QoS] Classe Bulk 1:30 (prio=3, ${BULK_RATE}mbit garanti)..."
tc class add dev "${IFACE}" parent 1:1 classid 1:30 \
    htb rate "${BULK_RATE}mbit" ceil "${TOTAL}mbit" prio 3

echo "[QoS] fq_codel sur chaque classe feuille..."
tc qdisc add dev "${IFACE}" parent 1:10 handle 10: fq_codel \
    target 5ms interval 100ms
tc qdisc add dev "${IFACE}" parent 1:20 handle 20: fq_codel \
    target 20ms interval 100ms
tc qdisc add dev "${IFACE}" parent 1:30 handle 30: fq_codel \
    target 100ms interval 1000ms

echo "[QoS] Filtres u32 DSCP → classes..."
# CS6 (48) et CS7 (56) → MGMT
tc filter add dev "${IFACE}" parent 1: protocol ip prio 1 u32 \
    match ip dsfield 0xc0 0xfc flowid 1:10
tc filter add dev "${IFACE}" parent 1: protocol ip prio 2 u32 \
    match ip dsfield 0xe0 0xfc flowid 1:10
# CS3 (24) et AF41 (34) → Interactive
tc filter add dev "${IFACE}" parent 1: protocol ip prio 3 u32 \
    match ip dsfield 0x60 0xfc flowid 1:20
tc filter add dev "${IFACE}" parent 1: protocol ip prio 4 u32 \
    match ip dsfield 0x88 0xfc flowid 1:20
# CS1 (8) → Bulk
tc filter add dev "${IFACE}" parent 1: protocol ip prio 5 u32 \
    match ip dsfield 0x20 0xfc flowid 1:30

echo "[QoS] HTB + fq_codel opérationnel sur ${IFACE}."

Commandes Utiles

bash
# Vérifier la configuration HTB active
docker exec rgz-gateway tc qdisc show dev eth0
docker exec rgz-gateway tc class show dev eth0
docker exec rgz-gateway tc filter show dev eth0

# Statistiques de trafic par classe (bytes, paquets, drops)
docker exec rgz-gateway tc -s class show dev eth0

# Statistiques fq_codel — latence mesurée, drops
docker exec rgz-gateway tc -s qdisc show dev eth0

# Appliquer manuellement le script QoS (après modification)
docker exec rgz-gateway /scripts/qos/htb_setup.sh

# Supprimer toutes les règles tc (reset propre)
docker exec rgz-gateway tc qdisc del dev eth0 root 2>/dev/null || true

# Vérifier les drops par classe (indicateur de saturation)
docker exec rgz-gateway tc -s class show dev eth0 | grep -A5 "class htb 1:30"

# Test débit depuis le gateway (vers un hôte test)
docker exec rgz-gateway iperf3 -c 10.0.0.1 -t 10 -b 100M

# Logs de démarrage QoS dans le gateway
docker logs rgz-gateway --tail=30 | grep -i "QoS\|htb\|tc"

Sécurité

RègleApplication
LL#40Ce script n'appelle jamais nft flush ruleset — les règles nftables sont gérées séparément par entrypoint.sh
LL#41Les règles tc sont non-persistantes (contrairement à nftables) — elles sont recréées à chaque démarrage du conteneur sans conflit
LL#27Logs Docker limités à max-size: 10m, max-file: 3 pour rgz-gateway
LL#33restart: unless-stopped dans docker-compose.core.yml pour rgz-gateway

Interaction avec les autres outils QoS

Le script htb_setup.sh doit être exécuté après le script DSCP (#28) dans entrypoint.sh pour que les filtres tc u32 trouvent les paquets déjà marqués. L'ordre d'exécution dans entrypoint.sh est :

bash
# docker/gateway/entrypoint.sh — ordre obligatoire
/scripts/gateway/nftables_setup.sh   # #7 rgz-gateway (deny-all, NAT)
/scripts/qos/dscp_marking.sh        # #28 nftables DSCP marking
/scripts/qos/htb_setup.sh           # #27 HTB + fq_codel (ce fichier)
/scripts/gateway/watch_config.sh &  # #32 hot-reload nftables

Implémentation TODO

  • [ ] Créer scripts/qos/htb_setup.sh avec les paramètres via variables d'environnement
  • [ ] Ajouter les variables QoS dans .env.example (QOS_INTERFACE, QOS_TOTAL_MBPS, etc.)
  • [ ] Intégrer l'appel htb_setup.sh dans docker/gateway/entrypoint.sh (après DSCP)
  • [ ] Valider tc disponible dans l'image docker/gateway/Dockerfile (iproute2 installé)
  • [ ] Tester les 3 classes avec iperf3 et marquage DSCP sur banc de test
  • [ ] Vérifier que la suppression tc qdisc del dev eth0 root est idempotente au redémarrage
  • [ ] Documenter les seuils adaptés à la capacité WAN réelle (100Mbit = valeur par défaut)
  • [ ] Valider que fq_codel réduit effectivement la latence sous charge (test bufferbloat)
  • [ ] Ajouter métriques tc -s dans le dashboard Grafana (#37) via node_exporter textfile collector

Dernière mise à jour: 2026-02-21

PROJET MOSAÏQUE — 81 outils, 22 conteneurs, 500+ revendeurs WiFi Zone