@@ -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,6 +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 ;
546+ int dgram_cnt = 0 ;
543547 uchar gso_dgram_cnt = 0 ;
544548
545549 TRACE_ENTER (QUIC_EV_CONN_IO_CB , qc );
@@ -588,6 +592,15 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
588592
589593 TRACE_PROTO ("TX prep pkts" , QUIC_EV_CONN_PHPKTS , qc , qel );
590594
595+ /* Start to decrement <max_dgrams> after the first packet built. */
596+ if (!dglen && pos != (unsigned char * )b_head (buf )) {
597+ if (max_dgrams && !-- max_dgrams ) {
598+ BUG_ON (LIST_ISEMPTY (frms ));
599+ TRACE_PROTO ("reached max allowed built datagrams" , QUIC_EV_CONN_PHPKTS , qc , qel );
600+ goto out ;
601+ }
602+ }
603+
591604 if (!first_pkt )
592605 pos += QUIC_DGRAM_HEADLEN ;
593606
@@ -655,8 +668,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
655668 * except if it is an too short Initial.
656669 */
657670 if (first_pkt && (first_pkt -> type != QUIC_PACKET_TYPE_INITIAL ||
658- wrlen >= QUIC_INITIAL_PACKET_MINLEN ))
671+ wrlen >= QUIC_INITIAL_PACKET_MINLEN )) {
659672 qc_txb_store (buf , wrlen , first_pkt );
673+ ++ dgram_cnt ;
674+ }
660675 TRACE_PROTO ("could not prepare anymore packet" , QUIC_EV_CONN_PHPKTS , qc , qel );
661676 break ;
662677
@@ -725,6 +740,8 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
725740 prv_pkt = cur_pkt ;
726741 dglen = 0 ;
727742
743+ ++ dgram_cnt ;
744+
728745 /* man 7 udp UDP_SEGMENT
729746 * The segment size must be chosen such that at
730747 * most 64 datagrams are sent in a single call
@@ -738,6 +755,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
738755 wrlen = dglen = 0 ;
739756 padding = 0 ;
740757 prv_pkt = NULL ;
758+ ++ dgram_cnt ;
741759 gso_dgram_cnt = 0 ;
742760 }
743761
@@ -761,7 +779,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
761779 }
762780
763781 TRACE_LEAVE (QUIC_EV_CONN_PHPKTS , qc );
764- return total ;
782+ return dgram_cnt ;
765783
766784 err :
767785 TRACE_DEVEL ("leaving on error" , QUIC_EV_CONN_PHPKTS , qc );
@@ -772,25 +790,35 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
772790 * specified via quic_enc_level <send_list> through their send_frms member. Set
773791 * <old_data> when reemitted duplicated data.
774792 *
775- * Returns 1 on success else 0. Note that <send_list> will always be reset
776- * after qc_send() exit.
793+ * If <max_dgrams> is non null, it limits the number of emitted datagrams.
794+ * Useful to support pacing emission.
795+ *
796+ * Note that <send_list> will always be emptied on function completion, both on
797+ * success and error.
798+ *
799+ * Returns the number of sent datagrams on success. It means either that all
800+ * input frames were sent or emission is interrupted due to pacing. Else a
801+ * negative error code is returned.
777802 */
778- int qc_send (struct quic_conn * qc , int old_data , struct list * send_list )
803+ int qc_send (struct quic_conn * qc , int old_data , struct list * send_list ,
804+ int max_dgrams )
779805{
780806 struct quic_enc_level * qel , * tmp_qel ;
781- int ret = 0 , status = 0 ;
807+ int prep = 0 , ret = 0 ;
782808 struct buffer * buf ;
783809
784810 TRACE_ENTER (QUIC_EV_CONN_TXPKT , qc );
785811
786812 buf = qc_get_txb (qc );
787813 if (!buf ) {
788814 TRACE_ERROR ("buffer allocation failed" , QUIC_EV_CONN_TXPKT , qc );
815+ ret = -1 ;
789816 goto out ;
790817 }
791818
792819 if (b_data (buf ) && !qc_purge_txbuf (qc , buf )) {
793820 TRACE_ERROR ("Could not purge TX buffer" , QUIC_EV_CONN_TXPKT , qc );
821+ ret = -1 ;
794822 goto out ;
795823 }
796824
@@ -806,25 +834,36 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
806834 while (!LIST_ISEMPTY (send_list ) &&
807835 (!(qc -> flags & (QUIC_FL_CONN_CLOSING |QUIC_FL_CONN_DRAINING )) ||
808836 (qc -> flags & QUIC_FL_CONN_IMMEDIATE_CLOSE ))) {
837+
809838 /* Buffer must always be empty before qc_prep_pkts() usage.
810839 * qc_send_ppkts() ensures it is cleared on success.
811840 */
812841 BUG_ON_HOT (b_data (buf ));
813842 b_reset (buf );
814843
815- ret = qc_prep_pkts (qc , buf , send_list );
844+ prep = qc_prep_pkts (qc , buf , send_list , max_dgrams ? max_dgrams - ret : 0 );
845+ BUG_ON (max_dgrams && prep > max_dgrams );
816846
817847 if (b_data (buf ) && !qc_send_ppkts (buf , qc -> xprt_ctx )) {
818848 if (qc -> flags & QUIC_FL_CONN_TO_KILL )
819849 qc_txb_release (qc );
850+ ret = -1 ;
820851 goto out ;
821852 }
822853
823- if (ret <= 0 ) {
854+ if (prep <= 0 ) {
855+ /* TODO should this be considered error if prep<0 ? */
824856 TRACE_DEVEL ("stopping on qc_prep_pkts() return" , QUIC_EV_CONN_TXPKT , qc );
825857 break ;
826858 }
827859
860+ ret += prep ;
861+ BUG_ON (max_dgrams && ret > max_dgrams );
862+ if (max_dgrams && ret == max_dgrams && !LIST_ISEMPTY (send_list )) {
863+ TRACE_DEVEL ("stopping for artificial pacing" , QUIC_EV_CONN_TXPKT , qc );
864+ break ;
865+ }
866+
828867 if ((qc -> flags & QUIC_FL_CONN_DRAINING ) &&
829868 !(qc -> flags & QUIC_FL_CONN_IMMEDIATE_CLOSE )) {
830869 TRACE_DEVEL ("draining connection" , QUIC_EV_CONN_TXPKT , qc );
@@ -833,10 +872,6 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
833872 }
834873
835874 qc_txb_release (qc );
836- if (ret < 0 )
837- goto out ;
838-
839- status = 1 ;
840875
841876 out :
842877 if (old_data ) {
@@ -850,8 +885,8 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
850885 qel -> send_frms = NULL ;
851886 }
852887
853- TRACE_DEVEL ((status ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
854- return status ;
888+ TRACE_DEVEL ((ret > 0 ? "leaving" : "leaving in error" ), QUIC_EV_CONN_TXPKT , qc );
889+ return ret ;
855890}
856891
857892/* Insert <qel> into <send_list> in preparation for sending. Set its send
@@ -915,10 +950,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
915950 if (qc -> hel )
916951 qel_register_send (& send_list , qc -> hel , & hfrms );
917952
918- sret = qc_send (qc , 1 , & send_list );
953+ sret = qc_send (qc , 1 , & send_list , 0 );
919954 qc_free_frm_list (qc , & ifrms );
920955 qc_free_frm_list (qc , & hfrms );
921- if (! sret )
956+ if (sret < 0 )
922957 goto leave ;
923958 }
924959 else {
@@ -928,10 +963,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
928963 */
929964 ipktns -> tx .pto_probe = 1 ;
930965 qel_register_send (& send_list , qc -> iel , & ifrms );
931- sret = qc_send (qc , 0 , & send_list );
966+ sret = qc_send (qc , 0 , & send_list , 0 );
932967 qc_free_frm_list (qc , & ifrms );
933968 qc_free_frm_list (qc , & hfrms );
934- if (! sret )
969+ if (sret < 0 )
935970 goto leave ;
936971
937972 break ;
@@ -957,9 +992,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
957992 if (!LIST_ISEMPTY (& frms1 )) {
958993 hpktns -> tx .pto_probe = 1 ;
959994 qel_register_send (& send_list , qc -> hel , & frms1 );
960- sret = qc_send (qc , 1 , & send_list );
995+ sret = qc_send (qc , 1 , & send_list , 0 );
961996 qc_free_frm_list (qc , & frms1 );
962- if (! sret )
997+ if (sret < 0 )
963998 goto leave ;
964999 }
9651000 }
@@ -980,9 +1015,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9801015 if (!LIST_ISEMPTY (& frms1 )) {
9811016 apktns -> tx .pto_probe = 1 ;
9821017 qel_register_send (& send_list , qc -> ael , & frms1 );
983- sret = qc_send (qc , 1 , & send_list );
1018+ sret = qc_send (qc , 1 , & send_list , 0 );
9841019 qc_free_frm_list (qc , & frms1 );
985- if (! sret ) {
1020+ if (sret < 0 ) {
9861021 qc_free_frm_list (qc , & frms2 );
9871022 goto leave ;
9881023 }
@@ -991,9 +1026,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
9911026 if (!LIST_ISEMPTY (& frms2 )) {
9921027 apktns -> tx .pto_probe = 1 ;
9931028 qel_register_send (& send_list , qc -> ael , & frms2 );
994- sret = qc_send (qc , 1 , & send_list );
1029+ sret = qc_send (qc , 1 , & send_list , 0 );
9951030 qc_free_frm_list (qc , & frms2 );
996- if (! sret )
1031+ if (sret < 0 )
9971032 goto leave ;
9981033 }
9991034 TRACE_STATE ("no more need to probe 01RTT packet number space" ,
0 commit comments