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