@@ -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 */
533536static 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