mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-12-01 15:51:01 +01:00
MINOR: quic: support a max number of built packet per send iteration
This commit is contained in:
parent
ebdcb59a0f
commit
4618b48c19
@ -38,7 +38,8 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms);
|
|||||||
void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
|
void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
|
||||||
struct list *frms);
|
struct list *frms);
|
||||||
int qel_need_sending(struct quic_enc_level *qel, struct quic_conn *qc);
|
int qel_need_sending(struct quic_enc_level *qel, struct quic_conn *qc);
|
||||||
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list);
|
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list,
|
||||||
|
int max_dgrams);
|
||||||
|
|
||||||
int qc_dgrams_retransmit(struct quic_conn *qc);
|
int qc_dgrams_retransmit(struct quic_conn *qc);
|
||||||
void qc_prep_hdshk_fast_retrans(struct quic_conn *qc,
|
void qc_prep_hdshk_fast_retrans(struct quic_conn *qc,
|
||||||
|
|||||||
@ -617,7 +617,7 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
|
|||||||
if (qel_need_sending(qc->ael, qc))
|
if (qel_need_sending(qc->ael, qc))
|
||||||
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
|
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
|
||||||
|
|
||||||
if (!qc_send(qc, 0, &send_list)) {
|
if (!qc_send(qc, 0, &send_list, 0)) {
|
||||||
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
|
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -877,7 +877,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
|||||||
qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
|
qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qc_send(qc, 0, &send_list)) {
|
if (!qc_send(qc, 0, &send_list, 0)) {
|
||||||
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
|
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -488,12 +488,12 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms)
|
|||||||
qc->state >= QUIC_HS_ST_COMPLETE) {
|
qc->state >= QUIC_HS_ST_COMPLETE) {
|
||||||
quic_build_post_handshake_frames(qc);
|
quic_build_post_handshake_frames(qc);
|
||||||
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
|
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
|
||||||
qc_send(qc, 0, &send_list);
|
qc_send(qc, 0, &send_list, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc);
|
TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc);
|
||||||
qel_register_send(&send_list, qc->ael, frms);
|
qel_register_send(&send_list, qc->ael, frms);
|
||||||
ret = qc_send(qc, 0, &send_list);
|
ret = qc_send(qc, 0, &send_list, 0);
|
||||||
|
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
|
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
|
||||||
return ret;
|
return ret;
|
||||||
@ -520,18 +520,21 @@ static inline void qc_select_tls_ver(struct quic_conn *qc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare as much as possible QUIC datagrams/packets for sending from <qels>
|
/* Prepare one or several QUIC datagrams/packets for sending from <qels> list
|
||||||
* list of encryption levels. Several packets can be coalesced into a single
|
* of encryption levels. Several packets can be coalesced into a single
|
||||||
* datagram. The result is written into <buf>.
|
* datagram. The result is written into <buf>.
|
||||||
*
|
*
|
||||||
|
* If <max_dgrams> is non null, it limits the number of prepared datagrams.
|
||||||
|
* Useful to support pacing emission.
|
||||||
|
*
|
||||||
* Each datagram is prepended by a two fields header : the datagram length and
|
* Each datagram is prepended by a two fields header : the datagram length and
|
||||||
* the address of first packet in the datagram.
|
* the address of first packet in the datagram.
|
||||||
*
|
*
|
||||||
* Returns the number of bytes prepared in datragrams/packets if succeeded
|
* Returns the number of prepared datagrams on success which may be 0. On error
|
||||||
* (may be 0), or -1 if something wrong happened.
|
* a negative error code is returned.
|
||||||
*/
|
*/
|
||||||
static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
||||||
struct list *qels)
|
struct list *qels, int max_dgrams)
|
||||||
{
|
{
|
||||||
int ret, cc, padding;
|
int ret, cc, padding;
|
||||||
struct quic_tx_packet *first_pkt, *prv_pkt;
|
struct quic_tx_packet *first_pkt, *prv_pkt;
|
||||||
@ -540,7 +543,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
uint16_t dglen;
|
uint16_t dglen;
|
||||||
size_t total;
|
size_t total;
|
||||||
struct quic_enc_level *qel, *tmp_qel;
|
struct quic_enc_level *qel, *tmp_qel;
|
||||||
uchar gso_dgram_cnt = 0;
|
uchar dgram_cnt = 0, gso_dgram_cnt = 0;
|
||||||
|
|
||||||
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
|
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
|
||||||
/* Currently qc_prep_pkts() does not handle buffer wrapping so the
|
/* 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,
|
|||||||
|
|
||||||
TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel);
|
TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||||
|
|
||||||
|
/* Start to decrement <max_dgrams> after the first packet built. */
|
||||||
|
if (!dglen && pos != (unsigned char *)b_head(buf)) {
|
||||||
|
if (max_dgrams && !--max_dgrams) {
|
||||||
|
BUG_ON(LIST_ISEMPTY(frms));
|
||||||
|
TRACE_PROTO("reached max allowed built datagrams", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!first_pkt)
|
if (!first_pkt)
|
||||||
pos += QUIC_DGRAM_HEADLEN;
|
pos += QUIC_DGRAM_HEADLEN;
|
||||||
|
|
||||||
@ -647,8 +659,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
* except if it is an too short Initial.
|
* except if it is an too short Initial.
|
||||||
*/
|
*/
|
||||||
if (first_pkt && (first_pkt->type != QUIC_PACKET_TYPE_INITIAL ||
|
if (first_pkt && (first_pkt->type != QUIC_PACKET_TYPE_INITIAL ||
|
||||||
wrlen >= QUIC_INITIAL_PACKET_MINLEN))
|
wrlen >= QUIC_INITIAL_PACKET_MINLEN)) {
|
||||||
qc_txb_store(buf, wrlen, first_pkt);
|
qc_txb_store(buf, wrlen, first_pkt);
|
||||||
|
++dgram_cnt;
|
||||||
|
}
|
||||||
TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel);
|
TRACE_PROTO("could not prepare anymore packet", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -717,6 +731,8 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
prv_pkt = cur_pkt;
|
prv_pkt = cur_pkt;
|
||||||
dglen = 0;
|
dglen = 0;
|
||||||
|
|
||||||
|
++dgram_cnt;
|
||||||
|
|
||||||
/* man 7 udp UDP_SEGMENT
|
/* man 7 udp UDP_SEGMENT
|
||||||
* The segment size must be chosen such that at
|
* The segment size must be chosen such that at
|
||||||
* most 64 datagrams are sent in a single call
|
* 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,
|
|||||||
wrlen = dglen = 0;
|
wrlen = dglen = 0;
|
||||||
padding = 0;
|
padding = 0;
|
||||||
prv_pkt = NULL;
|
prv_pkt = NULL;
|
||||||
|
++dgram_cnt;
|
||||||
gso_dgram_cnt = 0;
|
gso_dgram_cnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,8 +760,10 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (first_pkt)
|
if (first_pkt) {
|
||||||
qc_txb_store(buf, wrlen, first_pkt);
|
qc_txb_store(buf, wrlen, first_pkt);
|
||||||
|
++dgram_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
if (cc && total) {
|
if (cc && total) {
|
||||||
BUG_ON(buf != &qc->tx.cc_buf);
|
BUG_ON(buf != &qc->tx.cc_buf);
|
||||||
@ -752,7 +771,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
qc->tx.cc_dgram_len = dglen;
|
qc->tx.cc_dgram_len = dglen;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = total;
|
ret = dgram_cnt;
|
||||||
leave:
|
leave:
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
|
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
|
||||||
return ret;
|
return ret;
|
||||||
@ -762,13 +781,21 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
|
|||||||
* specified via quic_enc_level <send_list> through their send_frms member. Set
|
* specified via quic_enc_level <send_list> through their send_frms member. Set
|
||||||
* <old_data> when reemitted duplicated data.
|
* <old_data> when reemitted duplicated data.
|
||||||
*
|
*
|
||||||
* Returns 1 on success else 0. Note that <send_list> will always be reset
|
* If <max_dgrams> is non null, it limits the number of emitted datagrams.
|
||||||
* after qc_send() exit.
|
* Useful to support pacing emission.
|
||||||
|
*
|
||||||
|
* Note that <send_list> will always be emptied on function completion, both on
|
||||||
|
* success and error.
|
||||||
|
*
|
||||||
|
* Returns the number of sent datagrams on success. It means either that all
|
||||||
|
* input frames were sent or emission is interrupted due to pacing. Else a
|
||||||
|
* negative error code is returned.
|
||||||
*/
|
*/
|
||||||
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
|
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list,
|
||||||
|
int max_dgrams)
|
||||||
{
|
{
|
||||||
struct quic_enc_level *qel, *tmp_qel;
|
struct quic_enc_level *qel, *tmp_qel;
|
||||||
int ret = 0, status = 0;
|
int prep_pkts = 0, ret = -1;
|
||||||
struct buffer *buf;
|
struct buffer *buf;
|
||||||
|
|
||||||
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
|
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)
|
|||||||
while (!LIST_ISEMPTY(send_list) &&
|
while (!LIST_ISEMPTY(send_list) &&
|
||||||
(!(qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) ||
|
(!(qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) ||
|
||||||
(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))) {
|
(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))) {
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
/* Buffer must always be empty before qc_prep_pkts() usage.
|
/* Buffer must always be empty before qc_prep_pkts() usage.
|
||||||
* qc_send_ppkts() ensures it is cleared on success.
|
* qc_send_ppkts() ensures it is cleared on success.
|
||||||
*/
|
*/
|
||||||
BUG_ON_HOT(b_data(buf));
|
BUG_ON_HOT(b_data(buf));
|
||||||
b_reset(buf);
|
b_reset(buf);
|
||||||
|
|
||||||
ret = qc_prep_pkts(qc, buf, send_list);
|
prep_pkts = qc_prep_pkts(qc, buf, send_list, max_dgrams);
|
||||||
|
|
||||||
if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) {
|
if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) {
|
||||||
|
ret = -1;
|
||||||
if (qc->flags & QUIC_FL_CONN_TO_KILL)
|
if (qc->flags & QUIC_FL_CONN_TO_KILL)
|
||||||
qc_txb_release(qc);
|
qc_txb_release(qc);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret <= 0) {
|
if (prep_pkts <= 0) {
|
||||||
TRACE_DEVEL("stopping on qc_prep_pkts() return", QUIC_EV_CONN_TXPKT, qc);
|
TRACE_DEVEL("stopping on qc_prep_pkts() return", QUIC_EV_CONN_TXPKT, qc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret += prep_pkts;
|
||||||
|
if (max_dgrams && ret == max_dgrams && !LIST_ISEMPTY(send_list)) {
|
||||||
|
TRACE_DEVEL("stopping for artificial pacing", QUIC_EV_CONN_TXPKT, qc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
|
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
|
||||||
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) {
|
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) {
|
||||||
TRACE_DEVEL("draining connection", QUIC_EV_CONN_TXPKT, qc);
|
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)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
status = 1;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (old_data) {
|
if (old_data) {
|
||||||
TRACE_STATE("no more need old data for probing", QUIC_EV_CONN_TXPKT, qc);
|
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)
|
|||||||
qel->send_frms = NULL;
|
qel->send_frms = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_DEVEL((status ? "leaving" : "leaving in error"), QUIC_EV_CONN_TXPKT, qc);
|
TRACE_DEVEL((ret > 0 ? "leaving" : "leaving in error"), QUIC_EV_CONN_TXPKT, qc);
|
||||||
return status;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert <qel> into <send_list> in preparation for sending. Set its send
|
/* Insert <qel> into <send_list> in preparation for sending. Set its send
|
||||||
@ -905,10 +941,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
|||||||
if (qc->hel)
|
if (qc->hel)
|
||||||
qel_register_send(&send_list, qc->hel, &hfrms);
|
qel_register_send(&send_list, qc->hel, &hfrms);
|
||||||
|
|
||||||
sret = qc_send(qc, 1, &send_list);
|
sret = qc_send(qc, 1, &send_list, 0);
|
||||||
qc_free_frm_list(qc, &ifrms);
|
qc_free_frm_list(qc, &ifrms);
|
||||||
qc_free_frm_list(qc, &hfrms);
|
qc_free_frm_list(qc, &hfrms);
|
||||||
if (!sret)
|
if (sret < 0)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -918,10 +954,10 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
|||||||
*/
|
*/
|
||||||
ipktns->tx.pto_probe = 1;
|
ipktns->tx.pto_probe = 1;
|
||||||
qel_register_send(&send_list, qc->iel, &ifrms);
|
qel_register_send(&send_list, qc->iel, &ifrms);
|
||||||
sret = qc_send(qc, 0, &send_list);
|
sret = qc_send(qc, 0, &send_list, 0);
|
||||||
qc_free_frm_list(qc, &ifrms);
|
qc_free_frm_list(qc, &ifrms);
|
||||||
qc_free_frm_list(qc, &hfrms);
|
qc_free_frm_list(qc, &hfrms);
|
||||||
if (!sret)
|
if (sret < 0)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -947,9 +983,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
|||||||
if (!LIST_ISEMPTY(&frms1)) {
|
if (!LIST_ISEMPTY(&frms1)) {
|
||||||
hpktns->tx.pto_probe = 1;
|
hpktns->tx.pto_probe = 1;
|
||||||
qel_register_send(&send_list, qc->hel, &frms1);
|
qel_register_send(&send_list, qc->hel, &frms1);
|
||||||
sret = qc_send(qc, 1, &send_list);
|
sret = qc_send(qc, 1, &send_list, 0);
|
||||||
qc_free_frm_list(qc, &frms1);
|
qc_free_frm_list(qc, &frms1);
|
||||||
if (!sret)
|
if (sret < 0)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -970,9 +1006,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
|||||||
if (!LIST_ISEMPTY(&frms1)) {
|
if (!LIST_ISEMPTY(&frms1)) {
|
||||||
apktns->tx.pto_probe = 1;
|
apktns->tx.pto_probe = 1;
|
||||||
qel_register_send(&send_list, qc->ael, &frms1);
|
qel_register_send(&send_list, qc->ael, &frms1);
|
||||||
sret = qc_send(qc, 1, &send_list);
|
sret = qc_send(qc, 1, &send_list, 0);
|
||||||
qc_free_frm_list(qc, &frms1);
|
qc_free_frm_list(qc, &frms1);
|
||||||
if (!sret) {
|
if (sret < 0) {
|
||||||
qc_free_frm_list(qc, &frms2);
|
qc_free_frm_list(qc, &frms2);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -981,9 +1017,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
|
|||||||
if (!LIST_ISEMPTY(&frms2)) {
|
if (!LIST_ISEMPTY(&frms2)) {
|
||||||
apktns->tx.pto_probe = 1;
|
apktns->tx.pto_probe = 1;
|
||||||
qel_register_send(&send_list, qc->ael, &frms2);
|
qel_register_send(&send_list, qc->ael, &frms2);
|
||||||
sret = qc_send(qc, 1, &send_list);
|
sret = qc_send(qc, 1, &send_list, 0);
|
||||||
qc_free_frm_list(qc, &frms2);
|
qc_free_frm_list(qc, &frms2);
|
||||||
if (!sret)
|
if (sret < 0)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
TRACE_STATE("no more need to probe 01RTT packet number space",
|
TRACE_STATE("no more need to probe 01RTT packet number space",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user