@@ -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 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 int total = 0 ;
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
@@ -588,6 +591,15 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
588591
589592 TRACE_PROTO ("TX prep pkts" , QUIC_EV_CONN_PHPKTS , qc , qel );
590593
594+ /* Start to decrement <max_dgrams> after the first packet built. */
595+ if (!dglen && pos != (unsigned char * )b_head (buf )) {
596+ if (max_dgrams && !-- max_dgrams ) {
597+ BUG_ON (LIST_ISEMPTY (frms ));
598+ TRACE_PROTO ("reached max allowed built datagrams" , QUIC_EV_CONN_PHPKTS , qc , qel );
599+ goto out ;
600+ }
601+ }
602+
591603 if (!first_pkt )
592604 pos += QUIC_DGRAM_HEADLEN ;
593605
@@ -655,8 +667,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
655667 * except if it is an too short Initial.
656668 */
657669 if (first_pkt && (first_pkt -> type != QUIC_PACKET_TYPE_INITIAL ||
658- wrlen >= QUIC_INITIAL_PACKET_MINLEN ))
670+ wrlen >= QUIC_INITIAL_PACKET_MINLEN )) {
659671 qc_txb_store (buf , wrlen , first_pkt );
672+ ++ dgram_cnt ;
673+ }
660674 TRACE_PROTO ("could not prepare anymore packet" , QUIC_EV_CONN_PHPKTS , qc , qel );
661675 break ;
662676
@@ -725,6 +739,8 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
725739 prv_pkt = cur_pkt ;
726740 dglen = 0 ;
727741
742+ ++ dgram_cnt ;
743+
728744 /* man 7 udp UDP_SEGMENT
729745 * The segment size must be chosen such that at
730746 * most 64 datagrams are sent in a single call
@@ -738,6 +754,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
738754 wrlen = dglen = 0 ;
739755 padding = 0 ;
740756 prv_pkt = NULL ;
757+ ++ dgram_cnt ;
741758 gso_dgram_cnt = 0 ;
742759 }
743760
@@ -761,7 +778,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
761778 }
762779
763780 TRACE_LEAVE (QUIC_EV_CONN_PHPKTS , qc );
764- return total ;
781+ return dgram_cnt ;
765782
766783 err :
767784 TRACE_DEVEL ("leaving on error" , QUIC_EV_CONN_PHPKTS , qc );
@@ -772,25 +789,35 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
772789 * specified via quic_enc_level <send_list> through their send_frms member. Set
773790 * <old_data> when reemitted duplicated data.
774791 *
775- * Returns 1 on success else 0. Note that <send_list> will always be reset
776- * after qc_send() exit.
792+ * If <max_dgrams> is non null, it limits the number of emitted datagrams.
793+ * Useful to support pacing emission.
794+ *
795+ * Note that <send_list> will always be emptied on function completion, both on
796+ * success and error.
797+ *
798+ * Returns the number of sent datagrams on success. It means either that all
799+ * input frames were sent or emission is interrupted due to pacing. Else a
800+ * negative error code is returned.
777801 */
778- int qc_send (struct quic_conn * qc , int old_data , struct list * send_list )
802+ int qc_send (struct quic_conn * qc , int old_data , struct list * send_list ,
803+ int max_dgrams )
779804{
780805 struct quic_enc_level * qel , * tmp_qel ;
781- int ret = 0 , status = 0 ;
806+ int prep = 0 , ret = 0 ;
782807 struct buffer * buf ;
783808
784809 TRACE_ENTER (QUIC_EV_CONN_TXPKT , qc );
785810
786811 buf = qc_get_txb (qc );
787812 if (!buf ) {
788813 TRACE_ERROR ("buffer allocation failed" , QUIC_EV_CONN_TXPKT , qc );
814+ ret = -1 ;
789815 goto out ;
790816 }
791817
792818 if (b_data (buf ) && !qc_purge_txbuf (qc , buf )) {
793819 TRACE_ERROR ("Could not purge TX buffer" , QUIC_EV_CONN_TXPKT , qc );
820+ ret = -1 ;
794821 goto out ;
795822 }
796823
@@ -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+
809837 /* Buffer must always be empty before qc_prep_pkts() usage.
810838 * qc_send_ppkts() ensures it is cleared on success.
811839 */
812840 BUG_ON_HOT (b_data (buf ));
813841 b_reset (buf );
814842
815- ret = qc_prep_pkts (qc , buf , send_list );
843+ prep = qc_prep_pkts (qc , buf , send_list , max_dgrams ? max_dgrams - ret : 0 );
844+ BUG_ON (max_dgrams && prep > max_dgrams );
816845
817846 if (b_data (buf ) && !qc_send_ppkts (buf , qc -> xprt_ctx )) {
818847 if (qc -> flags & QUIC_FL_CONN_TO_KILL )
819848 qc_txb_release (qc );
849+ ret = -1 ;
820850 goto out ;
821851 }
822852
823- if (ret <= 0 ) {
853+ if (prep <= 0 ) {
854+ /* TODO should this be considered error if prep<0 ? */
824855 TRACE_DEVEL ("stopping on qc_prep_pkts() return" , QUIC_EV_CONN_TXPKT , qc );
825856 break ;
826857 }
827858
859+ ret += prep ;
860+ BUG_ON (max_dgrams && ret > max_dgrams );
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 );
@@ -833,10 +871,6 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
833871 }
834872
835873 qc_txb_release (qc );
836- if (ret < 0 )
837- goto out ;
838-
839- status = 1 ;
840874
841875 out :
842876 if (old_data ) {
@@ -850,8 +884,8 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
850884 qel -> send_frms = NULL ;
851885 }
852886
853- TRACE_DEVEL ((status ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
854- return status ;
887+ TRACE_DEVEL ((ret > 0 ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
888+ return ret ;
855889}
856890
857891/* Insert <qel> into <send_list> in preparation for sending. Set its send
@@ -915,10 +949,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
915949 if (qc -> hel )
916950 qel_register_send (& send_list , qc -> hel , & hfrms );
917951
918- sret = qc_send (qc , 1 , & send_list );
952+ sret = qc_send (qc , 1 , & send_list , 0 );
919953 qc_free_frm_list (qc , & ifrms );
920954 qc_free_frm_list (qc , & hfrms );
921- if (! sret )
955+ if (sret < 0 )
922956 goto leave ;
923957 }
924958 else {
@@ -928,10 +962,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
928962 */
929963 ipktns -> tx .pto_probe = 1 ;
930964 qel_register_send (& send_list , qc -> iel , & ifrms );
931- sret = qc_send (qc , 0 , & send_list );
965+ sret = qc_send (qc , 0 , & send_list , 0 );
932966 qc_free_frm_list (qc , & ifrms );
933967 qc_free_frm_list (qc , & hfrms );
934- if (! sret )
968+ if (sret < 0 )
935969 goto leave ;
936970
937971 break ;
@@ -957,9 +991,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
957991 if (!LIST_ISEMPTY (& frms1 )) {
958992 hpktns -> tx .pto_probe = 1 ;
959993 qel_register_send (& send_list , qc -> hel , & frms1 );
960- sret = qc_send (qc , 1 , & send_list );
994+ sret = qc_send (qc , 1 , & send_list , 0 );
961995 qc_free_frm_list (qc , & frms1 );
962- if (! sret )
996+ if (sret < 0 )
963997 goto leave ;
964998 }
965999 }
@@ -980,9 +1014,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9801014 if (!LIST_ISEMPTY (& frms1 )) {
9811015 apktns -> tx .pto_probe = 1 ;
9821016 qel_register_send (& send_list , qc -> ael , & frms1 );
983- sret = qc_send (qc , 1 , & send_list );
1017+ sret = qc_send (qc , 1 , & send_list , 0 );
9841018 qc_free_frm_list (qc , & frms1 );
985- if (! sret ) {
1019+ if (sret < 0 ) {
9861020 qc_free_frm_list (qc , & frms2 );
9871021 goto leave ;
9881022 }
@@ -991,9 +1025,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9911025 if (!LIST_ISEMPTY (& frms2 )) {
9921026 apktns -> tx .pto_probe = 1 ;
9931027 qel_register_send (& send_list , qc -> ael , & frms2 );
994- sret = qc_send (qc , 1 , & send_list );
1028+ sret = qc_send (qc , 1 , & send_list , 0 );
9951029 qc_free_frm_list (qc , & frms2 );
996- if (! sret )
1030+ if (sret < 0 )
9971031 goto leave ;
9981032 }
9991033 TRACE_STATE ("no more need to probe 01RTT packet number space" ,
0 commit comments