Congestione di rete: il problema globale
Il controllo del flusso (L06) protegge il buffer di un singolo ricevitore. La congestione è un problema diverso: riguarda i router intermedi nella rete. Quando troppi mittenti inviano troppi dati allo stesso tempo, le code dei router si riempiono, la latenza esplode e i pacchetti vengono scartati.
Senza controllo della congestione, ogni mittente TCP cercherebbe di usare tutta la banda disponibile. Il risultato è il congestion collapse (documentato nel 1986 su ARPANET): la rete satura, throughput crolla quasi a zero, ritrasmissioni continue peggiorano ulteriormente la situazione. TCP deve essere self-limiting: ridurre volontariamente la velocità quando percepisce congestione.
limite_effettivo = min(cwnd, rwnd). TCP stima lo stato della rete dai segnali impliciti (perdite, ACK) e regola cwnd di conseguenza.Segnali di congestione
TCP non riceve feedback esplicito dalla rete (non ci sono messaggi “sto congestionando”). Usa due segnali impliciti:
| Segnale | Tipo perdita | Significato |
|---|---|---|
| Timeout RTO | Grave | Nessun ACK per lungo tempo → router ha scartato il pacchetto, la rete è satura |
| 3 ACK duplicati | Lieve | La rete funziona (gli ACK arrivano) ma un singolo segmento è andato perso |
Gli algoritmi — TCP Reno (classico)
1 — Slow Start
cwnd iniziale = 1 MSS (oppure 10 MSS per RFC 6928, Linux moderno) ssthresh = valore iniziale alto (es. 65535 byte) Per ogni ACK ricevuto: cwnd += 1 MSS → crescita esponenziale (raddoppio ogni RTT) Termina quando: cwnd ≥ ssthresh → passa a Congestion Avoidance oppure si verifica una perdita
Il nome “Slow Start” è controintuitivo: inizia lentamente (1 MSS) ma cresce in modo esponenziale. L’idea è sondare la capacità della rete senza partire a piena velocità.
2 — Congestion Avoidance (AIMD)
Per ogni ACK ricevuto: cwnd += MSS × (MSS / cwnd) → crescita lineare ≈ +1 MSS per RTT Principio AIMD (Additive Increase, Multiplicative Decrease): - Increase additivo: +1 MSS per RTT (lineare) - Decrease moltiplicativo: cwnd dimezzato in caso di congestione
AIMD converge verso un punto di equilibrio in cui le connessioni concorrenti condividono equamente la banda disponibile (fairness). La crescita lineare proba cautamente la banda libera; il taglio a metà reagisce velocemente alla congestione. È uno dei risultati più eleganti del design dei protocolli di rete (Chiu & Jain, 1989).
3 — Fast Retransmit
Alla ricezione del terzo ACK duplicato: ritrasmissione immediata del segmento mancante senza attendere il timeout RTO. Questo è molto più veloce del timeout (che può essere 1+ secondi).
4 — Fast Recovery
Dopo Fast Retransmit (3 ACK duplicati): ssthresh = cwnd / 2 cwnd = ssthresh + 3 MSS ← non torna in Slow Start! Ritrasmetti il segmento perso Per ogni ulteriore ACK duplicato: cwnd += 1 MSS (gonfiaggio temporaneo) Quando arriva ACK cumulativo nuovo: cwnd = ssthresh → Congestion Avoidance Dopo Timeout: ssthresh = cwnd / 2 cwnd = 1 MSS ← torna in Slow Start
Fast Recovery non torna in Slow Start: la perdita per 3 ACK duplicati è considerata lieve (la rete funziona ancora). Il timeout è considerato grave e riporta cwnd a 1 MSS.
Evoluzione della cwnd nel tempo — grafico
cwnd │ │ Slow Start CA perdita FR/FRec │ ┌──────────────────┐ │ ╱╲ │╲ │╲ │ ╱ ╲ │ ╲ │ ╲ │ ╱ ╲──┘ ╲─────────────┘ ────── │ ╱ │ ╱ (esponenziale) (lineare AIMD) │ 1 ╱ └──────────────────────────────────────────────→ tempo ssthresh segnata con linea tratteggiata — cambia dinamicamente
Algoritmi moderni
TCP CUBIC (default Linux da kernel 2.6.19)
TCP Reno scala male su reti ad alta larghezza di banda e alta latenza (BDP elevato): impiega troppo tempo a recuperare la banda dopo una perdita. CUBIC usa una funzione cubica del tempo trascorso dall’ultima perdita:
cwnd(t) = C × (t − K)³ + W_max Dove: W_max = valore di cwnd prima dell'ultima perdita K = tempo per tornare a W_max C = parametro di scala (0.4 di default)
CUBIC è aggressivo lontano da W_max (recupera velocemente) e cauto vicino a W_max (esplora con cautela). Ottimizzato per fibra e reti a lunga distanza.
BBR — Bottleneck Bandwidth and RTT (Google, 2016)
BBR è un cambio di paradigma: invece di reagire alle perdite (come Reno e CUBIC), stima direttamente la banda disponibile e il RTT minimo per mantenere la connessione nel punto operativo ottimale — il “BDP point” che massimizza il throughput senza riempire i buffer.
| TCP Reno/CUBIC | BBR | |
|---|---|---|
| Segnale congestione | Perdita di pacchetti | Stima di BW + RTT |
| Problema | Riempie i buffer (bufferbloat) | Evita il riempimento dei buffer |
| Prestazioni su rete congestionata | Degrada | Più stabile |
| Uso | Default Linux (CUBIC) | Google CDN, YouTube, QUIC |
- cwnd limita i byte in volo nella rete:
min(cwnd, rwnd). Distinto dalla rwnd che protegge il buffer del ricevitore - Slow Start: crescita esponenziale da 1 MSS finché cwnd raggiunge ssthresh
- Congestion Avoidance (AIMD): crescita lineare +1 MSS/RTT, taglio a metà in caso di perdita
- Fast Retransmit: 3 ACK duplicati → ritrasmissione immediata senza timeout
- Fast Recovery: non torna in Slow Start dopo Fast Retransmit (meno aggressivo del timeout)
- CUBIC (default Linux): funzione cubica, scala meglio su reti ad alta banda/latenza
- BBR: stima BW e RTT invece di reagire alle perdite — base di HTTP/3 e QUIC