Skip to content

Commit 5133fd2

Browse files
a-denoyellehaproxyFred
authored andcommitted
MINOR: quic: support a max number of built packet per send iteration
1 parent 0b7fff8 commit 5133fd2

File tree

3 files changed

+71
-34
lines changed

3 files changed

+71
-34
lines changed

include/haproxy/quic_tx.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms);
3838
void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
3939
struct list *frms);
4040
int qel_need_sending(struct quic_enc_level *qel, struct quic_conn *qc);
41-
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list);
41+
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list,
42+
int max_dgrams);
4243

4344
int qc_dgrams_retransmit(struct quic_conn *qc);
4445
void qc_prep_hdshk_fast_retrans(struct quic_conn *qc,

src/quic_conn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
617617
if (qel_need_sending(qc->ael, qc))
618618
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
619619

620-
if (!qc_send(qc, 0, &send_list)) {
620+
if (!qc_send(qc, 0, &send_list, 0)) {
621621
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
622622
goto out;
623623
}
@@ -877,7 +877,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
877877
qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
878878
}
879879

880-
if (!qc_send(qc, 0, &send_list)) {
880+
if (!qc_send(qc, 0, &send_list, 0)) {
881881
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
882882
goto out;
883883
}

src/quic_tx.c

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -488,12 +488,12 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms)
488488
qc->state >= QUIC_HS_ST_COMPLETE) {
489489
quic_build_post_handshake_frames(qc);
490490
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
491-
qc_send(qc, 0, &send_list);
491+
qc_send(qc, 0, &send_list, 0);
492492
}
493493

494494
TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc);
495495
qel_register_send(&send_list, qc->ael, frms);
496-
ret = qc_send(qc, 0, &send_list);
496+
ret = qc_send(qc, 0, &send_list, 0);
497497

498498
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
499499
return ret;
@@ -520,18 +520,21 @@ static inline void qc_select_tls_ver(struct quic_conn *qc,
520520
}
521521
}
522522

523-
/* Prepare as much as possible QUIC datagrams/packets for sending from <qels>
524-
* list of encryption levels. Several packets can be coalesced into a single
523+
/* Prepare one or several QUIC datagrams/packets for sending from <qels> list
524+
* of encryption levels. Several packets can be coalesced into a single
525525
* datagram. The result is written into <buf>.
526526
*
527+
* If <max_dgrams> is non null, it limits the number of prepared datagrams.
528+
* Useful to support pacing emission.
529+
*
527530
* Each datagram is prepended by a two fields header : the datagram length and
528531
* the address of first packet in the datagram.
529532
*
530-
* Returns the number of bytes prepared in datragrams/packets if succeeded
531-
* (may be 0), or -1 if something wrong happened.
533+
* Returns the number of prepared datagrams on success which may be 0. On error
534+
* a negative error code is returned.
532535
*/
533536
static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
534-
struct list *qels)
537+
struct list *qels, int max_dgrams)
535538
{
536539
int ret, cc, padding;
537540
struct quic_tx_packet *first_pkt, *prv_pkt;
@@ -540,7 +543,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
540543
uint16_t dglen;
541544
size_t total;
542545
struct quic_enc_level *qel, *tmp_qel;
543-
uchar gso_dgram_cnt = 0;
546+
uchar dgram_cnt = 0, gso_dgram_cnt = 0;
544547

545548
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
546549
/* Currently qc_prep_pkts() does not handle buffer wrapping so the
@@ -590,6 +593,15 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
590593

591594
TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel);
592595

596+
/* Start to decrement <max_dgrams> after the first packet built. */
597+
if (!dglen && pos != (unsigned char *)b_head(buf)) {
598+
if (max_dgrams && !--max_dgrams) {
599+
BUG_ON(LIST_ISEMPTY(frms));
600+
TRACE_PROTO("reached max allowed built datagrams", QUIC_EV_CONN_PHPKTS, qc, qel);
601+
goto out;
602+
}
603+
}
604+
593605
if (!first_pkt)
594606
pos += QUIC_DGRAM_HEADLEN;
595607

@@ -657,8 +669,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
657669
* except if it is an too short Initial.
658670
*/
659671
if (first_pkt && (first_pkt->type != QUIC_PACKET_TYPE_INITIAL ||
660-
wrlen >= QUIC_INITIAL_PACKET_MINLEN))
672+
wrlen >= QUIC_INITIAL_PACKET_MINLEN)) {
661673
qc_txb_store(buf, wrlen, first_pkt);
674+
++dgram_cnt;
675+
}
662676
TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel);
663677
break;
664678

@@ -727,6 +741,8 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
727741
prv_pkt = cur_pkt;
728742
dglen = 0;
729743

744+
++dgram_cnt;
745+
730746
/* man 7 udp UDP_SEGMENT
731747
* The segment size must be chosen such that at
732748
* most 64 datagrams are sent in a single call
@@ -740,6 +756,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
740756
wrlen = dglen = 0;
741757
padding = 0;
742758
prv_pkt = NULL;
759+
++dgram_cnt;
743760
gso_dgram_cnt = 0;
744761
}
745762

@@ -753,16 +770,18 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
753770
}
754771

755772
out:
756-
if (first_pkt)
773+
if (first_pkt) {
757774
qc_txb_store(buf, wrlen, first_pkt);
775+
++dgram_cnt;
776+
}
758777

759778
if (cc && total) {
760779
BUG_ON(buf != &qc->tx.cc_buf);
761780
BUG_ON(dglen != total);
762781
qc->tx.cc_dgram_len = dglen;
763782
}
764783

765-
ret = total;
784+
ret = dgram_cnt;
766785
leave:
767786
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
768787
return ret;
@@ -772,13 +791,21 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
772791
* specified via quic_enc_level <send_list> through their send_frms member. Set
773792
* <old_data> when reemitted duplicated data.
774793
*
775-
* Returns 1 on success else 0. Note that <send_list> will always be reset
776-
* after qc_send() exit.
794+
* If <max_dgrams> is non null, it limits the number of emitted datagrams.
795+
* Useful to support pacing emission.
796+
*
797+
* Note that <send_list> will always be emptied on function completion, both on
798+
* success and error.
799+
*
800+
* Returns the number of sent datagrams on success. It means either that all
801+
* input frames were sent or emission is interrupted due to pacing. Else a
802+
* negative error code is returned.
777803
*/
778-
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
804+
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list,
805+
int max_dgrams)
779806
{
780807
struct quic_enc_level *qel, *tmp_qel;
781-
int ret = 0, status = 0;
808+
int prep_pkts = 0, ret = -1;
782809
struct buffer *buf;
783810

784811
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
@@ -806,25 +833,36 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
806833
while (!LIST_ISEMPTY(send_list) &&
807834
(!(qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) ||
808835
(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))) {
836+
837+
if (ret < 0)
838+
ret = 0;
839+
809840
/* Buffer must always be empty before qc_prep_pkts() usage.
810841
* qc_send_ppkts() ensures it is cleared on success.
811842
*/
812843
BUG_ON_HOT(b_data(buf));
813844
b_reset(buf);
814845

815-
ret = qc_prep_pkts(qc, buf, send_list);
846+
prep_pkts = qc_prep_pkts(qc, buf, send_list, max_dgrams);
816847

817848
if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) {
849+
ret = -1;
818850
if (qc->flags & QUIC_FL_CONN_TO_KILL)
819851
qc_txb_release(qc);
820852
goto out;
821853
}
822854

823-
if (ret <= 0) {
855+
if (prep_pkts <= 0) {
824856
TRACE_DEVEL("stopping on qc_prep_pkts() return", QUIC_EV_CONN_TXPKT, qc);
825857
break;
826858
}
827859

860+
ret += prep_pkts;
861+
if (max_dgrams && ret == max_dgrams && !LIST_ISEMPTY(send_list)) {
862+
TRACE_DEVEL("stopping for artificial pacing", QUIC_EV_CONN_TXPKT, qc);
863+
break;
864+
}
865+
828866
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
829867
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) {
830868
TRACE_DEVEL("draining connection", QUIC_EV_CONN_TXPKT, qc);
@@ -836,8 +874,6 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
836874
if (ret < 0)
837875
goto out;
838876

839-
status = 1;
840-
841877
out:
842878
if (old_data) {
843879
TRACE_STATE("no more need old data for probing", QUIC_EV_CONN_TXPKT, qc);
@@ -850,8 +886,8 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
850886
qel->send_frms = NULL;
851887
}
852888

853-
TRACE_DEVEL((status ? "leaving" : "leaving in error"), QUIC_EV_CONN_TXPKT, qc);
854-
return status;
889+
TRACE_DEVEL((ret > 0 ? "leaving" : "leaving in error"), QUIC_EV_CONN_TXPKT, qc);
890+
return ret;
855891
}
856892

857893
/* Insert <qel> into <send_list> in preparation for sending. Set its send
@@ -915,10 +951,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
915951
if (qc->hel)
916952
qel_register_send(&send_list, qc->hel, &hfrms);
917953

918-
sret = qc_send(qc, 1, &send_list);
954+
sret = qc_send(qc, 1, &send_list, 0);
919955
qc_free_frm_list(qc, &ifrms);
920956
qc_free_frm_list(qc, &hfrms);
921-
if (!sret)
957+
if (sret < 0)
922958
goto leave;
923959
}
924960
else {
@@ -928,10 +964,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
928964
*/
929965
ipktns->tx.pto_probe = 1;
930966
qel_register_send(&send_list, qc->iel, &ifrms);
931-
sret = qc_send(qc, 0, &send_list);
967+
sret = qc_send(qc, 0, &send_list, 0);
932968
qc_free_frm_list(qc, &ifrms);
933969
qc_free_frm_list(qc, &hfrms);
934-
if (!sret)
970+
if (sret < 0)
935971
goto leave;
936972

937973
break;
@@ -957,9 +993,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
957993
if (!LIST_ISEMPTY(&frms1)) {
958994
hpktns->tx.pto_probe = 1;
959995
qel_register_send(&send_list, qc->hel, &frms1);
960-
sret = qc_send(qc, 1, &send_list);
996+
sret = qc_send(qc, 1, &send_list, 0);
961997
qc_free_frm_list(qc, &frms1);
962-
if (!sret)
998+
if (sret < 0)
963999
goto leave;
9641000
}
9651001
}
@@ -980,9 +1016,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9801016
if (!LIST_ISEMPTY(&frms1)) {
9811017
apktns->tx.pto_probe = 1;
9821018
qel_register_send(&send_list, qc->ael, &frms1);
983-
sret = qc_send(qc, 1, &send_list);
1019+
sret = qc_send(qc, 1, &send_list, 0);
9841020
qc_free_frm_list(qc, &frms1);
985-
if (!sret) {
1021+
if (sret < 0) {
9861022
qc_free_frm_list(qc, &frms2);
9871023
goto leave;
9881024
}
@@ -991,9 +1027,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9911027
if (!LIST_ISEMPTY(&frms2)) {
9921028
apktns->tx.pto_probe = 1;
9931029
qel_register_send(&send_list, qc->ael, &frms2);
994-
sret = qc_send(qc, 1, &send_list);
1030+
sret = qc_send(qc, 1, &send_list, 0);
9951031
qc_free_frm_list(qc, &frms2);
996-
if (!sret)
1032+
if (sret < 0)
9971033
goto leave;
9981034
}
9991035
TRACE_STATE("no more need to probe 01RTT packet number space",

0 commit comments

Comments
 (0)