mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-03 02:32:03 +00:00
MINOR: quic: Add a new quic_ack.c C module for QUIC acknowledgements
Extract the code in relation with the QUIC acknowledgements from quic_conn.c to quic_ack.c to accelerate the compilation of quic_conn.c.
This commit is contained in:
parent
f454b78fa9
commit
7008f16d57
2
Makefile
2
Makefile
@ -607,7 +607,7 @@ OPTIONS_OBJS += src/quic_conn.o src/mux_quic.o src/h3.o src/xprt_quic.o \
|
||||
src/quic_cc_newreno.o src/quic_cc_cubic.o src/qpack-tbl.o \
|
||||
src/qpack-dec.o src/hq_interop.o src/quic_stream.o \
|
||||
src/h3_stats.o src/qmux_http.o src/cfgparse-quic.o \
|
||||
src/cbuf.o src/quic_cc.o src/quic_cc_nocc.o \
|
||||
src/cbuf.o src/quic_cc.o src/quic_cc_nocc.o src/quic_ack.o \
|
||||
src/quic_trace.o src/quic_cli.o src/quic_ssl.o
|
||||
endif
|
||||
|
||||
|
43
include/haproxy/quic_ack-t.h
Normal file
43
include/haproxy/quic_ack-t.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* include/haproxy/quic_ack-t.h
|
||||
* Definitions for QUIC acknowledgements internal types, constants and flags.
|
||||
*
|
||||
* Copyright (C) 2023
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#ifndef _HAPROXY_QUIC_ACK_T_H
|
||||
#define _HAPROXY_QUIC_ACK_T_H
|
||||
|
||||
/* The maximum number of ack ranges to be built in ACK frames */
|
||||
#define QUIC_MAX_ACK_RANGES 32
|
||||
|
||||
/* Structure to maintain a set of ACK ranges to be used to build ACK frames. */
|
||||
struct quic_arngs {
|
||||
/* ebtree of ACK ranges organized by their first value. */
|
||||
struct eb_root root;
|
||||
/* The number of ACK ranges is this tree */
|
||||
size_t sz;
|
||||
/* The number of bytes required to encode this ACK ranges lists. */
|
||||
size_t enc_sz;
|
||||
};
|
||||
|
||||
/* Structure to hold a range of ACKs sent in ACK frames. */
|
||||
struct quic_arng {
|
||||
int64_t first;
|
||||
int64_t last;
|
||||
};
|
||||
|
||||
/* Structure to hold a range of ACKs to be store as a node in a tree of
|
||||
* ACK ranges.
|
||||
*/
|
||||
struct quic_arng_node {
|
||||
struct eb64_node first;
|
||||
uint64_t last;
|
||||
};
|
||||
|
||||
#endif /* _HAPROXY_QUIC_ACK_T_H */
|
23
include/haproxy/quic_ack.h
Normal file
23
include/haproxy/quic_ack.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* include/proto/quic_ack.h
|
||||
* This file provides definitions for QUIC acknowledgements.
|
||||
*
|
||||
* Copyright (C) 2023
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _HAPROXY_QUIC_ACK_H
|
||||
#define _HAPROXY_QUIC_ACK_H
|
||||
|
||||
void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs);
|
||||
int quic_update_ack_ranges_list(struct quic_conn *qc,
|
||||
struct quic_arngs *arngs,
|
||||
struct quic_arng *ar);
|
||||
void qc_treat_ack_of_ack(struct quic_conn *qc, struct quic_arngs *arngs,
|
||||
int64_t largest_acked_pn);
|
||||
|
||||
#endif /* _HAPROXY_QUIC_ACK_H */
|
@ -309,20 +309,6 @@ struct quic_connection_id {
|
||||
uint tid; /* Attached Thread ID for the connection. */
|
||||
};
|
||||
|
||||
/* Structure to hold a range of ACKs sent in ACK frames. */
|
||||
struct quic_arng {
|
||||
int64_t first;
|
||||
int64_t last;
|
||||
};
|
||||
|
||||
/* Structure to hold a range of ACKs to be store as a node in a tree of
|
||||
* ACK ranges.
|
||||
*/
|
||||
struct quic_arng_node {
|
||||
struct eb64_node first;
|
||||
uint64_t last;
|
||||
};
|
||||
|
||||
/* Flag the packet number space as having received a packet */
|
||||
#define QUIC_FL_PKTNS_PKT_RECEIVED (1UL << 0)
|
||||
/* Flag the packet number space as requiring an ACK frame to be sent. */
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <import/ebtree.h>
|
||||
|
||||
#include <haproxy/quic_ack-t.h>
|
||||
#include <haproxy/openssl-compat.h>
|
||||
|
||||
/* It seems TLS 1.3 ciphersuites macros differ between openssl and boringssl */
|
||||
@ -123,19 +124,6 @@ extern const unsigned char initial_salt_draft_29[20];
|
||||
extern const unsigned char initial_salt_v1[20];
|
||||
extern const unsigned char initial_salt_v2[20];
|
||||
|
||||
/* The maximum number of ack ranges to be built in ACK frames */
|
||||
#define QUIC_MAX_ACK_RANGES 32
|
||||
|
||||
/* Structure to maintain a set of ACK ranges to be used to build ACK frames. */
|
||||
struct quic_arngs {
|
||||
/* ebtree of ACK ranges organized by their first value. */
|
||||
struct eb_root root;
|
||||
/* The number of ACK ranges is this tree */
|
||||
size_t sz;
|
||||
/* The number of bytes required to encode this ACK ranges lists. */
|
||||
size_t enc_sz;
|
||||
};
|
||||
|
||||
/* QUIC packet number space */
|
||||
struct quic_pktns {
|
||||
struct list list;
|
||||
|
259
src/quic_ack.c
Normal file
259
src/quic_ack.c
Normal file
@ -0,0 +1,259 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <import/eb64tree.h>
|
||||
|
||||
#include <haproxy/quic_conn-t.h>
|
||||
#include <haproxy/quic_enc.h>
|
||||
#include <haproxy/trace.h>
|
||||
|
||||
#define TRACE_SOURCE &trace_quic
|
||||
|
||||
DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng", sizeof(struct quic_arng_node));
|
||||
|
||||
/* Deallocate <l> list of ACK ranges. */
|
||||
void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs)
|
||||
{
|
||||
struct eb64_node *n;
|
||||
struct quic_arng_node *ar;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc);
|
||||
|
||||
n = eb64_first(&arngs->root);
|
||||
while (n) {
|
||||
struct eb64_node *next;
|
||||
|
||||
ar = eb64_entry(n, struct quic_arng_node, first);
|
||||
next = eb64_next(n);
|
||||
eb64_delete(n);
|
||||
pool_free(pool_head_quic_arng, ar);
|
||||
n = next;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
|
||||
}
|
||||
|
||||
/* Return the gap value between <p> and <q> ACK ranges where <q> follows <p> in
|
||||
* descending order.
|
||||
*/
|
||||
static inline size_t sack_gap(struct quic_arng_node *p,
|
||||
struct quic_arng_node *q)
|
||||
{
|
||||
return p->first.key - q->last - 2;
|
||||
}
|
||||
|
||||
/* Set the encoded size of <arngs> QUIC ack ranges. */
|
||||
static void quic_arngs_set_enc_sz(struct quic_conn *qc, struct quic_arngs *arngs)
|
||||
{
|
||||
struct eb64_node *node, *next;
|
||||
struct quic_arng_node *ar, *ar_next;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
|
||||
|
||||
node = eb64_last(&arngs->root);
|
||||
if (!node)
|
||||
goto leave;
|
||||
|
||||
ar = eb64_entry(node, struct quic_arng_node, first);
|
||||
arngs->enc_sz = quic_int_getsize(ar->last) +
|
||||
quic_int_getsize(ar->last - ar->first.key) + quic_int_getsize(arngs->sz - 1);
|
||||
|
||||
while ((next = eb64_prev(node))) {
|
||||
ar_next = eb64_entry(next, struct quic_arng_node, first);
|
||||
arngs->enc_sz += quic_int_getsize(sack_gap(ar, ar_next)) +
|
||||
quic_int_getsize(ar_next->last - ar_next->first.key);
|
||||
node = next;
|
||||
ar = eb64_entry(node, struct quic_arng_node, first);
|
||||
}
|
||||
|
||||
leave:
|
||||
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
|
||||
}
|
||||
|
||||
/* Insert <ar> ack range into <argns> tree of ack ranges.
|
||||
* Returns the ack range node which has been inserted if succeeded, NULL if not.
|
||||
*/
|
||||
static inline
|
||||
struct quic_arng_node *quic_insert_new_range(struct quic_conn *qc,
|
||||
struct quic_arngs *arngs,
|
||||
struct quic_arng *ar)
|
||||
{
|
||||
struct quic_arng_node *new_ar;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc);
|
||||
|
||||
if (arngs->sz >= QUIC_MAX_ACK_RANGES) {
|
||||
struct eb64_node *last;
|
||||
|
||||
last = eb64_last(&arngs->root);
|
||||
BUG_ON(last == NULL);
|
||||
eb64_delete(last);
|
||||
pool_free(pool_head_quic_arng, last);
|
||||
arngs->sz--;
|
||||
}
|
||||
|
||||
new_ar = pool_alloc(pool_head_quic_arng);
|
||||
if (!new_ar) {
|
||||
TRACE_ERROR("ack range allocation failed", QUIC_EV_CONN_RXPKT, qc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
new_ar->first.key = ar->first;
|
||||
new_ar->last = ar->last;
|
||||
eb64_insert(&arngs->root, &new_ar->first);
|
||||
arngs->sz++;
|
||||
|
||||
leave:
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
|
||||
return new_ar;
|
||||
}
|
||||
|
||||
/* Update <arngs> tree of ACK ranges with <ar> as new ACK range value.
|
||||
* Note that this function computes the number of bytes required to encode
|
||||
* this tree of ACK ranges in descending order.
|
||||
*
|
||||
* Descending order
|
||||
* ------------->
|
||||
* range1 range2
|
||||
* ..........|--------|..............|--------|
|
||||
* ^ ^ ^ ^
|
||||
* | | | |
|
||||
* last1 first1 last2 first2
|
||||
* ..........+--------+--------------+--------+......
|
||||
* diff1 gap12 diff2
|
||||
*
|
||||
* To encode the previous list of ranges we must encode integers as follows in
|
||||
* descending order:
|
||||
* enc(last2),enc(diff2),enc(gap12),enc(diff1)
|
||||
* with diff1 = last1 - first1
|
||||
* diff2 = last2 - first2
|
||||
* gap12 = first1 - last2 - 2 (>= 0)
|
||||
*
|
||||
|
||||
returns 0 on error
|
||||
|
||||
*/
|
||||
int quic_update_ack_ranges_list(struct quic_conn *qc,
|
||||
struct quic_arngs *arngs,
|
||||
struct quic_arng *ar)
|
||||
{
|
||||
int ret = 0;
|
||||
struct eb64_node *le;
|
||||
struct quic_arng_node *new_node;
|
||||
struct eb64_node *new;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc);
|
||||
|
||||
new = NULL;
|
||||
if (eb_is_empty(&arngs->root)) {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (new_node)
|
||||
ret = 1;
|
||||
|
||||
goto leave;
|
||||
}
|
||||
|
||||
le = eb64_lookup_le(&arngs->root, ar->first);
|
||||
if (!le) {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (!new_node)
|
||||
goto leave;
|
||||
|
||||
new = &new_node->first;
|
||||
}
|
||||
else {
|
||||
struct quic_arng_node *le_ar =
|
||||
eb64_entry(le, struct quic_arng_node, first);
|
||||
|
||||
/* Already existing range */
|
||||
if (le_ar->last >= ar->last) {
|
||||
ret = 1;
|
||||
}
|
||||
else if (le_ar->last + 1 >= ar->first) {
|
||||
le_ar->last = ar->last;
|
||||
new = le;
|
||||
new_node = le_ar;
|
||||
}
|
||||
else {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (!new_node)
|
||||
goto leave;
|
||||
|
||||
new = &new_node->first;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that the new inserted node does not overlap the nodes
|
||||
* which follow it.
|
||||
*/
|
||||
if (new) {
|
||||
struct eb64_node *next;
|
||||
struct quic_arng_node *next_node;
|
||||
|
||||
while ((next = eb64_next(new))) {
|
||||
next_node =
|
||||
eb64_entry(next, struct quic_arng_node, first);
|
||||
if (new_node->last + 1 < next_node->first.key)
|
||||
break;
|
||||
|
||||
if (next_node->last > new_node->last)
|
||||
new_node->last = next_node->last;
|
||||
eb64_delete(next);
|
||||
pool_free(pool_head_quic_arng, next_node);
|
||||
/* Decrement the size of these ranges. */
|
||||
arngs->sz--;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
leave:
|
||||
quic_arngs_set_enc_sz(qc, arngs);
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove already sent ranges of acknowledged packet numbers from
|
||||
* <pktns> packet number space tree below <largest_acked_pn> possibly
|
||||
* updating the range which contains <largest_acked_pn>.
|
||||
* Never fails.
|
||||
*/
|
||||
void qc_treat_ack_of_ack(struct quic_conn *qc, struct quic_arngs *arngs,
|
||||
int64_t largest_acked_pn)
|
||||
{
|
||||
struct eb64_node *ar, *next_ar;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc);
|
||||
|
||||
ar = eb64_first(&arngs->root);
|
||||
while (ar) {
|
||||
struct quic_arng_node *ar_node;
|
||||
|
||||
next_ar = eb64_next(ar);
|
||||
ar_node = eb64_entry(ar, struct quic_arng_node, first);
|
||||
|
||||
if ((int64_t)ar_node->first.key > largest_acked_pn) {
|
||||
TRACE_DEVEL("first.key > largest", QUIC_EV_CONN_PRSAFRM, qc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (largest_acked_pn < ar_node->last) {
|
||||
eb64_delete(ar);
|
||||
ar_node->first.key = largest_acked_pn + 1;
|
||||
eb64_insert(&arngs->root, ar);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do not empty the tree: the first ACK range contains the
|
||||
* largest acknowledged packet number.
|
||||
*/
|
||||
if (arngs->sz == 1)
|
||||
break;
|
||||
|
||||
eb64_delete(ar);
|
||||
pool_free(pool_head_quic_arng, ar_node);
|
||||
arngs->sz--;
|
||||
ar = next_ar;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
|
||||
}
|
||||
|
253
src/quic_conn.c
253
src/quic_conn.c
@ -45,6 +45,7 @@
|
||||
#include <haproxy/ncbuf.h>
|
||||
#include <haproxy/pipe.h>
|
||||
#include <haproxy/proxy.h>
|
||||
#include <haproxy/quic_ack.h>
|
||||
#include <haproxy/quic_cc.h>
|
||||
#include <haproxy/quic_cli-t.h>
|
||||
#include <haproxy/quic_frame.h>
|
||||
@ -135,7 +136,6 @@ DECLARE_POOL(pool_head_quic_tx_packet, "quic_tx_packet", sizeof(struct quic_tx_p
|
||||
DECLARE_POOL(pool_head_quic_crypto_buf, "quic_crypto_buf", sizeof(struct quic_crypto_buf));
|
||||
DECLARE_STATIC_POOL(pool_head_quic_cstream, "quic_cstream", sizeof(struct quic_cstream));
|
||||
DECLARE_POOL(pool_head_quic_frame, "quic_frame", sizeof(struct quic_frame));
|
||||
DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng", sizeof(struct quic_arng_node));
|
||||
|
||||
static struct quic_connection_id *new_quic_cid(struct eb_root *root,
|
||||
struct quic_conn *qc,
|
||||
@ -865,54 +865,6 @@ static inline void free_quic_tx_pkts(struct quic_conn *qc, struct list *pkts)
|
||||
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
|
||||
}
|
||||
|
||||
/* Remove already sent ranges of acknowledged packet numbers from
|
||||
* <pktns> packet number space tree below <largest_acked_pn> possibly
|
||||
* updating the range which contains <largest_acked_pn>.
|
||||
* Never fails.
|
||||
*/
|
||||
static void qc_treat_ack_of_ack(struct quic_conn *qc,
|
||||
struct quic_pktns *pktns,
|
||||
int64_t largest_acked_pn)
|
||||
{
|
||||
struct eb64_node *ar, *next_ar;
|
||||
struct quic_arngs *arngs = &pktns->rx.arngs;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc);
|
||||
|
||||
ar = eb64_first(&arngs->root);
|
||||
while (ar) {
|
||||
struct quic_arng_node *ar_node;
|
||||
|
||||
next_ar = eb64_next(ar);
|
||||
ar_node = eb64_entry(ar, struct quic_arng_node, first);
|
||||
|
||||
if ((int64_t)ar_node->first.key > largest_acked_pn) {
|
||||
TRACE_DEVEL("first.key > largest", QUIC_EV_CONN_PRSAFRM, qc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (largest_acked_pn < ar_node->last) {
|
||||
eb64_delete(ar);
|
||||
ar_node->first.key = largest_acked_pn + 1;
|
||||
eb64_insert(&arngs->root, ar);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do not empty the tree: the first ACK range contains the
|
||||
* largest acknowledged packet number.
|
||||
*/
|
||||
if (arngs->sz == 1)
|
||||
break;
|
||||
|
||||
eb64_delete(ar);
|
||||
pool_free(pool_head_quic_arng, ar_node);
|
||||
arngs->sz--;
|
||||
ar = next_ar;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
|
||||
}
|
||||
|
||||
/* Send a packet ack event nofication for each newly acked packet of
|
||||
* <newly_acked_pkts> list and free them.
|
||||
* Always succeeds.
|
||||
@ -936,7 +888,7 @@ static inline void qc_treat_newly_acked_pkts(struct quic_conn *qc,
|
||||
* packet number which was sent in an ACK frame by this packet.
|
||||
*/
|
||||
if (pkt->largest_acked_pn != -1)
|
||||
qc_treat_ack_of_ack(qc, pkt->pktns, pkt->largest_acked_pn);
|
||||
qc_treat_ack_of_ack(qc, &pkt->pktns->rx.arngs, pkt->largest_acked_pn);
|
||||
ev.ack.acked = pkt->in_flight_len;
|
||||
ev.ack.time_sent = pkt->time_sent;
|
||||
quic_cc_event(&qc->path->cc, &ev);
|
||||
@ -2687,207 +2639,6 @@ static int quic_build_post_handshake_frames(struct quic_conn *qc)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Deallocate <l> list of ACK ranges. */
|
||||
void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs)
|
||||
{
|
||||
struct eb64_node *n;
|
||||
struct quic_arng_node *ar;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc);
|
||||
|
||||
n = eb64_first(&arngs->root);
|
||||
while (n) {
|
||||
struct eb64_node *next;
|
||||
|
||||
ar = eb64_entry(n, struct quic_arng_node, first);
|
||||
next = eb64_next(n);
|
||||
eb64_delete(n);
|
||||
pool_free(pool_head_quic_arng, ar);
|
||||
n = next;
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
|
||||
}
|
||||
|
||||
/* Return the gap value between <p> and <q> ACK ranges where <q> follows <p> in
|
||||
* descending order.
|
||||
*/
|
||||
static inline size_t sack_gap(struct quic_arng_node *p,
|
||||
struct quic_arng_node *q)
|
||||
{
|
||||
return p->first.key - q->last - 2;
|
||||
}
|
||||
|
||||
/* Set the encoded size of <arngs> QUIC ack ranges. */
|
||||
static void quic_arngs_set_enc_sz(struct quic_conn *qc, struct quic_arngs *arngs)
|
||||
{
|
||||
struct eb64_node *node, *next;
|
||||
struct quic_arng_node *ar, *ar_next;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
|
||||
|
||||
node = eb64_last(&arngs->root);
|
||||
if (!node)
|
||||
goto leave;
|
||||
|
||||
ar = eb64_entry(node, struct quic_arng_node, first);
|
||||
arngs->enc_sz = quic_int_getsize(ar->last) +
|
||||
quic_int_getsize(ar->last - ar->first.key) + quic_int_getsize(arngs->sz - 1);
|
||||
|
||||
while ((next = eb64_prev(node))) {
|
||||
ar_next = eb64_entry(next, struct quic_arng_node, first);
|
||||
arngs->enc_sz += quic_int_getsize(sack_gap(ar, ar_next)) +
|
||||
quic_int_getsize(ar_next->last - ar_next->first.key);
|
||||
node = next;
|
||||
ar = eb64_entry(node, struct quic_arng_node, first);
|
||||
}
|
||||
|
||||
leave:
|
||||
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
|
||||
}
|
||||
|
||||
/* Insert <ar> ack range into <argns> tree of ack ranges.
|
||||
* Returns the ack range node which has been inserted if succeeded, NULL if not.
|
||||
*/
|
||||
static inline
|
||||
struct quic_arng_node *quic_insert_new_range(struct quic_conn *qc,
|
||||
struct quic_arngs *arngs,
|
||||
struct quic_arng *ar)
|
||||
{
|
||||
struct quic_arng_node *new_ar;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc);
|
||||
|
||||
if (arngs->sz >= QUIC_MAX_ACK_RANGES) {
|
||||
struct eb64_node *last;
|
||||
|
||||
last = eb64_last(&arngs->root);
|
||||
BUG_ON(last == NULL);
|
||||
eb64_delete(last);
|
||||
pool_free(pool_head_quic_arng, last);
|
||||
arngs->sz--;
|
||||
}
|
||||
|
||||
new_ar = pool_alloc(pool_head_quic_arng);
|
||||
if (!new_ar) {
|
||||
TRACE_ERROR("ack range allocation failed", QUIC_EV_CONN_RXPKT, qc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
new_ar->first.key = ar->first;
|
||||
new_ar->last = ar->last;
|
||||
eb64_insert(&arngs->root, &new_ar->first);
|
||||
arngs->sz++;
|
||||
|
||||
leave:
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
|
||||
return new_ar;
|
||||
}
|
||||
|
||||
/* Update <arngs> tree of ACK ranges with <ar> as new ACK range value.
|
||||
* Note that this function computes the number of bytes required to encode
|
||||
* this tree of ACK ranges in descending order.
|
||||
*
|
||||
* Descending order
|
||||
* ------------->
|
||||
* range1 range2
|
||||
* ..........|--------|..............|--------|
|
||||
* ^ ^ ^ ^
|
||||
* | | | |
|
||||
* last1 first1 last2 first2
|
||||
* ..........+--------+--------------+--------+......
|
||||
* diff1 gap12 diff2
|
||||
*
|
||||
* To encode the previous list of ranges we must encode integers as follows in
|
||||
* descending order:
|
||||
* enc(last2),enc(diff2),enc(gap12),enc(diff1)
|
||||
* with diff1 = last1 - first1
|
||||
* diff2 = last2 - first2
|
||||
* gap12 = first1 - last2 - 2 (>= 0)
|
||||
*
|
||||
|
||||
returns 0 on error
|
||||
|
||||
*/
|
||||
int quic_update_ack_ranges_list(struct quic_conn *qc,
|
||||
struct quic_arngs *arngs,
|
||||
struct quic_arng *ar)
|
||||
{
|
||||
int ret = 0;
|
||||
struct eb64_node *le;
|
||||
struct quic_arng_node *new_node;
|
||||
struct eb64_node *new;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_RXPKT, qc);
|
||||
|
||||
new = NULL;
|
||||
if (eb_is_empty(&arngs->root)) {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (new_node)
|
||||
ret = 1;
|
||||
|
||||
goto leave;
|
||||
}
|
||||
|
||||
le = eb64_lookup_le(&arngs->root, ar->first);
|
||||
if (!le) {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (!new_node)
|
||||
goto leave;
|
||||
|
||||
new = &new_node->first;
|
||||
}
|
||||
else {
|
||||
struct quic_arng_node *le_ar =
|
||||
eb64_entry(le, struct quic_arng_node, first);
|
||||
|
||||
/* Already existing range */
|
||||
if (le_ar->last >= ar->last) {
|
||||
ret = 1;
|
||||
}
|
||||
else if (le_ar->last + 1 >= ar->first) {
|
||||
le_ar->last = ar->last;
|
||||
new = le;
|
||||
new_node = le_ar;
|
||||
}
|
||||
else {
|
||||
new_node = quic_insert_new_range(qc, arngs, ar);
|
||||
if (!new_node)
|
||||
goto leave;
|
||||
|
||||
new = &new_node->first;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that the new inserted node does not overlap the nodes
|
||||
* which follow it.
|
||||
*/
|
||||
if (new) {
|
||||
struct eb64_node *next;
|
||||
struct quic_arng_node *next_node;
|
||||
|
||||
while ((next = eb64_next(new))) {
|
||||
next_node =
|
||||
eb64_entry(next, struct quic_arng_node, first);
|
||||
if (new_node->last + 1 < next_node->first.key)
|
||||
break;
|
||||
|
||||
if (next_node->last > new_node->last)
|
||||
new_node->last = next_node->last;
|
||||
eb64_delete(next);
|
||||
pool_free(pool_head_quic_arng, next_node);
|
||||
/* Decrement the size of these ranges. */
|
||||
arngs->sz--;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
leave:
|
||||
quic_arngs_set_enc_sz(qc, arngs);
|
||||
TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Detect the value of the spin bit to be used. */
|
||||
static inline void qc_handle_spin_bit(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||
struct quic_enc_level *qel)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <haproxy/buf.h>
|
||||
#include <haproxy/chunk.h>
|
||||
#include <haproxy/pool.h>
|
||||
#include <haproxy/quic_ack.h>
|
||||
#include <haproxy/quic_conn.h>
|
||||
#include <haproxy/quic_trace-t.h>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user