TCP: congestione

// obiettivi di apprendimento
Distinguere il problema della congestione di rete dal problema del controllo del flusso
Descrivere le quattro fasi dell’algoritmo di controllo della congestione TCP: Slow Start, Congestion Avoidance, Fast Retransmit, Fast Recovery
Comprendere il principio AIMD e il comportamento della cwnd nel tempo
Confrontare le varianti moderne TCP CUBIC e BBR con il TCP Reno classico
📄
Slides
Grafici cwnd nel tempo, confronto algoritmi
Scarica →

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.

// la tragedia dei commons nella rete

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.

// definizione formale
La Congestion Window (cwnd) è una variabile mantenuta dal mittente che limita il numero di byte in volo nella rete: 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:

SegnaleTipo perditaSignificato
Timeout RTOGraveNessun ACK per lungo tempo → router ha scartato il pacchetto, la rete è satura
3 ACK duplicatiLieveLa 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
// perché AIMD è efficiente e fair

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/CUBICBBR
Segnale congestionePerdita di pacchettiStima di BW + RTT
ProblemaRiempie i buffer (bufferbloat)Evita il riempimento dei buffer
Prestazioni su rete congestionataDegradaPiù stabile
UsoDefault Linux (CUBIC)Google CDN, YouTube, QUIC
📌 Riepilogo — Punti chiave
  • 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

Lascia un commento