summaryrefslogtreecommitdiff
path: root/src/lib/frct.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/frct.c')
-rw-r--r--src/lib/frct.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/lib/frct.c b/src/lib/frct.c
index 40f2e9f9..27c333c6 100644
--- a/src/lib/frct.c
+++ b/src/lib/frct.c
@@ -26,6 +26,7 @@
#define MAX_RDV (1 * BILLION) /* ns */
#define MAX_RTO_MUL 8 /* caps the RTO backoff shift */
+#define MAX_TLP_PER_EP 2 /* RFC 8985 §7.3: up to 2 TLPs */
#define INITIAL_RTO (1 * BILLION) /* RFC 6298 §2.1: 1 s default */
#define RTT_BOOT_NS (10 * MILLION) /* rtt_hint floor + initial mdev */
#define SRTT_FLOOR_NS 1000L /* 1 us; smoothed RTT floor */
@@ -366,12 +367,13 @@ struct frcti {
bool dsack_valid;
/* RFC 8985 §7.2 RACK reorder-window scaling. */
- uint8_t reo_wnd_mult; /* 1..REO_WND_MULT_MAX */
+ uint8_t reo_wnd_mult; /* REO_WND_MULT_MAX */
uint32_t dsack_lwe_snap; /* lwe @ last DSACK */
- uint64_t t_last_reo_widen; /* once-per-RTT gate */
+ uint64_t t_last_reo_widen; /* once-per-RTT */
uint32_t dup_thresh; /* RFC 8985 */
uint32_t tlp_high_seq; /* §7.3: 0 = none */
+ uint8_t tlp_count; /* §7.3 per-episode */
uint64_t t_nack;
bool open; /* FC window state */
bool in_recovery;
@@ -1226,8 +1228,9 @@ static void rxm_snd(struct frcti * frcti,
slot->time = TS_TO_UINT64(now);
/* RTO supersedes any pending TLP/fast-rxm on this slot. */
slot->flags = (slot->flags & ~(SND_FAST_RXM | SND_TLP)) | SND_RTX;
- /* §7.3: RTO supersedes any outstanding TLP. */
+ /* §7.3: RTO supersedes TLP probes and ends the probe episode. */
frcti->tlp_high_seq = 0;
+ frcti->tlp_count = 0;
frcti->rtt_lwe = seqno + 1;
@@ -2928,12 +2931,17 @@ static void tlp_due(void * arg)
if (frcti->snd_cr.seqno == frcti->snd_cr.lwe)
goto unlock;
+
if (!before(frcti->snd_cr.seqno, frcti->snd_cr.rwe))
goto unlock; /* FC-blocked: RDV handles it. */
- /* RFC 8985 §7.3: at most one outstanding TLP per episode. */
+
+ /* RFC 8985 §7.3: one outstanding probe, MAX_TLP_PER_EP per ep. */
if (frcti->tlp_high_seq != 0)
goto unlock;
+ if (frcti->tlp_count >= MAX_TLP_PER_EP)
+ goto unlock;
+
pto = tlp_pto(frcti);
/* §7.2: anchor PTO on most recent send; defer if still active. */
@@ -2949,9 +2957,8 @@ static void tlp_due(void * arg)
goto unlock;
/* Cap: if HoL RTO is due, let rxm_due fire instead. */
- rto_at = rxm->t0
- + ((uint64_t) frcti->rto
- << LOAD_RELAXED(&frcti->rto_mul));
+ rto_at = rxm->t0 + ((uint64_t) frcti->rto
+ << LOAD_RELAXED(&frcti->rto_mul));
if (rto_at <= now_ns)
goto unlock;
@@ -2964,6 +2971,7 @@ static void tlp_due(void * arg)
frcti->rtt_lwe = frcti->snd_cr.lwe + 1;
/* §7.3 outstanding-probe marker; ack_rcv/rxm_snd clear. */
frcti->tlp_high_seq = frcti->snd_cr.seqno;
+ frcti->tlp_count++;
STAT_BUMP(frcti, tlp_snd);
}
@@ -2989,9 +2997,11 @@ static int tlp_arm(struct frcti * frcti)
uint64_t pto;
uint64_t deadline;
- /* §7.3: at most one outstanding TLP per recovery episode. */
+ /* §7.3: one outstanding probe, MAX_TLP_PER_EP per recovery ep. */
if (LOAD_RELAXED(&frcti->tlp_high_seq) != 0)
return 0;
+ if (LOAD_RELAXED(&frcti->tlp_count) >= MAX_TLP_PER_EP)
+ return 0;
if (__atomic_test_and_set(&frcti->tlp_pending, __ATOMIC_RELAXED))
return 0;
@@ -3177,6 +3187,10 @@ static void frcti_ack_rcv(struct frcti * frcti,
&& !before(ackno, frcti->tlp_high_seq))
frcti->tlp_high_seq = 0;
+ /* §7.3: end the probe episode once inflight drains. */
+ if (ackno == frcti->snd_cr.seqno)
+ frcti->tlp_count = 0;
+
/* RFC 8985 §7.2: halve mult per REO_DECAY_PKTS fresh-ACK'd seqnos. */
fresh = ackno - frcti->dsack_lwe_snap;
if (frcti->reo_wnd_mult > 1 && fresh >= REO_DECAY_PKTS) {