mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-03 02:32:03 +00:00
BUG/MEDIUM: mux-quic: prevent BUG_ON() by refreshing frms on MAX_DATA
QUIC MUX emission has been optimized recently by recycling STREAM frames
list between emission cycles. This is done via qcc frms list member. If
new data is available, frames list must be cleared before the next
emission to force the encoding of new STREAM frames.
If a refresh frames list is missed, it would lead to incomplete data
emission on the next transfer. In most cases, this is detected via a
BUG_ON() inside qcc_io_send(), as qcs instances remains in send_list
after a qcc_send_frames() full emission.
A bug was recently found which causes this BUG_ON() crash. This is
directly related to flow control. Indeed, when sending credit is
increased on the connection or a stream, frames list should be cleared
as new larger STREAM frames could be encoded. This was already performed
on MAX_DATA/MAX_STREAM_DATA reception but only if flow-control limit was
unblocked. However this is not the proper condition and it may lead to
insufficient frames refresh and thus this BUG_ON() crash.
Fix this by adjusting the condition for frames refresh on flow control
credit increase. Now, frames list is cleared if real offset is not
blocked and soft offset was equal or greater to the previous limit.
Indeed, this is the only case in which frames refreshing is necessary as
it would result in bigger encoded STREAM frames.
This bug was detected on QUIC interop with go-x-net client. It can also
be reproduced, albeit not systematically, using the following command :
$ ngtcp2-client -q --no-quic-dump --no-http-dump \
--exit-on-all-streams-close --max-data 10 \
127.0.0.1 20443 -n10 "http://127.0.0.1:20443/?s=10k"
This bug appeared with the following patch. As it is scheduled for 3.1
backporting, the current fix should be backported with it.
14710b5e6b
MEDIUM/OPTIM: mux-quic: do not rebuild frms list on every send
This commit is contained in:
parent
f2838f5172
commit
7edb2ffae7
@ -1642,6 +1642,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
*/
|
||||
int qcc_recv_max_data(struct qcc *qcc, uint64_t max)
|
||||
{
|
||||
const int blocked_soft = qfctl_sblocked(&qcc->tx.fc);
|
||||
int unblock_soft = 0, unblock_real = 0;
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
@ -1656,7 +1657,11 @@ int qcc_recv_max_data(struct qcc *qcc, uint64_t max)
|
||||
if (unblock_soft)
|
||||
qcc_notify_fctl(qcc);
|
||||
|
||||
if (unblock_soft || unblock_real)
|
||||
/* Refresh frms list only if this would result in newer data :
|
||||
* a. flow-control is not real blocked
|
||||
* b. soft off was equal or greater than previous limit
|
||||
*/
|
||||
if (!qfctl_rblocked(&qcc->tx.fc) && blocked_soft)
|
||||
qcc_clear_frms(qcc);
|
||||
}
|
||||
|
||||
@ -1693,6 +1698,7 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
|
||||
goto err;
|
||||
|
||||
if (qcs) {
|
||||
const int blocked_soft = qfctl_sblocked(&qcs->tx.fc);
|
||||
int unblock_soft = 0, unblock_real = 0;
|
||||
|
||||
TRACE_PROTO("receiving MAX_STREAM_DATA", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, qcc->conn, qcs);
|
||||
@ -1708,7 +1714,8 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
|
||||
qcs_notify_send(qcs);
|
||||
}
|
||||
|
||||
if (unblock_soft || unblock_real)
|
||||
/* Same refresh condition as qcc_recv_max_data(). */
|
||||
if (!qfctl_rblocked(&qcs->tx.fc) && blocked_soft)
|
||||
qcc_clear_frms(qcc);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user