MINOR: quic: Split QUIC connection code into three parts

Move the TX part of the code to quic_tx.c.
Add quic_tx-t.h and quic_tx.h headers for this TX part code.
The definition of quic_tx_packet struct has been move from quic_conn-t.h to
quic_tx-t.h.

Same thing for the TX part:
Move the RX part of the code to quic_rx.c.
Add quic_rx-t.h and quic_rx.h headers for this TX part code.
The definition of quic_rx_packet struct has been move from quic_conn-t.h to
quic_rx-t.h.
This commit is contained in:
Frédéric Lécaille 2023-07-25 15:42:16 +02:00
parent 2fe50a01ca
commit 444c1a4113
14 changed files with 5508 additions and 5317 deletions

View File

@ -608,7 +608,8 @@ OPTIONS_OBJS += src/quic_conn.o src/mux_quic.o src/h3.o src/xprt_quic.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/quic_ack.o \
src/quic_trace.o src/quic_cli.o src/quic_ssl.o
src/quic_trace.o src/quic_cli.o src/quic_ssl.o \
src/quic_rx.o src/quic_tx.o
endif
ifneq ($(USE_QUIC_OPENSSL_COMPAT),)

View File

@ -254,11 +254,8 @@ enum quic_pkt_type {
#define QUIC_CONN_RX_BUFSZ (1UL << 16)
extern struct trace_source trace_quic;
extern struct pool_head *pool_head_quic_rx_packet;
extern struct pool_head *pool_head_quic_tx_packet;
extern struct pool_head *pool_head_quic_crypto_buf;
extern struct pool_head *pool_head_quic_frame;
extern struct pool_head *pool_head_quic_dgram;
struct quic_version {
uint32_t num;
@ -341,52 +338,6 @@ struct quic_dgram {
/* The QUIC packet numbers are 62-bits integers */
#define QUIC_MAX_PACKET_NUM ((1ULL << 62) - 1)
/* Maximum number of ack-eliciting received packets since the last
* ACK frame was sent
*/
#define QUIC_MAX_RX_AEPKTS_SINCE_LAST_ACK 2
#define QUIC_ACK_DELAY (QUIC_TP_DFLT_MAX_ACK_DELAY - 5)
/* Flag a received packet as being an ack-eliciting packet. */
#define QUIC_FL_RX_PACKET_ACK_ELICITING (1UL << 0)
/* Packet is the first one in the containing datagram. */
#define QUIC_FL_RX_PACKET_DGRAM_FIRST (1UL << 1)
/* Spin bit set */
#define QUIC_FL_RX_PACKET_SPIN_BIT (1UL << 2)
struct quic_rx_packet {
struct list list;
struct list qc_rx_pkt_list;
/* QUIC version used in packet. */
const struct quic_version *version;
unsigned char type;
/* Initial desctination connection ID. */
struct quic_cid dcid;
struct quic_cid scid;
/* Packet number offset : only valid for Initial/Handshake/0-RTT/1-RTT. */
size_t pn_offset;
/* Packet number */
int64_t pn;
/* Packet number length */
uint32_t pnl;
uint64_t token_len;
unsigned char *token;
/* Packet length */
uint64_t len;
/* Packet length before decryption */
uint64_t raw_len;
/* Additional authenticated data length */
size_t aad_len;
unsigned char *data;
struct eb64_node pn_node;
volatile unsigned int refcnt;
/* Source address of this packet. */
struct sockaddr_storage saddr;
unsigned int flags;
unsigned int time_received;
};
/* QUIC datagram handler */
struct quic_dghdlr {
struct mt_list dgrams;
@ -401,51 +352,6 @@ struct quic_rx_crypto_frm {
struct quic_rx_packet *pkt;
};
/* Flag a sent packet as being an ack-eliciting packet. */
#define QUIC_FL_TX_PACKET_ACK_ELICITING (1UL << 0)
/* Flag a sent packet as containing a PADDING frame. */
#define QUIC_FL_TX_PACKET_PADDING (1UL << 1)
/* Flag a sent packet as being in flight. */
#define QUIC_FL_TX_PACKET_IN_FLIGHT (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING)
/* Flag a sent packet as containing a CONNECTION_CLOSE frame */
#define QUIC_FL_TX_PACKET_CC (1UL << 2)
/* Flag a sent packet as containing an ACK frame */
#define QUIC_FL_TX_PACKET_ACK (1UL << 3)
/* Flag a sent packet as being coalesced to another one in the same datagram */
#define QUIC_FL_TX_PACKET_COALESCED (1UL << 4)
/* Flag a sent packet as being probing with old data */
#define QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA (1UL << 5)
/* Structure to store enough information about TX QUIC packets. */
struct quic_tx_packet {
/* List entry point. */
struct list list;
/* Packet length */
size_t len;
/* This is not the packet length but the length of outstanding data
* for in flight TX packet.
*/
size_t in_flight_len;
struct eb64_node pn_node;
/* The list of frames of this packet. */
struct list frms;
/* The time this packet was sent (ms). */
unsigned int time_sent;
/* Packet number spakce. */
struct quic_pktns *pktns;
/* Flags. */
unsigned int flags;
/* Reference counter */
int refcnt;
/* Next packet in the same datagram */
struct quic_tx_packet *next;
/* Previous packet in the same datagram */
struct quic_tx_packet *prev;
/* Largest acknowledged packet number if this packet contains an ACK frame */
int64_t largest_acked_pn;
unsigned char type;
};
#define QUIC_CRYPTO_BUF_SHIFT 10
#define QUIC_CRYPTO_BUF_MASK ((1UL << QUIC_CRYPTO_BUF_SHIFT) - 1)
/* The maximum allowed size of CRYPTO data buffer provided by the TLS stack. */

View File

@ -44,6 +44,7 @@
#include <haproxy/quic_enc.h>
#include <haproxy/quic_frame.h>
#include <haproxy/quic_loss.h>
#include <haproxy/quic_rx-t.h>
#include <haproxy/mux_quic.h>
#include <openssl/rand.h>
@ -58,6 +59,31 @@ void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs);
struct quic_cstream *quic_cstream_new(struct quic_conn *qc);
struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state);
struct quic_connection_id *new_quic_cid(struct eb_root *root,
struct quic_conn *qc,
const struct quic_cid *orig,
const struct sockaddr_storage *addr);
void qc_cc_err_count_inc(struct quic_conn *qc, struct quic_frame *frm);
int qc_h3_request_reject(struct quic_conn *qc, uint64_t id);
int qc_build_new_connection_id_frm(struct quic_conn *qc,
struct quic_connection_id *conn_id);
struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
struct quic_cid *dcid, struct quic_cid *scid,
const struct quic_cid *token_odcid,
struct quic_connection_id *conn_id,
struct sockaddr_storage *local_addr,
struct sockaddr_storage *peer_addr,
int server, int token, void *owner);
const struct quic_version *qc_supported_version(uint32_t version);
int quic_peer_validated_addr(struct quic_conn *qc);
void qc_set_timer(struct quic_conn *qc);
void qc_detach_th_ctx_list(struct quic_conn *qc, int closing);
void qc_idle_timer_do_rearm(struct quic_conn *qc, int arm_ack);
void qc_idle_timer_rearm(struct quic_conn *qc, int read, int arm_ack);
void qc_check_close_on_released_mux(struct quic_conn *qc);
int quic_stateless_reset_token_cpy(unsigned char *pos, size_t len,
const unsigned char *salt, size_t saltlen);
/* Return the long packet type matching with <qv> version and <type> */
static inline int quic_pkt_type(int type, uint32_t version)
{
@ -409,38 +435,6 @@ static inline uint64_t quic_compute_ack_delay_us(unsigned int time_received,
return ((now_ms - time_received) * 1000) >> conn->tx.params.ack_delay_exponent;
}
/* The TX packets sent in the same datagram are linked to each others in
* the order they are built. This function detach a packet from its successor
* and predecessor in the same datagram.
*/
static inline void quic_tx_packet_dgram_detach(struct quic_tx_packet *pkt)
{
if (pkt->prev)
pkt->prev->next = pkt->next;
if (pkt->next)
pkt->next->prev = pkt->prev;
}
/* Increment the reference counter of <pkt> */
static inline void quic_tx_packet_refinc(struct quic_tx_packet *pkt)
{
pkt->refcnt++;
}
/* Decrement the reference counter of <pkt> */
static inline void quic_tx_packet_refdec(struct quic_tx_packet *pkt)
{
if (--pkt->refcnt == 0) {
BUG_ON(!LIST_ISEMPTY(&pkt->frms));
/* If there are others packet in the same datagram <pkt> is attached to,
* detach the previous one and the next one from <pkt>.
*/
quic_tx_packet_dgram_detach(pkt);
pool_free(pool_head_quic_tx_packet, pkt);
}
}
/* Initialize <p> QUIC network path depending on <ipv4> boolean
* which is true for an IPv4 path, if not false for an IPv6 path.
*/
@ -581,8 +575,6 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms);
void qc_notify_err(struct quic_conn *qc);
int qc_notify_send(struct quic_conn *qc);
void qc_release_frm(struct quic_conn *qc, struct quic_frame *frm);
void qc_check_close_on_released_mux(struct quic_conn *qc);
void quic_conn_release(struct quic_conn *qc);

View File

@ -41,6 +41,8 @@ int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt,
const unsigned char **pos, const unsigned char *end,
struct quic_conn *conn);
void qc_release_frm(struct quic_conn *qc, struct quic_frame *frm);
/* Return the length of <frm> frame if succeeded, -1 if not (unknown frames
* or which must not be transmitted again after having been lost (PING, PADDING).
*/

View File

@ -0,0 +1,54 @@
#ifndef _HAPROXY_RX_T_H
#define _HAPROXY_RX_T_H
extern struct pool_head *pool_head_quic_conn_rxbuf;
extern struct pool_head *pool_head_quic_dgram;
extern struct pool_head *pool_head_quic_rx_packet;
/* Maximum number of ack-eliciting received packets since the last
* ACK frame was sent
*/
#define QUIC_MAX_RX_AEPKTS_SINCE_LAST_ACK 2
#define QUIC_ACK_DELAY (QUIC_TP_DFLT_MAX_ACK_DELAY - 5)
/* Flag a received packet as being an ack-eliciting packet. */
#define QUIC_FL_RX_PACKET_ACK_ELICITING (1UL << 0)
/* Packet is the first one in the containing datagram. */
#define QUIC_FL_RX_PACKET_DGRAM_FIRST (1UL << 1)
/* Spin bit set */
#define QUIC_FL_RX_PACKET_SPIN_BIT (1UL << 2)
struct quic_rx_packet {
struct list list;
struct list qc_rx_pkt_list;
/* QUIC version used in packet. */
const struct quic_version *version;
unsigned char type;
/* Initial desctination connection ID. */
struct quic_cid dcid;
struct quic_cid scid;
/* Packet number offset : only valid for Initial/Handshake/0-RTT/1-RTT. */
size_t pn_offset;
/* Packet number */
int64_t pn;
/* Packet number length */
uint32_t pnl;
uint64_t token_len;
unsigned char *token;
/* Packet length */
uint64_t len;
/* Packet length before decryption */
uint64_t raw_len;
/* Additional authenticated data length */
size_t aad_len;
unsigned char *data;
struct eb64_node pn_node;
volatile unsigned int refcnt;
/* Source address of this packet. */
struct sockaddr_storage saddr;
unsigned int flags;
unsigned int time_received;
};
#endif /* _HAPROXY_RX_T_H */

37
include/haproxy/quic_rx.h Normal file
View File

@ -0,0 +1,37 @@
/*
* QUIC protocol definitions (RX side).
*
* Copyright (C) 2023
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_QUIC_RX_H
#define _HAPROXY_QUIC_RX_H
#include <haproxy/listener-t.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_rx-t.h>
int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
struct listener *li);
int qc_treat_rx_pkts(struct quic_conn *qc);
int qc_parse_hd_form(struct quic_rx_packet *pkt,
unsigned char **pos, const unsigned char *end);
void quic_free_ncbuf(struct ncbuf *ncbuf);
int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns,
struct list *pkts, uint64_t now_us);
#endif /* _HAPROXY_QUIC_RX_H */

View File

@ -28,6 +28,7 @@
#include <haproxy/quic_conn.h>
#include <haproxy/quic_frame.h>
#include <haproxy/quic_tls-t.h>
#include <haproxy/quic_tx.h>
#include <haproxy/trace.h>
int quic_tls_finalize(struct quic_conn *qc, int server);
@ -538,6 +539,21 @@ static inline void quic_pktns_discard(struct quic_pktns *pktns,
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
}
/* Release all the frames attached to <pktns> packet number space */
static inline void qc_release_pktns_frms(struct quic_conn *qc,
struct quic_pktns *pktns)
{
struct quic_frame *frm, *frmbak;
TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
list_for_each_entry_safe(frm, frmbak, &pktns->tx.frms, list)
qc_frm_free(qc, &frm);
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
}
/* Return 1 if <pktns> matches with the Application packet number space of
* <conn> connection which is common to the 0-RTT and 1-RTT encryption levels, 0
* if not (handshake packets).
@ -640,6 +656,19 @@ static inline int quic_tls_pkt_type_pktns_dcd(struct quic_conn *qc, unsigned cha
return 0;
}
/* Select the correct TLS cipher context to used to decipher an RX packet
* with <type> as type and <version> as version and attached to <qc>
* connection from <qel> encryption level.
*/
static inline struct quic_tls_ctx *qc_select_tls_ctx(struct quic_conn *qc,
struct quic_enc_level *qel,
unsigned char type,
const struct quic_version *version)
{
return type != QUIC_PACKET_TYPE_INITIAL ? &qel->tls_ctx :
version == qc->negotiated_version ? qc->nictx : &qel->tls_ctx;
}
/* Reset all members of <ctx> to default values, ->hp_key[] excepted */
static inline void quic_tls_ctx_reset(struct quic_tls_ctx *ctx)
{

View File

@ -0,0 +1,51 @@
#ifndef _HAPROXY_TX_T_H
#define _HAPROXY_TX_T_H
extern struct pool_head *pool_head_quic_tx_packet;
/* Flag a sent packet as being an ack-eliciting packet. */
#define QUIC_FL_TX_PACKET_ACK_ELICITING (1UL << 0)
/* Flag a sent packet as containing a PADDING frame. */
#define QUIC_FL_TX_PACKET_PADDING (1UL << 1)
/* Flag a sent packet as being in flight. */
#define QUIC_FL_TX_PACKET_IN_FLIGHT (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING)
/* Flag a sent packet as containing a CONNECTION_CLOSE frame */
#define QUIC_FL_TX_PACKET_CC (1UL << 2)
/* Flag a sent packet as containing an ACK frame */
#define QUIC_FL_TX_PACKET_ACK (1UL << 3)
/* Flag a sent packet as being coalesced to another one in the same datagram */
#define QUIC_FL_TX_PACKET_COALESCED (1UL << 4)
/* Flag a sent packet as being probing with old data */
#define QUIC_FL_TX_PACKET_PROBE_WITH_OLD_DATA (1UL << 5)
/* Structure to store enough information about TX QUIC packets. */
struct quic_tx_packet {
/* List entry point. */
struct list list;
/* Packet length */
size_t len;
/* This is not the packet length but the length of outstanding data
* for in flight TX packet.
*/
size_t in_flight_len;
struct eb64_node pn_node;
/* The list of frames of this packet. */
struct list frms;
/* The time this packet was sent (ms). */
unsigned int time_sent;
/* Packet number spakce. */
struct quic_pktns *pktns;
/* Flags. */
unsigned int flags;
/* Reference counter */
int refcnt;
/* Next packet in the same datagram */
struct quic_tx_packet *next;
/* Previous packet in the same datagram */
struct quic_tx_packet *prev;
/* Largest acknowledged packet number if this packet contains an ACK frame */
int64_t largest_acked_pn;
unsigned char type;
};
#endif /* _HAPROXY_TX_T_H */

89
include/haproxy/quic_tx.h Normal file
View File

@ -0,0 +1,89 @@
/*
* QUIC protocol definitions (TX side).
*
* Copyright (C) 2023
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_QUIC_TX_H
#define _HAPROXY_QUIC_TX_H
#include <haproxy/buf-t.h>
#include <haproxy/list-t.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_tls-t.h>
#include <haproxy/quic_tx-t.h>
struct buffer *qc_txb_alloc(struct quic_conn *qc);
void qc_txb_release(struct quic_conn *qc);
int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf);
int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel);
int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels);
int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx);
int qc_may_probe_ipktns(struct quic_conn *qc);
int quic_build_post_handshake_frames(struct quic_conn *qc);
int qc_send_app_pkts(struct quic_conn *qc, struct list *frms);
int qc_dgrams_retransmit(struct quic_conn *qc);
int qc_notify_send(struct quic_conn *qc);
void free_quic_tx_pkts(struct quic_conn *qc, struct list *pkts);
void qc_prep_hdshk_fast_retrans(struct quic_conn *qc,
struct list *ifrms, struct list *hfrms);
int quic_generate_retry_token_aad(unsigned char *aad,
uint32_t version,
const struct quic_cid *dcid,
const struct quic_cid *scid,
const struct sockaddr_storage *addr);
int send_retry(int fd, struct sockaddr_storage *addr,
struct quic_rx_packet *pkt, const struct quic_version *qv);
int send_stateless_reset(struct listener *l, struct sockaddr_storage *dstaddr,
struct quic_rx_packet *rxpkt);
int send_version_negotiation(int fd, struct sockaddr_storage *addr,
struct quic_rx_packet *pkt);
/* The TX packets sent in the same datagram are linked to each others in
* the order they are built. This function detach a packet from its successor
* and predecessor in the same datagram.
*/
static inline void quic_tx_packet_dgram_detach(struct quic_tx_packet *pkt)
{
if (pkt->prev)
pkt->prev->next = pkt->next;
if (pkt->next)
pkt->next->prev = pkt->prev;
}
/* Increment the reference counter of <pkt> */
static inline void quic_tx_packet_refinc(struct quic_tx_packet *pkt)
{
pkt->refcnt++;
}
/* Decrement the reference counter of <pkt> */
static inline void quic_tx_packet_refdec(struct quic_tx_packet *pkt)
{
if (--pkt->refcnt == 0) {
BUG_ON(!LIST_ISEMPTY(&pkt->frms));
/* If there are others packet in the same datagram <pkt> is attached to,
* detach the previous one and the next one from <pkt>.
*/
quic_tx_packet_dgram_detach(pkt);
pool_free(pool_head_quic_tx_packet, pkt);
}
}
#endif /* _HAPROXY_QUIC_TX_H */

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,9 @@
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_enc.h>
#include <haproxy/quic_frame.h>
#include <haproxy/quic_rx-t.h>
#include <haproxy/quic_tp-t.h>
#include <haproxy/quic_tx.h>
#include <haproxy/trace.h>
#define TRACE_SOURCE &trace_quic
@ -1221,3 +1223,49 @@ void qc_frm_free(struct quic_conn *qc, struct quic_frame **frm)
*frm = NULL;
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
}
/* Release <frm> frame and mark its copies as acknowledged */
void qc_release_frm(struct quic_conn *qc, struct quic_frame *frm)
{
uint64_t pn;
struct quic_frame *origin, *f, *tmp;
TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc);
/* Identify this frame: a frame copy or one of its copies */
origin = frm->origin ? frm->origin : frm;
/* Ensure the source of the copies is flagged as acked, <frm> being
* possibly a copy of <origin>
*/
origin->flags |= QUIC_FL_TX_FRAME_ACKED;
/* Mark all the copy of <origin> as acknowledged. We must
* not release the packets (releasing the frames) at this time as
* they are possibly also to be acknowledged alongside the
* the current one.
*/
list_for_each_entry_safe(f, tmp, &origin->reflist, ref) {
if (f->pkt) {
f->flags |= QUIC_FL_TX_FRAME_ACKED;
f->origin = NULL;
LIST_DEL_INIT(&f->ref);
pn = f->pkt->pn_node.key;
TRACE_DEVEL("mark frame as acked from packet",
QUIC_EV_CONN_PRSAFRM, qc, f, &pn);
}
else {
TRACE_DEVEL("freeing unsent frame",
QUIC_EV_CONN_PRSAFRM, qc, f);
LIST_DEL_INIT(&f->ref);
qc_frm_free(qc, &f);
}
}
LIST_DEL_INIT(&frm->list);
pn = frm->pkt->pn_node.key;
quic_tx_packet_refdec(frm->pkt);
TRACE_DEVEL("freeing frame from packet",
QUIC_EV_CONN_PRSAFRM, qc, frm, &pn);
qc_frm_free(qc, &frm);
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
}

2586
src/quic_rx.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@
#include <haproxy/proto_quic.h>
#include <haproxy/proxy-t.h>
#include <haproxy/quic_conn.h>
#include <haproxy/quic_rx.h>
#include <haproxy/quic_sock.h>
#include <haproxy/quic_tp-t.h>
#include <haproxy/session.h>

2558
src/quic_tx.c Normal file

File diff suppressed because it is too large Load Diff