6. Rilevamento della perdita (Loss Detection)
Un mittente QUIC utilizza gli acknowledgment (riscontri) per rilevare i pacchetti persi e un PTO per garantire la ricezione degli acknowledgment; vedere Sezione 6.2. Questa sezione fornisce una descrizione di questi algoritmi.
Se un pacchetto viene perso, il trasporto QUIC deve recuperare da tale perdita, ad esempio ritrasmettendo i dati, inviando un frame aggiornato o abbandonando il frame. Per ulteriori informazioni, vedere la Sezione 13.3 di [QUIC-TRANSPORT].
Il rilevamento della perdita (loss detection) è separato per spazio di numero di pacchetto (per packet number space), a differenza della misurazione RTT e del controllo della congestione, poiché RTT e controllo della congestione sono proprietà del percorso, mentre il rilevamento della perdita dipende anche dalla disponibilità delle chiavi.
6.1. Rilevamento basato su acknowledgment (Acknowledgment-Based Detection)
Il rilevamento della perdita basato su acknowledgment implementa lo spirito della ritrasmissione rapida (Fast Retransmit) di TCP [RFC5681], della ritrasmissione anticipata (Early Retransmit) [RFC5827], dell'acknowledgment anticipato (Forward Acknowledgment) [FACK], del recupero della perdita SACK [RFC6675] e di RACK-TLP [RFC8985]. Questa sezione fornisce una panoramica di come questi algoritmi sono implementati in QUIC.
Un pacchetto viene dichiarato perso se soddisfa tutte le seguenti condizioni:
-
Il pacchetto non è stato riscontrato, è in volo (in flight) ed è stato inviato prima di un pacchetto riscontrato.
-
Il pacchetto è stato inviato
kPacketThresholdpacchetti prima di un pacchetto riscontrato (Sezione 6.1.1), oppure è stato inviato sufficientemente tempo fa (Sezione 6.1.2).
L'acknowledgment indica che un pacchetto inviato successivamente è stato consegnato, e le soglie di pacchetto e di tempo forniscono una certa tolleranza per il riordino dei pacchetti.
Dichiarare erroneamente i pacchetti come persi porta a ritrasmissioni non necessarie e può comportare un degrado delle prestazioni a causa delle azioni del controllore di congestione durante il rilevamento della perdita. Le implementazioni possono rilevare ritrasmissioni spurie e aumentare la soglia di riordino del pacchetto o del tempo per ridurre future ritrasmissioni spurie ed eventi di perdita. Le implementazioni con soglie di tempo adattive POSSONO scegliere di iniziare con soglie di riordino iniziali più piccole per minimizzare la latenza di recupero.
6.1.1. Soglia di pacchetto (Packet Threshold)
Il valore iniziale RACCOMANDATO (RECOMMENDED) per la soglia di riordino del pacchetto (kPacketThreshold) è 3, basato sulle migliori pratiche per il rilevamento della perdita TCP [RFC5681] [RFC6675]. Per rimanere simile a TCP, le implementazioni NON DOVREBBERO (SHOULD NOT) utilizzare una soglia di pacchetto inferiore a 3; vedere [RFC5681].
Alcune reti possono mostrare gradi più elevati di riordino dei pacchetti, causando la rilevazione da parte del mittente di perdite spurie. Inoltre, il riordino dei pacchetti potrebbe essere più comune con QUIC rispetto a TCP perché gli elementi di rete che potrebbero osservare e riordinare i pacchetti TCP non possono farlo con QUIC e perché i numeri di pacchetto QUIC sono crittografati. Gli algoritmi che aumentano la soglia di riordino dopo aver rilevato in modo spurio una perdita, come RACK [RFC8985], si sono dimostrati utili in TCP e ci si aspetta che siano almeno altrettanto utili in QUIC.
6.1.2. Soglia di tempo (Time Threshold)
Una volta che un pacchetto successivo nello stesso spazio di numero di pacchetto è stato riscontrato, un endpoint DOVREBBE (SHOULD) dichiarare perso un pacchetto precedente se è stato inviato una certa quantità di tempo soglia fa. Per evitare di dichiarare i pacchetti persi troppo presto, questa soglia di tempo DEVE (MUST) essere impostata almeno alla granularità del timer locale, come indicato dalla costante kGranularity. La soglia di tempo è:
max(kTimeThreshold * max(smoothed_rtt, latest_rtt), kGranularity)
Se i pacchetti inviati prima del pacchetto riscontrato più grande non possono ancora essere dichiarati persi, allora un timer DOVREBBE (SHOULD) essere impostato per il tempo rimanente.
L'uso di max(smoothed_rtt, latest_rtt) protegge dai seguenti due casi:
-
il campione RTT più recente è inferiore all'RTT levigato, forse a causa di un riordino in cui l'acknowledgment ha incontrato un percorso più breve;
-
il campione RTT più recente è superiore all'RTT levigato, forse a causa di un aumento sostenuto dell'RTT effettivo, ma l'RTT levigato non ha ancora recuperato.
La soglia di tempo RACCOMANDATO (RECOMMENDED) (kTimeThreshold), espressa come moltiplicatore RTT, è 9/8. Il valore RACCOMANDATO (RECOMMENDED) della granularità del timer (kGranularity) è 1 millisecondo.
Nota: RACK di TCP [RFC8985] specifica una soglia leggermente più grande, equivalente a 5/4, per uno scopo simile. L'esperienza con QUIC mostra che 9/8 funziona bene.
Le implementazioni POSSONO (MAY) sperimentare con soglie assolute, soglie da connessioni precedenti, soglie adattive o soglie che includono la variazione RTT. Soglie più piccole riducono la resilienza al riordino e aumentano le ritrasmissioni spurie, e soglie più grandi aumentano il ritardo di rilevamento della perdita.
6.2. Timeout di sonda (Probe Timeout)
Un timeout di sonda (PTO) innesca l'invio di uno o due datagrammi di sonda quando i pacchetti che richiedono acknowledgment (ack-eliciting packets) non vengono riscontrati entro il periodo di tempo previsto o il server potrebbe non aver ancora validato l'indirizzo del client. Un PTO consente a una connessione di recuperare dalla perdita di pacchetti di coda o di acknowledgment.
Come per il rilevamento della perdita, il PTO è per spazio di numero di pacchetto (per packet number space). Cioè, un valore PTO viene calcolato per ogni spazio di numero di pacchetto.
Un evento di scadenza del timer PTO non indica una perdita di pacchetto e NON DEVE (MUST NOT) causare la marcatura come persi dei pacchetti precedentemente non riscontrati. Quando viene ricevuto un acknowledgment per un pacchetto appena sollecitato, il rilevamento della perdita procede come dettato dai meccanismi di soglia di pacchetto e di tempo; vedere Sezione 6.1.
L'algoritmo PTO utilizzato in QUIC implementa le funzioni di affidabilità di Tail Loss Probe [RFC8985], RTO [RFC5681] e algoritmi F-RTO per TCP [RFC5682]. Il calcolo del timeout è basato sul periodo RTO di TCP [RFC6298].
6.2.1. Calcolo del PTO (Computing PTO)
Quando viene trasmesso un pacchetto che richiede acknowledgment, il mittente pianifica un timer per il periodo PTO come segue:
PTO = smoothed_rtt + max(4*rttvar, kGranularity) + max_ack_delay
Il periodo PTO è la quantità di tempo che un mittente dovrebbe attendere per un acknowledgment di un pacchetto inviato. Questo periodo di tempo include l'RTT di rete stimato (smoothed_rtt), la variazione nella stima (4*rttvar) e max_ack_delay, per tenere conto del tempo massimo entro il quale un ricevitore potrebbe ritardare l'invio di un acknowledgment.
Quando il PTO è armato per gli spazi di numero di pacchetto Initial o Handshake, il max_ack_delay nel calcolo del periodo PTO è impostato a 0, poiché ci si aspetta che il peer non ritardi intenzionalmente questi pacchetti; vedere la Sezione 13.2.1 di [QUIC-TRANSPORT].
Il periodo PTO DEVE (MUST) essere almeno kGranularity per evitare che il timer scada immediatamente.
Quando i pacchetti che richiedono acknowledgment sono in volo in più spazi di numero di pacchetto, il timer DEVE (MUST) essere impostato al valore più anticipato degli spazi di numero di pacchetto Initial e Handshake.
Un endpoint NON DEVE (MUST NOT) impostare il suo timer PTO per lo spazio di numero di pacchetto dei dati applicativi fino a quando l'handshake non è confermato. Ciò impedisce all'endpoint di ritrasmettere informazioni nei pacchetti quando o il peer non ha ancora le chiavi per elaborarli o l'endpoint non ha ancora le chiavi per elaborare i loro acknowledgment. Ad esempio, ciò può accadere quando un client invia pacchetti 0-RTT al server; lo fa senza sapere se il server sarà in grado di decifrarli. Allo stesso modo, ciò può accadere quando un server invia pacchetti 1-RTT prima di confermare che il client ha verificato il certificato del server e quindi può leggere questi pacchetti 1-RTT.
Un mittente DOVREBBE (SHOULD) riavviare il suo timer PTO ogni volta che un pacchetto che richiede acknowledgment viene inviato o riscontrato, o quando le chiavi Initial o Handshake vengono scartate (Sezione 4.9 di [QUIC-TLS]). Ciò garantisce che il PTO sia sempre impostato in base alla stima più recente dell'RTT e per il pacchetto corretto attraverso gli spazi di numero di pacchetto.
Quando un timer PTO scade, il backoff PTO DEVE (MUST) essere aumentato, risultando nell'impostazione del periodo PTO al doppio del suo valore attuale. Il fattore di backoff PTO viene ripristinato quando viene ricevuto un acknowledgment, tranne nel caso seguente. Un server potrebbe impiegare più tempo per rispondere ai pacchetti durante l'handshake rispetto al normale. Per proteggere tale server da sonde client ripetute, il backoff PTO non viene ripristinato su un client che non è ancora certo che il server abbia completato la validazione dell'indirizzo del client. Cioè, un client non ripristina il fattore di backoff PTO alla ricezione di acknowledgment nei pacchetti Initial.
Questa riduzione esponenziale della velocità del mittente è importante perché PTO consecutivi potrebbero essere causati dalla perdita di pacchetti o acknowledgment a causa di una congestione grave. Anche quando ci sono pacchetti che richiedono acknowledgment in volo in più spazi di numero di pacchetto, l'aumento esponenziale del PTO si verifica in tutti gli spazi per prevenire un carico eccessivo sulla rete. Ad esempio, un timeout nello spazio di numero di pacchetto Initial raddoppia la lunghezza del timeout nello spazio di numero di pacchetto Handshake.
La lunghezza totale del tempo durante il quale si verificano scadenze PTO consecutive è limitata dal timeout di inattività (idle timeout).
Il timer PTO NON DEVE (MUST NOT) essere impostato se un timer è impostato per il rilevamento della perdita di soglia di tempo; vedere Sezione 6.1.2. Un timer impostato per il rilevamento della perdita di soglia di tempo scadrà prima del timer PTO nella maggior parte dei casi ed è meno probabile che ritrasmetta dati in modo spurio.
6.2.2. Handshake e nuovi percorsi (Handshakes and New Paths)
Le connessioni riprese sulla stessa rete POSSONO (MAY) utilizzare il valore RTT levigato finale della connessione precedente come RTT iniziale della connessione ripresa. Quando non è disponibile alcun RTT precedente, l'RTT iniziale DOVREBBE (SHOULD) essere impostato a 333 millisecondi. Ciò porta gli handshake a iniziare con un PTO di 1 secondo, come raccomandato per l'RTO iniziale di TCP; vedere la Sezione 2 di [RFC6298].
Una connessione PUÒ (MAY) utilizzare il ritardo tra l'invio di un PATH_CHALLENGE e la ricezione di un PATH_RESPONSE per impostare l'RTT iniziale (vedere kInitialRtt nell'Appendice A.2) per un nuovo percorso, ma il ritardo NON DOVREBBE (SHOULD NOT) essere considerato un campione RTT.
Quando le chiavi Initial e Handshake vengono scartate (vedere Sezione 6.4), tutti i pacchetti Initial e Handshake non possono più essere riscontrati, quindi vengono rimossi dai byte in volo (bytes in flight). I timer PTO e di rilevamento della perdita DEVONO (MUST) essere ripristinati, poiché lo scarto delle chiavi indica un progresso e il timer di rilevamento della perdita potrebbe essere stato impostato per uno spazio di numero di pacchetto ora scartato.
6.2.2.1. Prima della validazione dell'indirizzo (Before Address Validation)
Fino a quando il server non ha validato l'indirizzo del client sul percorso, la quantità di dati che può inviare è limitata a tre volte la quantità di dati ricevuti, come specificato nella Sezione 8.1 di [QUIC-TRANSPORT]. Se non è possibile inviare dati aggiuntivi, il timer PTO del server NON DEVE (MUST NOT) essere armato fino a quando non sono stati ricevuti datagrammi dal client, poiché i pacchetti inviati su PTO contano per il limite anti-amplificazione.
Quando un server riceve un datagramma dal client, il limite di amplificazione viene aumentato e il server ripristina il timer PTO. Se il timer PTO viene quindi impostato a un momento nel passato, viene eseguito immediatamente. Ciò evita di inviare nuovi pacchetti 1-RTT prima dei pacchetti critici per il completamento dell'handshake. In particolare, ciò può accadere quando 0-RTT viene accettato ma il server non riesce a validare l'indirizzo del client.
Poiché il server potrebbe essere bloccato fino a quando non vengono ricevuti più datagrammi dal client, è responsabilità del client inviare pacchetti per sbloccare il server fino a quando non è certo che il server abbia completato la sua validazione dell'indirizzo (vedere la Sezione 8 di [QUIC-TRANSPORT]). Cioè, il client DEVE (MUST) impostare il timer PTO se il client non ha ricevuto un acknowledgment per nessuno dei suoi pacchetti Handshake e l'handshake non è confermato (vedere la Sezione 4.1.2 di [QUIC-TLS]), anche se non ci sono pacchetti in volo. Quando il PTO scatta, il client DEVE (MUST) inviare un pacchetto Handshake se ha chiavi Handshake, altrimenti DEVE (MUST) inviare un pacchetto Initial in un datagramma UDP con un payload di almeno 1200 byte.
6.2.3. Accelerazione del completamento dell'handshake (Speeding up Handshake Completion)
Quando un server riceve un pacchetto Initial contenente dati CRYPTO duplicati, può presumere che il client non abbia ricevuto tutti i dati CRYPTO del server inviati nei pacchetti Initial, o che l'RTT stimato del client sia troppo piccolo. Quando un client riceve pacchetti Handshake o 1-RTT prima di ottenere le chiavi Handshake, può presumere che alcuni o tutti i pacchetti Initial del server siano andati persi.
Per accelerare il completamento dell'handshake in queste condizioni, un endpoint PUÒ (MAY), per un numero limitato di volte per connessione, inviare un pacchetto contenente dati CRYPTO non riscontrati prima della scadenza del PTO, soggetto ai limiti di validazione dell'indirizzo nella Sezione 8.1 di [QUIC-TRANSPORT]. Farlo al massimo una volta per connessione è adeguato per recuperare rapidamente da una singola perdita di pacchetto. Un endpoint che ritrasmette sempre pacchetti in risposta alla ricezione di pacchetti che non può elaborare rischia di creare uno scambio infinito di pacchetti.
Un endpoint può anche utilizzare pacchetti coalescenti (vedere la Sezione 12.2 di [QUIC-TRANSPORT]) per garantire che ogni datagramma solleciti almeno un acknowledgment. Ad esempio, un client può coalizzare un pacchetto Initial contenente frame PING e PADDING con un pacchetto di dati 0-RTT, e un server può coalizzare un pacchetto Initial contenente un frame PING con uno o più pacchetti nel suo primo volo.
6.2.4. Invio di pacchetti di sonda (Sending Probe Packets)
Quando un timer PTO scade, un mittente DEVE (MUST) inviare almeno un pacchetto che richiede acknowledgment nello spazio di numero di pacchetto come sonda. Un endpoint PUÒ (MAY) inviare fino a due datagrammi di dimensioni complete contenenti pacchetti che richiedono acknowledgment per evitare una costosa scadenza PTO consecutiva dovuta a un singolo datagramma perso, o per trasmettere dati da più spazi di numero di pacchetto. Tutti i pacchetti di sonda inviati su un PTO DEVONO (MUST) richiedere acknowledgment.
Oltre a inviare dati nello spazio di numero di pacchetto per il quale il timer è scaduto, il mittente DOVREBBE (SHOULD) inviare pacchetti che richiedono acknowledgment da altri spazi di numero di pacchetto con dati in volo, coalizzando i pacchetti se possibile. Ciò è particolarmente prezioso quando il server ha sia dati Initial che Handshake in volo o quando il client ha sia dati Handshake che Application in volo, poiché il peer potrebbe avere solo chiavi di ricezione per uno dei due spazi di numero di pacchetto.
Se il mittente desidera sollecitare un acknowledgment più rapido su PTO, può saltare un numero di pacchetto per eliminare il ritardo di acknowledgment.
Un endpoint DOVREBBE (SHOULD) includere nuovi dati nei pacchetti inviati alla scadenza del PTO. I dati precedentemente inviati POSSONO (MAY) essere inviati se non è possibile inviare nuovi dati. Le implementazioni POSSONO (MAY) utilizzare strategie alternative per determinare il contenuto dei pacchetti di sonda, incluso l'invio di dati nuovi o ritrasmessi in base alle priorità dell'applicazione.
Un mittente potrebbe non avere dati nuovi o precedentemente inviati da inviare. Come esempio, considerare la seguente sequenza di eventi: nuovi dati applicativi vengono inviati in un frame STREAM, ritenuti persi, quindi ritrasmessi in un nuovo pacchetto, e quindi la trasmissione originale viene riscontrata. Quando non ci sono dati da inviare, il mittente DOVREBBE (SHOULD) inviare un frame PING o un altro frame che richiede acknowledgment in un singolo pacchetto, riarmando il timer PTO.
In alternativa, invece di inviare un pacchetto che richiede acknowledgment, il mittente PUÒ (MAY) contrassegnare tutti i pacchetti ancora in volo come persi. Ciò evita di inviare un pacchetto aggiuntivo, ma aumenta il rischio di dichiarare in modo spurio i pacchetti come persi, risultando in una riduzione di velocità non necessaria da parte del controllore di congestione.
I periodi PTO consecutivi aumentano esponenzialmente e, di conseguenza, la latenza di recupero della connessione aumenta esponenzialmente man mano che i pacchetti continuano a essere scartati nella rete. L'invio di due pacchetti alla scadenza del PTO aumenta la resilienza alle perdite di pacchetti, riducendo così la probabilità di eventi PTO consecutivi.
Quando il timer PTO scade più volte e non è possibile inviare nuovi dati, le implementazioni devono scegliere tra inviare lo stesso payload ogni volta o inviare payload diversi. Inviare lo stesso payload ogni volta può essere più semplice e garantisce che i frame con la priorità più alta arrivino per primi. Inviare payload diversi ogni volta riduce le possibilità di ritrasmissioni spurie.
6.3. Gestione dei pacchetti Retry (Handling Retry Packets)
Un pacchetto Retry fa sì che un client invii un altro pacchetto Initial, riavviando effettivamente il processo di connessione. Un pacchetto Retry indica che il pacchetto Initial è stato ricevuto ma non elaborato. Un pacchetto Retry non può essere trattato come un acknowledgment, poiché non indica che un pacchetto è stato elaborato o specifica il numero di pacchetto.
I client che ricevono un pacchetto Retry ripristinano lo stato di controllo della congestione e di recupero della perdita, incluso il ripristino di tutti i timer in sospeso. Altro stato di connessione, in particolare i messaggi di handshake crittografico, viene conservato; vedere la Sezione 17.2.5 di [QUIC-TRANSPORT].
Il client PUÒ (MAY) calcolare una stima RTT al server come il periodo di tempo dall'invio del primo pacchetto Initial alla ricezione di un pacchetto Retry o di negoziazione della versione. Il client PUÒ (MAY) utilizzare questo valore al posto del suo valore predefinito per la stima RTT iniziale.
6.4. Scarto di chiavi e stato dei pacchetti (Discarding Keys and Packet State)
Quando le chiavi di protezione dei pacchetti Initial e Handshake vengono scartate (vedere la Sezione 4.9 di [QUIC-TLS]), tutti i pacchetti inviati con quelle chiavi non possono più essere riscontrati perché i loro acknowledgment non possono essere elaborati. Il mittente DEVE (MUST) scartare tutto lo stato di recupero associato a quei pacchetti e DEVE (MUST) rimuoverli dal conteggio dei byte in volo (bytes in flight).
Gli endpoint smettono di inviare e ricevere pacchetti Initial una volta che iniziano a scambiare pacchetti Handshake; vedere la Sezione 17.2.2.1 di [QUIC-TRANSPORT]. A questo punto, lo stato di recupero per tutti i pacchetti Initial in volo viene scartato.
Quando 0-RTT viene rifiutato, lo stato di recupero per tutti i pacchetti 0-RTT in volo viene scartato.
Se un server accetta 0-RTT, ma non bufferizza i pacchetti 0-RTT che arrivano prima dei pacchetti Initial, i primi pacchetti 0-RTT verranno dichiarati persi, ma ci si aspetta che ciò sia infrequente.
Ci si aspetta che le chiavi vengano scartate a un certo momento dopo che i pacchetti crittografati con esse sono stati riscontrati o dichiarati persi. Tuttavia, i segreti Initial e Handshake vengono scartati non appena le chiavi Handshake e 1-RTT sono provate essere disponibili sia per il client che per il server; vedere la Sezione 4.9.1 di [QUIC-TLS].