@@ -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
@@ -647,8 +659,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
647659 * except if it is an too short Initial.
648660 */
649661 if (first_pkt && (first_pkt -> type != QUIC_PACKET_TYPE_INITIAL ||
650- wrlen >= QUIC_INITIAL_PACKET_MINLEN ))
662+ wrlen >= QUIC_INITIAL_PACKET_MINLEN )) {
651663 qc_txb_store (buf , wrlen , first_pkt );
664+ ++ dgram_cnt ;
665+ }
652666 TRACE_PROTO ("could not prepare anymore packet" , QUIC_EV_CONN_PHPKTS , qc , qel );
653667 break ;
654668
@@ -717,6 +731,8 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
717731 prv_pkt = cur_pkt ;
718732 dglen = 0 ;
719733
734+ ++ dgram_cnt ;
735+
720736 /* man 7 udp UDP_SEGMENT
721737 * The segment size must be chosen such that at
722738 * most 64 datagrams are sent in a single call
@@ -730,6 +746,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
730746 wrlen = dglen = 0 ;
731747 padding = 0 ;
732748 prv_pkt = NULL ;
749+ ++ dgram_cnt ;
733750 gso_dgram_cnt = 0 ;
734751 }
735752
@@ -743,16 +760,18 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
743760 }
744761
745762 out :
746- if (first_pkt )
763+ if (first_pkt ) {
747764 qc_txb_store (buf , wrlen , first_pkt );
765+ ++ dgram_cnt ;
766+ }
748767
749768 if (cc && total ) {
750769 BUG_ON (buf != & qc -> tx .cc_buf );
751770 BUG_ON (dglen != total );
752771 qc -> tx .cc_dgram_len = dglen ;
753772 }
754773
755- ret = total ;
774+ ret = dgram_cnt ;
756775 leave :
757776 TRACE_LEAVE (QUIC_EV_CONN_PHPKTS , qc );
758777 return ret ;
@@ -762,13 +781,21 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
762781 * specified via quic_enc_level <send_list> through their send_frms member. Set
763782 * <old_data> when reemitted duplicated data.
764783 *
765- * Returns 1 on success else 0. Note that <send_list> will always be reset
766- * after qc_send() exit.
784+ * If <max_dgrams> is non null, it limits the number of emitted datagrams.
785+ * Useful to support pacing emission.
786+ *
787+ * Note that <send_list> will always be emptied on function completion, both on
788+ * success and error.
789+ *
790+ * Returns the number of sent datagrams on success. It means either that all
791+ * input frames were sent or emission is interrupted due to pacing. Else a
792+ * negative error code is returned.
767793 */
768- int qc_send (struct quic_conn * qc , int old_data , struct list * send_list )
794+ int qc_send (struct quic_conn * qc , int old_data , struct list * send_list ,
795+ int max_dgrams )
769796{
770797 struct quic_enc_level * qel , * tmp_qel ;
771- int ret = 0 , status = 0 ;
798+ int prep_pkts = 0 , ret = -1 ;
772799 struct buffer * buf ;
773800
774801 TRACE_ENTER (QUIC_EV_CONN_TXPKT , qc );
@@ -796,25 +823,36 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
796823 while (!LIST_ISEMPTY (send_list ) &&
797824 (!(qc -> flags & (QUIC_FL_CONN_CLOSING |QUIC_FL_CONN_DRAINING )) ||
798825 (qc -> flags & QUIC_FL_CONN_IMMEDIATE_CLOSE ))) {
826+
827+ if (ret < 0 )
828+ ret = 0 ;
829+
799830 /* Buffer must always be empty before qc_prep_pkts() usage.
800831 * qc_send_ppkts() ensures it is cleared on success.
801832 */
802833 BUG_ON_HOT (b_data (buf ));
803834 b_reset (buf );
804835
805- ret = qc_prep_pkts (qc , buf , send_list );
836+ prep_pkts = qc_prep_pkts (qc , buf , send_list , max_dgrams );
806837
807838 if (b_data (buf ) && !qc_send_ppkts (buf , qc -> xprt_ctx )) {
839+ ret = -1 ;
808840 if (qc -> flags & QUIC_FL_CONN_TO_KILL )
809841 qc_txb_release (qc );
810842 goto out ;
811843 }
812844
813- if (ret <= 0 ) {
845+ if (prep_pkts <= 0 ) {
814846 TRACE_DEVEL ("stopping on qc_prep_pkts() return" , QUIC_EV_CONN_TXPKT , qc );
815847 break ;
816848 }
817849
850+ ret += prep_pkts ;
851+ if (max_dgrams && ret == max_dgrams && !LIST_ISEMPTY (send_list )) {
852+ TRACE_DEVEL ("stopping for artificial pacing" , QUIC_EV_CONN_TXPKT , qc );
853+ break ;
854+ }
855+
818856 if ((qc -> flags & QUIC_FL_CONN_DRAINING ) &&
819857 !(qc -> flags & QUIC_FL_CONN_IMMEDIATE_CLOSE )) {
820858 TRACE_DEVEL ("draining connection" , QUIC_EV_CONN_TXPKT , qc );
@@ -826,8 +864,6 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
826864 if (ret < 0 )
827865 goto out ;
828866
829- status = 1 ;
830-
831867 out :
832868 if (old_data ) {
833869 TRACE_STATE ("no more need old data for probing" , QUIC_EV_CONN_TXPKT , qc );
@@ -840,8 +876,8 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
840876 qel -> send_frms = NULL ;
841877 }
842878
843- TRACE_DEVEL ((status ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
844- return status ;
879+ TRACE_DEVEL ((ret > 0 ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
880+ return ret ;
845881}
846882
847883/* Insert <qel> into <send_list> in preparation for sending. Set its send
@@ -905,10 +941,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
905941 if (qc -> hel )
906942 qel_register_send (& send_list , qc -> hel , & hfrms );
907943
908- sret = qc_send (qc , 1 , & send_list );
944+ sret = qc_send (qc , 1 , & send_list , 0 );
909945 qc_free_frm_list (qc , & ifrms );
910946 qc_free_frm_list (qc , & hfrms );
911- if (! sret )
947+ if (sret < 0 )
912948 goto leave ;
913949 }
914950 else {
@@ -918,10 +954,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
918954 */
919955 ipktns -> tx .pto_probe = 1 ;
920956 qel_register_send (& send_list , qc -> iel , & ifrms );
921- sret = qc_send (qc , 0 , & send_list );
957+ sret = qc_send (qc , 0 , & send_list , 0 );
922958 qc_free_frm_list (qc , & ifrms );
923959 qc_free_frm_list (qc , & hfrms );
924- if (! sret )
960+ if (sret < 0 )
925961 goto leave ;
926962
927963 break ;
@@ -947,9 +983,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
947983 if (!LIST_ISEMPTY (& frms1 )) {
948984 hpktns -> tx .pto_probe = 1 ;
949985 qel_register_send (& send_list , qc -> hel , & frms1 );
950- sret = qc_send (qc , 1 , & send_list );
986+ sret = qc_send (qc , 1 , & send_list , 0 );
951987 qc_free_frm_list (qc , & frms1 );
952- if (! sret )
988+ if (sret < 0 )
953989 goto leave ;
954990 }
955991 }
@@ -970,9 +1006,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9701006 if (!LIST_ISEMPTY (& frms1 )) {
9711007 apktns -> tx .pto_probe = 1 ;
9721008 qel_register_send (& send_list , qc -> ael , & frms1 );
973- sret = qc_send (qc , 1 , & send_list );
1009+ sret = qc_send (qc , 1 , & send_list , 0 );
9741010 qc_free_frm_list (qc , & frms1 );
975- if (! sret ) {
1011+ if (sret < 0 ) {
9761012 qc_free_frm_list (qc , & frms2 );
9771013 goto leave ;
9781014 }
@@ -981,9 +1017,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9811017 if (!LIST_ISEMPTY (& frms2 )) {
9821018 apktns -> tx .pto_probe = 1 ;
9831019 qel_register_send (& send_list , qc -> ael , & frms2 );
984- sret = qc_send (qc , 1 , & send_list );
1020+ sret = qc_send (qc , 1 , & send_list , 0 );
9851021 qc_free_frm_list (qc , & frms2 );
986- if (! sret )
1022+ if (sret < 0 )
9871023 goto leave ;
9881024 }
9891025 TRACE_STATE ("no more need to probe 01RTT packet number space" ,
0 commit comments