Zum Hauptinhalt springen

6. Algorithmus (Algorithm)

6.1. Initialisierungsschritte (Initialization Steps)

Zu Beginn einer Staukontroll-Antwortphase, die von einem Staukontrollalgorithmus initiiert wird, muss (muss) ein Datensender, der PRR verwendet, den PRR-Zustand initialisieren.

Der Zeitpunkt, zu dem eine Staukontroll-Antwortphase beginnt, wird vollständig vom Staukontrollalgorithmus bestimmt, zum Beispiel kann (kann) er dem Beginn einer schnellen Wiederherstellungsphase entsprechen, oder er kann (kann) jede Runde auftreten, wenn eine Reduzierung durchgeführt wird, nachdem die schnelle Wiederherstellung bereits läuft, bei Erkennung einer verlorenen Neuübertragung oder einer verlorenen ursprünglichen Übertragung.

Die PRR-Initialisierung ermöglicht es einem Staukontrollalgorithmus CongCtrlAlg(), ssthresh auf einen anderen Wert als FlightSize/2 zu setzen (z. B. einschließlich CUBIC [RFC9438]).

Ein wichtiger Schritt bei der PRR-Initialisierung ist die Berechnung der Wiederherstellungs-Fluggröße (Recovery Flight Size, RecoverFS), die die Schätzung des Senders der Anzahl der Bytes ist, die während der aktuellen PRR-Phase geliefert werden können (kann). Dies kann (kann) als die Summe der folgenden Werte zu Beginn der Phase betrachtet werden: inflight, die im ACK, das die Wiederherstellung ausgelöst hat, kumulativ bestätigten Bytes, die im ACK, das die Wiederherstellung ausgelöst hat, SACKten Bytes und die bereits zwischen SND.UNA und SND.NXT als verloren markierten Bytes. RecoverFS umfasst Verluste, da Verluste mit Heuristiken markiert werden und daher während der Wiederherstellung einige zuvor als verloren markierte Pakete letztendlich geliefert werden können (kann) (ohne Neuübertragung zu erfordern). PRR verwendet RecoverFS, um eine glatte Senderate zu berechnen. Beim Eintritt in die schnelle Wiederherstellung initialisiert PRR RecoverFS, und RecoverFS bleibt während einer gegebenen schnellen Wiederherstellungsphase konstant.

Die vollständige Sequenz der PRR-Algorithmus-Initialisierungsschritte ist wie folgt:

ssthresh = CongCtrlAlg()  // Ziel-Fluggröße in der Wiederherstellung
prr_delivered = 0 // Gesamt gelieferte Bytes in der Wiederherstellung
prr_out = 0 // Gesamt gesendete Bytes in der Wiederherstellung
RecoverFS = SND.NXT - SND.UNA // Bytes, die vor Eintritt in die Wiederherstellung SACKt wurden

// Bytes, die vor Eintritt in die Wiederherstellung SACKt wurden, werden während
// der Wiederherstellung nicht als geliefert markiert:
RecoverFS -= (im Scoreboard SACKte Bytes)

// Selektiv ACKte Bytes einschließen (häufiger Fall):
RecoverFS += (neu SACKte Bytes)

// Kumulativ bestätigte Bytes einschließen (seltener Fall):
RecoverFS += (neu kumulativ bestätigte Bytes)

6.2. Schritte pro ACK (Per-ACK Steps)

Bei jedem ACK zu Beginn oder während der schnellen Wiederherstellung, mit Ausnahme des ACK, das die PRR-Phase beendet, führt PRR die folgenden Schritte aus.

Zunächst berechnet der Sender DeliveredData, was die beste Schätzung des Datensenders der Gesamtanzahl der Bytes ist, die das aktuelle ACK anzeigt, seit dem zuvor empfangenen ACK an den Empfänger geliefert worden zu sein. Mit SACK kann (kann) DeliveredData präzise als die Änderung in SND.UNA plus die vorzeichenbehaftete Änderung der Menge der im Scoreboard als SACKt markierten Daten berechnet werden. Somit ist DeliveredData im Spezialfall, wenn es vor oder nach einem ACK keine SACKten Sequenzbereiche im Scoreboard gibt, die Änderung in SND.UNA.

In einer Wiederherstellung ohne SACK wird DeliveredData bei jedem empfangenen doppelten ACK auf 1 SMSS geschätzt (d. h. SND.UNA hat sich nicht geändert). Wenn SND.UNA voranschreitet (d. h. ein vollständiges oder teilweises ACK), ist DeliveredData die Änderung in SND.UNA, minus 1 SMSS für jedes vorangehende doppelte ACK. Beachten Sie, dass ohne SACK ein sich schlecht verhaltender Empfänger, der überschüssige doppelte ACKs zurückgibt (wie in [Savage99] beschrieben), versuchen könnte, DeliveredData künstlich aufzublähen. Als Gegenmaßnahme erlaubt PRR, wenn SACK nicht verwendet wird, keine Erhöhung von DeliveredData, wenn die Gesamtanzahl der in der PRR-Phase gelieferten Bytes die geschätzten ausstehenden Daten beim Eintritt in die Wiederherstellung (RecoverFS) übersteigt.

Als Nächstes berechnet der Sender inflight, was die beste Schätzung des Datensenders der Anzahl der im Netzwerk im Flug befindlichen Bytes ist. Um inflight zu berechnen, kann (kann) eine Verbindung mit aktiviertem SACK und Verwendung der Verlustertung [RFC6675] den in [RFC6675] spezifizierten "Pipe"-Algorithmus verwenden. Eine SACK-fähige Verbindung, die RACK-TLP-Verlustertung [RFC8985] oder andere Verluststungsalgorithmen verwendet, muss (muss) inflight berechnen, indem sie mit SND.NXT - SND.UNA beginnt, die im Scoreboard SACKten Bytes subtrahiert, die im Scoreboard als verloren markierten Bytes subtrahiert und die Bytes aus dem Scoreboard addiert, die seit der Markierung als verloren neuübertragen wurden.

Für eine Verbindung ohne aktiviertes SACK muss (muss) der Sender subtrahieren: min(RecoverFS, 1 SMSS für jedes vorangehende doppelte ACK in der schnellen Wiederherstellungsphase); das min() mit RecoverFS dient der Verteidigung gegen einen sich schlecht verhaltenden Empfänger [Savage99], anstatt die im SACK-Scoreboard SACKten Bytes zu subtrahieren.

Als Nächstes berechnet der Sender SafeACK, eine lokale boolesche Variable, die anzeigt, dass das aktuelle ACK guten Fortschritt meldet. SafeACK ist nur dann wahr, wenn das ACK neue Daten kumulativ bestätigt und das ACK keine weiteren Verluste anzeigt. Zum Beispiel kann (kann) ein ACK, das eine "Rettungs"-Neuübertragung auslöst (Abschnitt 4 von [RFC6675], NextSeg() Bedingung 4), weitere Verluste anzeigen. Beide Bedingungen zeigen an, dass die Wiederherstellung gut voranschreitet, und der Sender kann (kann) bei Bedarf aggressiver senden, wodurch inflight erhöht wird.

Schließlich verwendet der Sender DeliveredData, inflight, SafeACK und andere PRR-Zustände, um SndCnt zu berechnen, eine lokale Variable, die anzeigt, wie viele Bytes als Antwort auf jedes ACK gesendet werden sollten (sollte), und verwendet dann SndCnt, um cwnd zu aktualisieren.

Die vollständige Sequenz der PRR-Algorithmus-Schritte pro ACK ist wie folgt:

if (DeliveredData is 0)
Return

prr_delivered += DeliveredData
inflight = (geschätzte Menge an im Flug befindlichen Daten)
SafeACK = (SND.UNA ist vorangeschritten UND keine weiteren Verluste angezeigt)

if (inflight > ssthresh) {
// Proportionale Ratenreduzierung
// Dies verwendet Ganzzahldivision, aufgerundet:
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
out = DIV_ROUND_UP(prr_delivered * ssthresh, RecoverFS)
SndCnt = out - prr_out
} else {
// Standardmäßig PRR-CRB verwenden
SndCnt = MAX(prr_delivered - prr_out, DeliveredData)
if (SafeACK) {
// PRR-SSRB verwenden, wenn die Wiederherstellung gut voranschreitet
SndCnt += SMSS
}
// Versuchen aufzuholen, soweit erlaubt
SndCnt = MIN(ssthresh - inflight, SndCnt)
}

if (prr_out is 0 AND SndCnt is 0) {
// Schnelle Neuübertragung beim Eintritt in die Wiederherstellung erzwingen
SndCnt = SMSS
}

cwnd = inflight + SndCnt

Nachdem der Sender SndCnt berechnet und es verwendet hat, um cwnd zu aktualisieren, überträgt der Sender mehr Daten. Beachten Sie, dass die Entscheidung, welche Daten gesendet werden sollen (z. B. fehlende Daten neuübertragen oder mehr neue Daten senden), außerhalb des Umfangs dieses Dokuments liegt.

6.3. Schritte pro Übertragung (Per-Transmit Steps)

Bei jeder Datenübertragung oder Neuübertragung führt PRR Folgendes aus:

prr_out += (gesendete Daten)

6.4. Abschlussschritte (Completion Steps)

Die PRR-Phase endet beim Abschluss der schnellen Wiederherstellung oder vor dem Start einer neuen PRR-Phase aufgrund einer neuen Staukontroll-Antwortphase.

Beim Abschluss einer PRR-Phase führt PRR Folgendes aus:

cwnd = ssthresh

Beachten Sie, dass dieser Schritt, cwnd auf ssthresh zu setzen, in einigen Fällen einen aufeinanderfolgenden Burst von Segmenten in das Netzwerk ermöglichen kann (kann).

Implementierungen werden ermutigt (empfohlen), Pacing zu verwenden, um die Burstiness des Datenflusses zu reduzieren. Diese Ermutigung steht im Einklang mit aktuellen Praktiken zur Abschwächung von Burstiness (z. B. [PACING]), einschließlich des Pacing von Übertragungsbursts nach dem Neustart aus dem Leerlauf.