Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8587:61f1c6ac8967 quic
QUIC: added ACK frame range support.
The history of acknowledged packet is kept in send context as ranges.
Up to NGX_QUIC_MAX_RANGES ranges is stored.
As a result, instead of separate ack frames, single frame with ranges
is sent.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 14 Oct 2020 23:21:36 +0300 |
parents | 02ee77f8d53d |
children | 018baa412c0d |
comparison
equal
deleted
inserted
replaced
8586:7621ffaa79b3 | 8587:61f1c6ac8967 |
---|---|
91 */ | 91 */ |
92 typedef struct { | 92 typedef struct { |
93 ngx_quic_secret_t client_secret; | 93 ngx_quic_secret_t client_secret; |
94 ngx_quic_secret_t server_secret; | 94 ngx_quic_secret_t server_secret; |
95 | 95 |
96 enum ssl_encryption_level_t level; | |
97 | |
96 uint64_t pnum; /* to be sent */ | 98 uint64_t pnum; /* to be sent */ |
97 uint64_t largest_ack; /* received from peer */ | 99 uint64_t largest_ack; /* received from peer */ |
98 uint64_t largest_pn; /* received from peer */ | 100 uint64_t largest_pn; /* received from peer */ |
99 | 101 |
100 ngx_queue_t frames; | 102 ngx_queue_t frames; |
101 ngx_queue_t sent; | 103 ngx_queue_t sent; |
104 | |
105 uint64_t largest_range; | |
106 uint64_t first_range; | |
107 ngx_uint_t nranges; | |
108 ngx_quic_ack_range_t ranges[NGX_QUIC_MAX_RANGES]; | |
109 struct timeval ack_received; | |
110 ngx_uint_t send_ack; /* unsigned send_ack:1 */ | |
102 } ngx_quic_send_ctx_t; | 111 } ngx_quic_send_ctx_t; |
103 | 112 |
104 | 113 |
105 struct ngx_quic_connection_s { | 114 struct ngx_quic_connection_s { |
106 ngx_str_t scid; /* initial client ID */ | 115 ngx_str_t scid; /* initial client ID */ |
228 enum ssl_encryption_level_t level); | 237 enum ssl_encryption_level_t level); |
229 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, | 238 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, |
230 ngx_quic_header_t *pkt); | 239 ngx_quic_header_t *pkt); |
231 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, | 240 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, |
232 ngx_quic_header_t *pkt); | 241 ngx_quic_header_t *pkt); |
233 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); | 242 static ngx_int_t ngx_quic_ack_packet(ngx_connection_t *c, |
243 ngx_quic_header_t *pkt); | |
244 static ngx_int_t ngx_quic_send_ack_range(ngx_connection_t *c, | |
245 ngx_quic_send_ctx_t *ctx, uint64_t smallest, uint64_t largest); | |
246 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, | |
247 ngx_quic_send_ctx_t *ctx); | |
234 static ngx_int_t ngx_quic_ack_delay(ngx_connection_t *c, | 248 static ngx_int_t ngx_quic_ack_delay(ngx_connection_t *c, |
235 struct timeval *received, enum ssl_encryption_level_t level); | 249 struct timeval *received, enum ssl_encryption_level_t level); |
236 static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); | 250 static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); |
237 static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); | 251 static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); |
238 | 252 |
683 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 697 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
684 ngx_queue_init(&qc->send_ctx[i].frames); | 698 ngx_queue_init(&qc->send_ctx[i].frames); |
685 ngx_queue_init(&qc->send_ctx[i].sent); | 699 ngx_queue_init(&qc->send_ctx[i].sent); |
686 qc->send_ctx[i].largest_pn = (uint64_t) -1; | 700 qc->send_ctx[i].largest_pn = (uint64_t) -1; |
687 qc->send_ctx[i].largest_ack = (uint64_t) -1; | 701 qc->send_ctx[i].largest_ack = (uint64_t) -1; |
688 } | 702 qc->send_ctx[i].largest_range = (uint64_t) -1; |
703 } | |
704 | |
705 qc->send_ctx[0].level = ssl_encryption_initial; | |
706 qc->send_ctx[1].level = ssl_encryption_handshake; | |
707 qc->send_ctx[2].level = ssl_encryption_application; | |
689 | 708 |
690 for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { | 709 for (i = 0; i < NGX_QUIC_ENCRYPTION_LAST; i++) { |
691 ngx_queue_init(&qc->crypto[i].frames); | 710 ngx_queue_init(&qc->crypto[i].frames); |
692 } | 711 } |
693 | 712 |
1972 | 1991 |
1973 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 1992 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
1974 ngx_quic_congestion_ack(c, f); | 1993 ngx_quic_congestion_ack(c, f); |
1975 ngx_quic_free_frame(c, f); | 1994 ngx_quic_free_frame(c, f); |
1976 } | 1995 } |
1996 | |
1997 ctx->send_ack = 0; | |
1977 } | 1998 } |
1978 | 1999 |
1979 | 2000 |
1980 static ngx_int_t | 2001 static ngx_int_t |
1981 ngx_quic_check_peer(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) | 2002 ngx_quic_check_peer(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) |
2107 } | 2128 } |
2108 | 2129 |
2109 /* got there with ack-eliciting packet */ | 2130 /* got there with ack-eliciting packet */ |
2110 | 2131 |
2111 if (!ack_sent) { | 2132 if (!ack_sent) { |
2112 if (ngx_quic_send_ack(c, pkt) != NGX_OK) { | 2133 if (ngx_quic_ack_packet(c, pkt) != NGX_OK) { |
2113 return NGX_ERROR; | 2134 return NGX_ERROR; |
2114 } | 2135 } |
2115 | 2136 |
2116 ack_sent = 1; | 2137 ack_sent = 1; |
2117 } | 2138 } |
2272 return NGX_OK; | 2293 return NGX_OK; |
2273 } | 2294 } |
2274 | 2295 |
2275 | 2296 |
2276 static ngx_int_t | 2297 static ngx_int_t |
2277 ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt) | 2298 ngx_quic_ack_packet(ngx_connection_t *c, ngx_quic_header_t *pkt) |
2299 { | |
2300 uint64_t base, largest, smallest, gs, ge, gap, range, pn; | |
2301 ngx_uint_t i, j, nr; | |
2302 ngx_quic_send_ctx_t *ctx; | |
2303 ngx_quic_ack_range_t *r; | |
2304 | |
2305 c->log->action = "preparing ack"; | |
2306 | |
2307 ctx = ngx_quic_get_send_ctx(c->quic, pkt->level); | |
2308 | |
2309 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
2310 "ngx_quic_ack_packet pn %uL largest %uL nranges %ui", | |
2311 pkt->pn, ctx->largest_range, ctx->nranges); | |
2312 | |
2313 if (!ctx->send_ack) { | |
2314 ngx_post_event(&c->quic->push, &ngx_posted_events); | |
2315 } | |
2316 | |
2317 ctx->send_ack = 1; | |
2318 | |
2319 base = ctx->largest_range; | |
2320 pn = pkt->pn; | |
2321 | |
2322 if (base == (uint64_t) -1) { | |
2323 ctx->largest_range = pn; | |
2324 ctx->ack_received = pkt->received; | |
2325 return NGX_OK; | |
2326 } | |
2327 | |
2328 if (base == pn) { | |
2329 return NGX_OK; | |
2330 } | |
2331 | |
2332 largest = base; | |
2333 smallest = largest - ctx->first_range; | |
2334 | |
2335 if (pn > base) { | |
2336 ctx->largest_range = pn; | |
2337 ctx->ack_received = pkt->received; | |
2338 | |
2339 if (pn - base == 1) { | |
2340 ctx->first_range++; | |
2341 return NGX_OK; | |
2342 | |
2343 } else { | |
2344 /* new gap in front of current largest */ | |
2345 gap = pn - base - 2; | |
2346 range = ctx->first_range; | |
2347 | |
2348 ctx->first_range = 0; | |
2349 i = 0; | |
2350 | |
2351 goto insert; | |
2352 } | |
2353 } | |
2354 | |
2355 /* pn < base, perform lookup in existing ranges */ | |
2356 | |
2357 if (pn >= smallest && pn <= largest) { | |
2358 return NGX_OK; | |
2359 } | |
2360 | |
2361 #if (NGX_SUPPRESS_WARN) | |
2362 r = NULL; | |
2363 #endif | |
2364 | |
2365 for (i = 0; i < ctx->nranges; i++) { | |
2366 r = &ctx->ranges[i]; | |
2367 | |
2368 ge = smallest - 1; | |
2369 gs = ge - r->gap; | |
2370 | |
2371 if (pn >= gs && pn <= ge) { | |
2372 | |
2373 if (gs == ge) { | |
2374 /* gap size is exactly one packet, now filled */ | |
2375 | |
2376 /* data moves to previous range, current is removed */ | |
2377 | |
2378 if (i == 0) { | |
2379 ctx->first_range += r->range + 2; | |
2380 | |
2381 } else { | |
2382 ctx->ranges[i - 1].range += r->range + 2; | |
2383 } | |
2384 | |
2385 nr = ctx->nranges - i - 1; | |
2386 if (nr) { | |
2387 ngx_memmove(&ctx->ranges[i], &ctx->ranges[i + 1], | |
2388 sizeof(ngx_quic_ack_range_t) * nr); | |
2389 } | |
2390 | |
2391 ctx->nranges--; | |
2392 | |
2393 } else if (pn == gs) { | |
2394 /* current gap shrinks from tail (current range grows) */ | |
2395 r->gap--; | |
2396 r->range++; | |
2397 | |
2398 } else if (pn == ge) { | |
2399 /* current gap shrinks from head (previous range grows) */ | |
2400 r->gap--; | |
2401 | |
2402 if (i == 0) { | |
2403 ctx->first_range++; | |
2404 | |
2405 } else { | |
2406 ctx->ranges[i - 1].range++; | |
2407 } | |
2408 | |
2409 } else { | |
2410 /* current gap is split into two parts */ | |
2411 | |
2412 r->gap = pn - gs - 1; | |
2413 gap = ge - pn - 1; | |
2414 range = 0; | |
2415 | |
2416 goto insert; | |
2417 } | |
2418 | |
2419 return NGX_OK; | |
2420 } | |
2421 | |
2422 largest = smallest - r->gap - 2; | |
2423 smallest = largest - r->range; | |
2424 | |
2425 if (pn >= smallest && pn <= largest) { | |
2426 /* this packet number is already known */ | |
2427 return NGX_OK; | |
2428 } | |
2429 | |
2430 } | |
2431 | |
2432 if (pn == smallest - 1) { | |
2433 /* extend first or last range */ | |
2434 | |
2435 if (i == 0) { | |
2436 ctx->first_range++; | |
2437 | |
2438 } else { | |
2439 r->range++; | |
2440 } | |
2441 | |
2442 return NGX_OK; | |
2443 } | |
2444 | |
2445 /* nothing found, add new range at the tail */ | |
2446 | |
2447 if (ctx->nranges == NGX_QUIC_MAX_RANGES) { | |
2448 /* packet is too old to keep it */ | |
2449 return ngx_quic_send_ack_range(c, ctx, pn, pn); | |
2450 } | |
2451 | |
2452 gap = smallest - 2 - pn; | |
2453 range = 0; | |
2454 | |
2455 insert: | |
2456 | |
2457 nr = ctx->nranges - i; | |
2458 | |
2459 if (ctx->nranges == NGX_QUIC_MAX_RANGES) { | |
2460 /* last range is dropped and reused for newer data */ | |
2461 | |
2462 for (j = i; j < ctx->nranges; j++) { | |
2463 largest = smallest - ctx->ranges[j].gap - 2; | |
2464 smallest = largest - ctx->ranges[j].range; | |
2465 } | |
2466 | |
2467 if (ngx_quic_send_ack_range(c, ctx, smallest, largest) != NGX_OK) { | |
2468 return NGX_ERROR; | |
2469 } | |
2470 | |
2471 nr--; | |
2472 | |
2473 } else { | |
2474 ctx->nranges++; | |
2475 } | |
2476 | |
2477 ngx_memmove(&ctx->ranges[i + 1], &ctx->ranges[i], | |
2478 sizeof(ngx_quic_ack_range_t) * nr); | |
2479 | |
2480 ctx->ranges[i].gap = gap; | |
2481 ctx->ranges[i].range = range; | |
2482 | |
2483 return NGX_OK; | |
2484 } | |
2485 | |
2486 | |
2487 static ngx_int_t | |
2488 ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, | |
2489 uint64_t smallest, uint64_t largest) | |
2278 { | 2490 { |
2279 ngx_quic_frame_t *frame; | 2491 ngx_quic_frame_t *frame; |
2280 | |
2281 c->log->action = "generating acknowledgment"; | |
2282 | |
2283 /* every ACK-eliciting packet is acknowledged, TODO ACK Ranges */ | |
2284 | 2492 |
2285 frame = ngx_quic_alloc_frame(c, 0); | 2493 frame = ngx_quic_alloc_frame(c, 0); |
2286 if (frame == NULL) { | 2494 if (frame == NULL) { |
2287 return NGX_ERROR; | 2495 return NGX_ERROR; |
2288 } | 2496 } |
2289 | 2497 |
2290 frame->level = (pkt->level == ssl_encryption_early_data) | 2498 frame->level = ctx->level; |
2291 ? ssl_encryption_application | |
2292 : pkt->level; | |
2293 | |
2294 frame->type = NGX_QUIC_FT_ACK; | 2499 frame->type = NGX_QUIC_FT_ACK; |
2295 frame->u.ack.largest = pkt->pn; | 2500 frame->u.ack.largest = largest; |
2296 frame->u.ack.delay = ngx_quic_ack_delay(c, &pkt->received, frame->level); | 2501 frame->u.ack.delay = 0; |
2297 | 2502 frame->u.ack.range_count = 0; |
2298 ngx_sprintf(frame->info, "ACK for PN=%uL from frame handler level=%d", | 2503 frame->u.ack.first_range = largest - smallest; |
2299 pkt->pn, frame->level); | 2504 |
2505 ngx_sprintf(frame->info, "ACK for PN=%uL..%uL 0 ranges level=%d", | |
2506 largest, smallest, frame->level); | |
2507 | |
2508 return NGX_OK; | |
2509 } | |
2510 | |
2511 | |
2512 static ngx_int_t | |
2513 ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) | |
2514 { | |
2515 size_t ranges_len; | |
2516 ngx_quic_frame_t *frame; | |
2517 | |
2518 ranges_len = sizeof(ngx_quic_ack_range_t) * ctx->nranges; | |
2519 | |
2520 frame = ngx_quic_alloc_frame(c, ranges_len); | |
2521 if (frame == NULL) { | |
2522 return NGX_ERROR; | |
2523 } | |
2524 | |
2525 ngx_memcpy(frame->data, ctx->ranges, ranges_len); | |
2526 | |
2527 frame->level = ctx->level; | |
2528 frame->type = NGX_QUIC_FT_ACK; | |
2529 frame->u.ack.largest = ctx->largest_range; | |
2530 frame->u.ack.delay = ngx_quic_ack_delay(c, &ctx->ack_received, ctx->level); | |
2531 frame->u.ack.range_count = ctx->nranges; | |
2532 frame->u.ack.first_range = ctx->first_range; | |
2533 frame->u.ack.ranges_start = frame->data; | |
2534 frame->u.ack.ranges_end = frame->data + ranges_len; | |
2535 | |
2536 ngx_sprintf(frame->info, "ACK for PN=%uL %ui ranges level=%d", | |
2537 ctx->largest_range, ctx->nranges, frame->level); | |
2538 | |
2300 ngx_quic_queue_frame(c->quic, frame); | 2539 ngx_quic_queue_frame(c->quic, frame); |
2540 | |
2541 ctx->send_ack = 0; | |
2301 | 2542 |
2302 return NGX_OK; | 2543 return NGX_OK; |
2303 } | 2544 } |
2304 | 2545 |
2305 | 2546 |
3710 | 3951 |
3711 static ngx_int_t | 3952 static ngx_int_t |
3712 ngx_quic_output(ngx_connection_t *c) | 3953 ngx_quic_output(ngx_connection_t *c) |
3713 { | 3954 { |
3714 ngx_uint_t i; | 3955 ngx_uint_t i; |
3956 ngx_quic_send_ctx_t *ctx; | |
3715 ngx_quic_connection_t *qc; | 3957 ngx_quic_connection_t *qc; |
3716 | 3958 |
3717 c->log->action = "sending frames"; | 3959 c->log->action = "sending frames"; |
3718 | 3960 |
3719 qc = c->quic; | 3961 qc = c->quic; |
3720 | 3962 |
3721 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 3963 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
3722 if (ngx_quic_output_frames(c, &qc->send_ctx[i]) != NGX_OK) { | 3964 |
3965 ctx = &qc->send_ctx[i]; | |
3966 | |
3967 if (ctx->send_ack) { | |
3968 if (ngx_quic_send_ack(c, ctx) != NGX_OK) { | |
3969 return NGX_ERROR; | |
3970 } | |
3971 } | |
3972 | |
3973 if (ngx_quic_output_frames(c, ctx) != NGX_OK) { | |
3723 return NGX_ERROR; | 3974 return NGX_ERROR; |
3724 } | 3975 } |
3725 } | 3976 } |
3726 | 3977 |
3727 if (!qc->send_timer_set && !qc->closing) { | 3978 if (!qc->send_timer_set && !qc->closing) { |