diff --git a/lib/ngtcp2_rtb.c b/lib/ngtcp2_rtb.c index 0f1d97f27d4964e66d00f018771de4084593266d..44792bff9290ba667875422a2e57b249a75049b8 100644 --- a/lib/ngtcp2_rtb.c +++ b/lib/ngtcp2_rtb.c @@ -241,6 +241,7 @@ void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, rtb->cc_pkt_num = 0; rtb->cc_bytes_in_flight = 0; rtb->persistent_congestion_start_ts = UINT64_MAX; + rtb->num_lost_pkts = 0; } void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { @@ -322,6 +323,8 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, ent->flags |= NGTCP2_RTB_FLAG_LOST_RETRANSMITTED; ent->lost_ts = ts; + ++rtb->num_lost_pkts; + ngtcp2_ksl_it_next(it); return 0; @@ -431,6 +434,8 @@ static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, ent->flags |= NGTCP2_RTB_FLAG_LOST_RETRANSMITTED; ent->lost_ts = ts; + ++rtb->num_lost_pkts; + ngtcp2_ksl_it_next(it); return 0; @@ -720,12 +725,8 @@ ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, const ngtcp2_rtb_entry *ent, uint64_t loss_delay, - ngtcp2_tstamp lost_send_time) { + ngtcp2_tstamp lost_send_time, uint64_t pkt_thres) { ngtcp2_tstamp loss_time; - uint64_t pkt_thres = - rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; - - pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD); if (ent->ts <= lost_send_time || rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { @@ -768,7 +769,10 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, ngtcp2_duration loss_window, congestion_period; ngtcp2_cc *cc = rtb->cc; int rv; + uint64_t pkt_thres = + rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; + pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD); cstat->loss_time[rtb->pktns_id] = UINT64_MAX; loss_delay = compute_pkt_loss_delay(cstat); lost_send_time = ts - loss_delay; @@ -781,7 +785,7 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, break; } - if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time)) { + if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time, pkt_thres)) { /* All entries from ent are considered to be lost. */ latest_ts = oldest_ts = ent->ts; last_lost_pkt_num = ent->hd.pkt_num; @@ -840,12 +844,31 @@ int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, } } - /* TODO Limit the number of LOST_RETRANSMITTED entries under maximum - reordering threshold. */ + ngtcp2_rtb_remove_excessive_lost_pkt(rtb, pkt_thres); return 0; } +void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { + ngtcp2_ksl_it it = ngtcp2_ksl_end(&rtb->ents); + ngtcp2_rtb_entry *ent; + + for (; rtb->num_lost_pkts > n;) { + assert(ngtcp2_ksl_it_end(&it)); + ngtcp2_ksl_it_prev(&it); + ent = ngtcp2_ksl_it_get(&it); + + assert(ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED); + + ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, + "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); + + --rtb->num_lost_pkts; + ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); + ngtcp2_rtb_entry_del(ent, rtb->mem); + } +} + void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, ngtcp2_tstamp ts) { ngtcp2_ksl_it it; @@ -871,6 +894,7 @@ void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, "removing stale lost pkn=%" PRId64, ent->hd.pkt_num); + --rtb->num_lost_pkts; ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); ngtcp2_rtb_entry_del(ent, rtb->mem); @@ -909,6 +933,10 @@ static void rtb_on_pkt_lost2(ngtcp2_rtb *rtb, ngtcp2_frame_chain **pfrc, } if (!(ent->flags & NGTCP2_RTB_FLAG_PROBE)) { + if (ent->flags & NGTCP2_RTB_FLAG_LOST_RETRANSMITTED) { + --rtb->num_lost_pkts; + } + if (ent->flags & NGTCP2_RTB_FLAG_CRYPTO_TIMEOUT_RETRANSMITTED) { ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, "pkn=%" PRId64 " CRYPTO has already been retransmitted", diff --git a/lib/ngtcp2_rtb.h b/lib/ngtcp2_rtb.h index b9f350fa857accb081b62610259bab3aa60b7f04..d74b56f075b7603586d25aaaee2438bdff2523fa 100644 --- a/lib/ngtcp2_rtb.h +++ b/lib/ngtcp2_rtb.h @@ -259,6 +259,9 @@ typedef struct { congestion evaluation is started. It happens roughly after handshake is confirmed. */ ngtcp2_tstamp persistent_congestion_start_ts; + /* num_lost_pkts is the number entries in ents which has + NGTCP2_RTB_FLAG_LOST_RETRANSMITTED flag set. */ + size_t num_lost_pkts; } ngtcp2_rtb; /* @@ -368,4 +371,10 @@ int ngtcp2_rtb_empty(ngtcp2_rtb *rtb); */ void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num); +/* + * ngtcp2_rtb_remove_expired_lost_pkt ensures that the number of lost + * packets at most |n|. + */ +void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n); + #endif /* NGTCP2_RTB_H */ diff --git a/tests/main.c b/tests/main.c index 3ac72fc1c92a86ce46adf71c233bc6ac949b00b1..1336eb82ce0c38bbea5f0804b1ca0298e05dae5d 100644 --- a/tests/main.c +++ b/tests/main.c @@ -169,6 +169,8 @@ int main() { !CU_add_test(pSuite, "rtb_lost_pkt_ts", test_ngtcp2_rtb_lost_pkt_ts) || !CU_add_test(pSuite, "rtb_remove_expired_lost_pkt", test_ngtcp2_rtb_remove_expired_lost_pkt) || + !CU_add_test(pSuite, "rtb_remove_excessive_lost_pkt", + test_ngtcp2_rtb_remove_excessive_lost_pkt) || !CU_add_test(pSuite, "idtr_open", test_ngtcp2_idtr_open) || !CU_add_test(pSuite, "ringbuf_push_front", test_ngtcp2_ringbuf_push_front) || diff --git a/tests/ngtcp2_rtb_test.c b/tests/ngtcp2_rtb_test.c index 3e303da36d37ec19f287b46af316bef9ebf8ab97..3f6c4f132d86128018c9d0769d28bcdd2a80181a 100644 --- a/tests/ngtcp2_rtb_test.c +++ b/tests/ngtcp2_rtb_test.c @@ -367,3 +367,45 @@ void test_ngtcp2_rtb_remove_expired_lost_pkt(void) { ngtcp2_cc_reno_cc_free(&cc, mem); ngtcp2_strm_free(&crypto); } + +void test_ngtcp2_rtb_remove_excessive_lost_pkt(void) { + ngtcp2_rtb rtb; + const ngtcp2_pktns_id pktns_id = NGTCP2_PKTNS_ID_APP; + ngtcp2_strm crypto; + ngtcp2_log log; + const ngtcp2_mem *mem = ngtcp2_mem_default(); + ngtcp2_cc cc; + ngtcp2_rst rst; + ngtcp2_conn_stat cstat; + ngtcp2_ksl_it it; + ngtcp2_rtb_entry *ent; + size_t i; + + ngtcp2_strm_init(&crypto, 0, NGTCP2_STRM_FLAG_NONE, 0, 0, NULL, mem); + ngtcp2_log_init(&log, NULL, NULL, 0, NULL); + + conn_stat_init(&cstat); + ngtcp2_rst_init(&rst); + ngtcp2_cc_reno_cc_init(&cc, &log, mem); + ngtcp2_rtb_init(&rtb, pktns_id, &crypto, &rst, &cc, &log, NULL, mem); + + add_rtb_entry_range(&rtb, 0, 7, &cstat, mem); + + it = ngtcp2_ksl_end(&rtb.ents); + + for (i = 0; i < 5; ++i) { + ngtcp2_ksl_it_prev(&it); + ent = ngtcp2_ksl_it_get(&it); + ent->flags |= NGTCP2_RTB_FLAG_LOST_RETRANSMITTED; + ent->lost_ts = 16777217; + ++rtb.num_lost_pkts; + } + + ngtcp2_rtb_remove_excessive_lost_pkt(&rtb, 2); + + CU_ASSERT(4 == ngtcp2_ksl_len(&rtb.ents)); + + ngtcp2_rtb_free(&rtb); + ngtcp2_cc_reno_cc_free(&cc, mem); + ngtcp2_strm_free(&crypto); +} diff --git a/tests/ngtcp2_rtb_test.h b/tests/ngtcp2_rtb_test.h index c9bf2f9671973f3fbd34939a9922809896756ac1..f880e1eb786cbf748c27c570725ef3e5951fe55e 100644 --- a/tests/ngtcp2_rtb_test.h +++ b/tests/ngtcp2_rtb_test.h @@ -33,5 +33,6 @@ void test_ngtcp2_rtb_add(void); void test_ngtcp2_rtb_recv_ack(void); void test_ngtcp2_rtb_lost_pkt_ts(void); void test_ngtcp2_rtb_remove_expired_lost_pkt(void); +void test_ngtcp2_rtb_remove_excessive_lost_pkt(void); #endif /* NGTCP2_RTB_TEST_H */