view src/event/quic/ngx_event_quic_connection.h @ 9196:6c8595b77e66

QUIC: path aware in-flight bytes accounting. On-packet acknowledgement is made path aware, as per RFC 9000, Section 9.4: Packets sent on the old path MUST NOT contribute to congestion control or RTT estimation for the new path. To make this possible in a single congestion control context, the first packet to be sent after the new path has been validated, which includes resetting the congestion controller and RTT estimator, is now remembered in the connection. Packets sent previously, such as on the old path, are not taken into account. Note that although the packet number is saved per-connection, the added checks affect application level packets only. For non-application level packets, which are only processed prior to the handshake is complete, the remembered packet number remains set to zero.
author Sergey Kandaurov <pluknet@nginx.com>
date Tue, 12 Dec 2023 20:21:12 +0400
parents ff452f283aa9
children
line wrap: on
line source

/*
 * Copyright (C) Nginx, Inc.
 */


#ifndef _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_
#define _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>


/* #define NGX_QUIC_DEBUG_PACKETS */  /* dump packet contents */
/* #define NGX_QUIC_DEBUG_FRAMES */   /* dump frames contents */
/* #define NGX_QUIC_DEBUG_ALLOC */    /* log frames and bufs alloc */
/* #define NGX_QUIC_DEBUG_CRYPTO */

typedef struct ngx_quic_connection_s  ngx_quic_connection_t;
typedef struct ngx_quic_server_id_s   ngx_quic_server_id_t;
typedef struct ngx_quic_client_id_s   ngx_quic_client_id_t;
typedef struct ngx_quic_send_ctx_s    ngx_quic_send_ctx_t;
typedef struct ngx_quic_socket_s      ngx_quic_socket_t;
typedef struct ngx_quic_path_s        ngx_quic_path_t;
typedef struct ngx_quic_keys_s        ngx_quic_keys_t;

#if (NGX_QUIC_OPENSSL_COMPAT)
#include <ngx_event_quic_openssl_compat.h>
#endif
#include <ngx_event_quic_transport.h>
#include <ngx_event_quic_protection.h>
#include <ngx_event_quic_frames.h>
#include <ngx_event_quic_migration.h>
#include <ngx_event_quic_connid.h>
#include <ngx_event_quic_streams.h>
#include <ngx_event_quic_ssl.h>
#include <ngx_event_quic_tokens.h>
#include <ngx_event_quic_ack.h>
#include <ngx_event_quic_output.h>
#include <ngx_event_quic_socket.h>


/* RFC 9002, 6.2.2.  Handshakes and New Paths: kInitialRtt */
#define NGX_QUIC_INITIAL_RTT                 333 /* ms */

#define NGX_QUIC_UNSET_PN                    (uint64_t) -1

#define NGX_QUIC_SEND_CTX_LAST               (NGX_QUIC_ENCRYPTION_LAST - 1)

/*  0-RTT and 1-RTT data exist in the same packet number space,
 *  so we have 3 packet number spaces:
 *
 *  0 - Initial
 *  1 - Handshake
 *  2 - 0-RTT and 1-RTT
 */
#define ngx_quic_get_send_ctx(qc, level)                                      \
    ((level) == ssl_encryption_initial) ? &((qc)->send_ctx[0])                \
        : (((level) == ssl_encryption_handshake) ? &((qc)->send_ctx[1])       \
                                                 : &((qc)->send_ctx[2]))

#define ngx_quic_get_connection(c)                                            \
    (((c)->udp) ? (((ngx_quic_socket_t *)((c)->udp))->quic) : NULL)

#define ngx_quic_get_socket(c)               ((ngx_quic_socket_t *)((c)->udp))

#define ngx_quic_init_rtt(qc)                                                 \
    (qc)->avg_rtt = NGX_QUIC_INITIAL_RTT;                                     \
    (qc)->rttvar = NGX_QUIC_INITIAL_RTT / 2;                                  \
    (qc)->min_rtt = NGX_TIMER_INFINITE;                                       \
    (qc)->first_rtt = NGX_TIMER_INFINITE;                                     \
    (qc)->latest_rtt = 0;


typedef enum {
    NGX_QUIC_PATH_IDLE = 0,
    NGX_QUIC_PATH_VALIDATING,
    NGX_QUIC_PATH_WAITING,
    NGX_QUIC_PATH_MTUD
} ngx_quic_path_state_e;


struct ngx_quic_client_id_s {
    ngx_queue_t                       queue;
    uint64_t                          seqnum;
    size_t                            len;
    u_char                            id[NGX_QUIC_CID_LEN_MAX];
    u_char                            sr_token[NGX_QUIC_SR_TOKEN_LEN];
    ngx_uint_t                        used;  /* unsigned  used:1; */
};


struct ngx_quic_server_id_s {
    uint64_t                          seqnum;
    size_t                            len;
    u_char                            id[NGX_QUIC_CID_LEN_MAX];
};


struct ngx_quic_path_s {
    ngx_queue_t                       queue;
    struct sockaddr                  *sockaddr;
    ngx_sockaddr_t                    sa;
    socklen_t                         socklen;
    ngx_quic_client_id_t             *cid;
    ngx_quic_path_state_e             state;
    ngx_msec_t                        expires;
    ngx_uint_t                        tries;
    ngx_uint_t                        tag;
    size_t                            mtu;
    size_t                            mtud;
    size_t                            max_mtu;
    off_t                             sent;
    off_t                             received;
    u_char                            challenge[2][8];
    uint64_t                          seqnum;
    uint64_t                          mtu_pnum[NGX_QUIC_PATH_RETRIES];
    ngx_str_t                         addr_text;
    u_char                            text[NGX_SOCKADDR_STRLEN];
    unsigned                          validated:1;
    unsigned                          mtu_unvalidated:1;
};


struct ngx_quic_socket_s {
    ngx_udp_connection_t              udp;
    ngx_quic_connection_t            *quic;
    ngx_queue_t                       queue;
    ngx_quic_server_id_t              sid;
    ngx_sockaddr_t                    sockaddr;
    socklen_t                         socklen;
    ngx_uint_t                        used; /* unsigned  used:1; */
};


typedef struct {
    ngx_rbtree_t                      tree;
    ngx_rbtree_node_t                 sentinel;

    ngx_queue_t                       uninitialized;
    ngx_queue_t                       free;

    uint64_t                          sent;
    uint64_t                          recv_offset;
    uint64_t                          recv_window;
    uint64_t                          recv_last;
    uint64_t                          recv_max_data;
    uint64_t                          send_offset;
    uint64_t                          send_max_data;

    uint64_t                          server_max_streams_uni;
    uint64_t                          server_max_streams_bidi;
    uint64_t                          server_streams_uni;
    uint64_t                          server_streams_bidi;

    uint64_t                          client_max_streams_uni;
    uint64_t                          client_max_streams_bidi;
    uint64_t                          client_streams_uni;
    uint64_t                          client_streams_bidi;

    ngx_uint_t                        initialized;
                                                 /* unsigned  initialized:1; */
} ngx_quic_streams_t;


typedef struct {
    size_t                            in_flight;
    size_t                            window;
    size_t                            ssthresh;
    ngx_msec_t                        recovery_start;
} ngx_quic_congestion_t;


/*
 * RFC 9000, 12.3.  Packet Numbers
 *
 *  Conceptually, a packet number space is the context in which a packet
 *  can be processed and acknowledged.  Initial packets can only be sent
 *  with Initial packet protection keys and acknowledged in packets that
 *  are also Initial packets.
 */
struct ngx_quic_send_ctx_s {
    enum ssl_encryption_level_t       level;

    ngx_quic_buffer_t                 crypto;
    uint64_t                          crypto_sent;

    uint64_t                          pnum;        /* to be sent */
    uint64_t                          largest_ack; /* received from peer */
    uint64_t                          largest_pn;  /* received from peer */

    ngx_queue_t                       frames;      /* generated frames */
    ngx_queue_t                       sending;     /* frames assigned to pkt */
    ngx_queue_t                       sent;        /* frames waiting ACK */

    uint64_t                          pending_ack; /* non sent ack-eliciting */
    uint64_t                          largest_range;
    uint64_t                          first_range;
    ngx_msec_t                        largest_received;
    ngx_msec_t                        ack_delay_start;
    ngx_uint_t                        nranges;
    ngx_quic_ack_range_t              ranges[NGX_QUIC_MAX_RANGES];
    ngx_uint_t                        send_ack;
};


struct ngx_quic_connection_s {
    uint32_t                          version;

    ngx_quic_path_t                  *path;

    ngx_queue_t                       sockets;
    ngx_queue_t                       paths;
    ngx_queue_t                       client_ids;
    ngx_queue_t                       free_sockets;
    ngx_queue_t                       free_paths;
    ngx_queue_t                       free_client_ids;

    ngx_uint_t                        nsockets;
    ngx_uint_t                        nclient_ids;
    uint64_t                          max_retired_seqnum;
    uint64_t                          client_seqnum;
    uint64_t                          server_seqnum;
    uint64_t                          path_seqnum;

    ngx_quic_tp_t                     tp;
    ngx_quic_tp_t                     ctp;

    ngx_quic_send_ctx_t               send_ctx[NGX_QUIC_SEND_CTX_LAST];

    ngx_quic_keys_t                  *keys;

    ngx_quic_conf_t                  *conf;

    ngx_event_t                       push;
    ngx_event_t                       pto;
    ngx_event_t                       close;
    ngx_event_t                       path_validation;
    ngx_event_t                       key_update;

    ngx_msec_t                        last_cc;

    ngx_msec_t                        first_rtt;
    ngx_msec_t                        latest_rtt;
    ngx_msec_t                        avg_rtt;
    ngx_msec_t                        min_rtt;
    ngx_msec_t                        rttvar;

    ngx_uint_t                        pto_count;

    ngx_queue_t                       free_frames;
    ngx_buf_t                        *free_bufs;
    ngx_buf_t                        *free_shadow_bufs;

    ngx_uint_t                        nframes;
#ifdef NGX_QUIC_DEBUG_ALLOC
    ngx_uint_t                        nbufs;
    ngx_uint_t                        nshadowbufs;
#endif

#if (NGX_QUIC_OPENSSL_COMPAT)
    ngx_quic_compat_t                *compat;
#endif

    ngx_quic_streams_t                streams;
    ngx_quic_congestion_t             congestion;

    uint64_t                          rst_pnum;    /* first on validated path */

    off_t                             received;

    ngx_uint_t                        error;
    enum ssl_encryption_level_t       error_level;
    ngx_uint_t                        error_ftype;
    const char                       *error_reason;

    ngx_uint_t                        shutdown_code;
    const char                       *shutdown_reason;

    unsigned                          error_app:1;
    unsigned                          send_timer_set:1;
    unsigned                          closing:1;
    unsigned                          shutdown:1;
    unsigned                          draining:1;
    unsigned                          key_phase:1;
    unsigned                          validated:1;
    unsigned                          client_tp_done:1;
};


ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c,
    ngx_quic_tp_t *ctp);
void ngx_quic_discard_ctx(ngx_connection_t *c,
    enum ssl_encryption_level_t level);
void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
void ngx_quic_shutdown_quic(ngx_connection_t *c);

#if (NGX_DEBUG)
void ngx_quic_connstate_dbg(ngx_connection_t *c);
#else
#define ngx_quic_connstate_dbg(c)
#endif

#endif /* _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ */