Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_output.c @ 9192:efcdaa66df2e
QUIC: congestion control in ngx_quic_frame_sendto().
Previously ngx_quic_frame_sendto() ignored congestion control and did not
contribute to in_flight counter.
Now congestion control window is checked unless ignore_congestion flag is set.
Also, in_flight counter is incremented and the frame is stored in ctx->sent
queue if it's ack-eliciting. This behavior is now similar to
ngx_quic_output_packet().
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 29 Nov 2023 21:41:29 +0400 |
parents | 3a67dd34b6cc |
children | ce1ff81e9b92 |
comparison
equal
deleted
inserted
replaced
9191:618132842e7c | 9192:efcdaa66df2e |
---|---|
842 | 842 |
843 | 843 |
844 ngx_int_t | 844 ngx_int_t |
845 ngx_quic_send_cc(ngx_connection_t *c) | 845 ngx_quic_send_cc(ngx_connection_t *c) |
846 { | 846 { |
847 ngx_quic_frame_t frame; | 847 ngx_quic_frame_t *frame; |
848 ngx_quic_connection_t *qc; | 848 ngx_quic_connection_t *qc; |
849 | 849 |
850 qc = ngx_quic_get_connection(c); | 850 qc = ngx_quic_get_connection(c); |
851 | 851 |
852 if (qc->draining) { | 852 if (qc->draining) { |
858 { | 858 { |
859 /* dot not send CC too often */ | 859 /* dot not send CC too often */ |
860 return NGX_OK; | 860 return NGX_OK; |
861 } | 861 } |
862 | 862 |
863 ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); | 863 frame = ngx_quic_alloc_frame(c); |
864 | 864 if (frame == NULL) { |
865 frame.level = qc->error_level; | 865 return NGX_ERROR; |
866 frame.type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP | 866 } |
867 : NGX_QUIC_FT_CONNECTION_CLOSE; | 867 |
868 frame.u.close.error_code = qc->error; | 868 frame->level = qc->error_level; |
869 frame.u.close.frame_type = qc->error_ftype; | 869 frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP |
870 : NGX_QUIC_FT_CONNECTION_CLOSE; | |
871 frame->u.close.error_code = qc->error; | |
872 frame->u.close.frame_type = qc->error_ftype; | |
870 | 873 |
871 if (qc->error_reason) { | 874 if (qc->error_reason) { |
872 frame.u.close.reason.len = ngx_strlen(qc->error_reason); | 875 frame->u.close.reason.len = ngx_strlen(qc->error_reason); |
873 frame.u.close.reason.data = (u_char *) qc->error_reason; | 876 frame->u.close.reason.data = (u_char *) qc->error_reason; |
874 } | 877 } |
878 | |
879 frame->ignore_congestion = 1; | |
875 | 880 |
876 qc->last_cc = ngx_current_msec; | 881 qc->last_cc = ngx_current_msec; |
877 | 882 |
878 return ngx_quic_frame_sendto(c, &frame, 0, qc->path); | 883 return ngx_quic_frame_sendto(c, frame, 0, qc->path); |
879 } | 884 } |
880 | 885 |
881 | 886 |
882 ngx_int_t | 887 ngx_int_t |
883 ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, | 888 ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, |
1182 size_t min, ngx_quic_path_t *path) | 1187 size_t min, ngx_quic_path_t *path) |
1183 { | 1188 { |
1184 size_t max, max_payload, min_payload, pad; | 1189 size_t max, max_payload, min_payload, pad; |
1185 ssize_t len, sent; | 1190 ssize_t len, sent; |
1186 ngx_str_t res; | 1191 ngx_str_t res; |
1192 ngx_msec_t now; | |
1187 ngx_quic_header_t pkt; | 1193 ngx_quic_header_t pkt; |
1188 ngx_quic_send_ctx_t *ctx; | 1194 ngx_quic_send_ctx_t *ctx; |
1195 ngx_quic_congestion_t *cg; | |
1189 ngx_quic_connection_t *qc; | 1196 ngx_quic_connection_t *qc; |
1190 | 1197 |
1191 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 1198 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
1192 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 1199 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
1193 | 1200 |
1194 qc = ngx_quic_get_connection(c); | 1201 qc = ngx_quic_get_connection(c); |
1202 cg = &qc->congestion; | |
1195 ctx = ngx_quic_get_send_ctx(qc, frame->level); | 1203 ctx = ngx_quic_get_send_ctx(qc, frame->level); |
1204 | |
1205 now = ngx_current_msec; | |
1196 | 1206 |
1197 max = ngx_quic_path_limit(c, path, path->mtu); | 1207 max = ngx_quic_path_limit(c, path, path->mtu); |
1198 | 1208 |
1199 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1209 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1200 "quic sendto %s packet max:%uz min:%uz", | 1210 "quic sendto %s packet max:%uz min:%uz", |
1201 ngx_quic_level_name(ctx->level), max, min); | 1211 ngx_quic_level_name(ctx->level), max, min); |
1202 | 1212 |
1213 if (cg->in_flight >= cg->window && !frame->ignore_congestion) { | |
1214 ngx_quic_free_frame(c, frame); | |
1215 return NGX_AGAIN; | |
1216 } | |
1217 | |
1203 ngx_quic_init_packet(c, ctx, &pkt, path); | 1218 ngx_quic_init_packet(c, ctx, &pkt, path); |
1204 | 1219 |
1205 min_payload = ngx_quic_payload_size(&pkt, min); | 1220 min_payload = ngx_quic_payload_size(&pkt, min); |
1206 max_payload = ngx_quic_payload_size(&pkt, max); | 1221 max_payload = ngx_quic_payload_size(&pkt, max); |
1207 | 1222 |
1208 /* RFC 9001, 5.4.2. Header Protection Sample */ | 1223 /* RFC 9001, 5.4.2. Header Protection Sample */ |
1209 pad = 4 - pkt.num_len; | 1224 pad = 4 - pkt.num_len; |
1210 min_payload = ngx_max(min_payload, pad); | 1225 min_payload = ngx_max(min_payload, pad); |
1211 | 1226 |
1212 if (min_payload > max_payload) { | 1227 if (min_payload > max_payload) { |
1228 ngx_quic_free_frame(c, frame); | |
1213 return NGX_AGAIN; | 1229 return NGX_AGAIN; |
1214 } | 1230 } |
1215 | 1231 |
1216 #if (NGX_DEBUG) | 1232 #if (NGX_DEBUG) |
1217 frame->pnum = pkt.number; | 1233 frame->pnum = pkt.number; |
1219 | 1235 |
1220 ngx_quic_log_frame(c->log, frame, 1); | 1236 ngx_quic_log_frame(c->log, frame, 1); |
1221 | 1237 |
1222 len = ngx_quic_create_frame(NULL, frame); | 1238 len = ngx_quic_create_frame(NULL, frame); |
1223 if ((size_t) len > max_payload) { | 1239 if ((size_t) len > max_payload) { |
1240 ngx_quic_free_frame(c, frame); | |
1224 return NGX_AGAIN; | 1241 return NGX_AGAIN; |
1225 } | 1242 } |
1226 | 1243 |
1227 len = ngx_quic_create_frame(src, frame); | 1244 len = ngx_quic_create_frame(src, frame); |
1228 if (len == -1) { | 1245 if (len == -1) { |
1246 ngx_quic_free_frame(c, frame); | |
1229 return NGX_ERROR; | 1247 return NGX_ERROR; |
1230 } | 1248 } |
1231 | 1249 |
1232 if (len < (ssize_t) min_payload) { | 1250 if (len < (ssize_t) min_payload) { |
1233 ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len); | 1251 ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len); |
1240 res.data = dst; | 1258 res.data = dst; |
1241 | 1259 |
1242 ngx_quic_log_packet(c->log, &pkt); | 1260 ngx_quic_log_packet(c->log, &pkt); |
1243 | 1261 |
1244 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { | 1262 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { |
1245 return NGX_ERROR; | 1263 ngx_quic_free_frame(c, frame); |
1246 } | 1264 return NGX_ERROR; |
1265 } | |
1266 | |
1267 frame->pnum = ctx->pnum; | |
1268 frame->first = now; | |
1269 frame->last = now; | |
1270 frame->plen = res.len; | |
1247 | 1271 |
1248 ctx->pnum++; | 1272 ctx->pnum++; |
1249 | 1273 |
1250 sent = ngx_quic_send(c, res.data, res.len, path->sockaddr, path->socklen); | 1274 sent = ngx_quic_send(c, res.data, res.len, path->sockaddr, path->socklen); |
1251 if (sent < 0) { | 1275 if (sent < 0) { |
1276 ngx_quic_free_frame(c, frame); | |
1252 return sent; | 1277 return sent; |
1253 } | 1278 } |
1254 | 1279 |
1255 path->sent += sent; | 1280 path->sent += sent; |
1281 | |
1282 if (frame->need_ack && !qc->closing) { | |
1283 ngx_queue_insert_tail(&ctx->sent, &frame->queue); | |
1284 | |
1285 cg->in_flight += frame->plen; | |
1286 | |
1287 } else { | |
1288 ngx_quic_free_frame(c, frame); | |
1289 return NGX_OK; | |
1290 } | |
1291 | |
1292 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1293 "quic congestion send if:%uz", cg->in_flight); | |
1294 | |
1295 if (!qc->send_timer_set) { | |
1296 qc->send_timer_set = 1; | |
1297 ngx_add_timer(c->read, qc->tp.max_idle_timeout); | |
1298 } | |
1299 | |
1300 ngx_quic_set_lost_timer(c); | |
1256 | 1301 |
1257 return NGX_OK; | 1302 return NGX_OK; |
1258 } | 1303 } |
1259 | 1304 |
1260 | 1305 |