From 36bd1a563bf772e1c36c9abf73b7483a72a2d924 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Tue, 10 Dec 2024 09:29:44 +0000 Subject: [PATCH] quic: test FD_QUIC_ACK_TX_ENOSPC metrics reporting --- src/waltz/quic/tests/fd_quic_sandbox.c | 43 ++++++++++++++++++++ src/waltz/quic/tests/fd_quic_sandbox.h | 8 ++++ src/waltz/quic/tests/test_quic_conformance.c | 37 ++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/waltz/quic/tests/fd_quic_sandbox.c b/src/waltz/quic/tests/fd_quic_sandbox.c index 99473b6077..b39cf259a6 100644 --- a/src/waltz/quic/tests/fd_quic_sandbox.c +++ b/src/waltz/quic/tests/fd_quic_sandbox.c @@ -1,5 +1,6 @@ #include "fd_quic_sandbox.h" #include "../fd_quic_private.h" +#include "../templ/fd_quic_parse_util.h" /* fd_quic_sandbox_capture_pkt captures a single outgoing packet sent by fd_quic. */ @@ -304,6 +305,7 @@ fd_quic_sandbox_new_conn_established( fd_quic_sandbox_t * sandbox, conn->handshake_complete = 1; conn->hs_data_empty = 1; conn->peer_enc_level = fd_quic_enc_level_appdata_id; + conn->keys_avail = 1U<idle_timeout = FD_QUIC_SANDBOX_IDLE_TIMEOUT; conn->last_activity = sandbox->wallclock; @@ -382,3 +384,44 @@ fd_quic_sandbox_send_lone_frame( fd_quic_sandbox_t * sandbox, /* Synchronize log seq[0] from tx to rx */ fd_quic_log_tx_seq_update( fd_quic_get_state( sandbox->quic )->log_tx ); } + +void +fd_quic_sandbox_send_ping_pkt( fd_quic_sandbox_t * sandbox, + fd_quic_conn_t * conn, + ulong pktnum ) { + + uchar pkt_buf[ 256 ]; + pkt_buf[0] = fd_quic_one_rtt_h0( /* spin */ 0, + /* key_phase */ !!conn->key_phase, + /* pktnum_len-1 */ 3 ); + memcpy( pkt_buf+1, &conn->our_conn_id, FD_QUIC_CONN_ID_SZ ); + uint pktnum_comp = fd_uint_bswap( (uint)( pktnum & UINT_MAX ) ); + memcpy( pkt_buf+9, &pktnum_comp, 4 ); + pkt_buf[13] = 0x01; /* PING frame */ + memset( pkt_buf+14, 0, 18UL ); + + fd_quic_crypto_keys_t * keys = &conn->keys[fd_quic_enc_level_appdata_id][!conn->server]; + ulong out_sz = 48UL; + int crypt_res = fd_quic_crypto_encrypt( pkt_buf, &out_sz, pkt_buf, 13UL, pkt_buf+13, 19UL, keys, keys, pktnum ); + FD_TEST( crypt_res==FD_QUIC_SUCCESS ); + + fd_quic_pkt_t pkt_meta = { + .ip4 = {{ + .verihl = FD_IP4_VERIHL(4,5), + .net_tot_len = 28, + .net_frag_off = 0x4000u, /* don't fragment */ + .ttl = 64, + .protocol = FD_IP4_HDR_PROTOCOL_UDP, + }}, + .udp = {{ + .net_sport = FD_QUIC_SANDBOX_PEER_PORT, + .net_dport = FD_QUIC_SANDBOX_SELF_PORT, + .net_len = 8, + }}, + .pkt_number = pktnum, + .rcv_time = sandbox->wallclock, + .enc_level = fd_quic_enc_level_appdata_id, + }; + + fd_quic_process_quic_packet_v1( sandbox->quic, &pkt_meta, pkt_buf, out_sz ); +} diff --git a/src/waltz/quic/tests/fd_quic_sandbox.h b/src/waltz/quic/tests/fd_quic_sandbox.h index 109d7700d7..48efd9b306 100644 --- a/src/waltz/quic/tests/fd_quic_sandbox.h +++ b/src/waltz/quic/tests/fd_quic_sandbox.h @@ -225,6 +225,14 @@ fd_quic_sandbox_send_lone_frame( fd_quic_sandbox_t * sandbox, uchar const * frame, ulong frame_sz ); +/* fd_quic_sandbox_send_ping_pkt sends a 1-RTT packet containing only a + PING frame. */ + +void +fd_quic_sandbox_send_ping_pkt( fd_quic_sandbox_t * sandbox, + fd_quic_conn_t * conn, + ulong pktnum ); + FD_PROTOTYPES_END #endif /* HEADER_fd_src_waltz_quic_tests_fd_quic_sandbox_h */ diff --git a/src/waltz/quic/tests/test_quic_conformance.c b/src/waltz/quic/tests/test_quic_conformance.c index d18ee4ce03..e0f42ddcdd 100644 --- a/src/waltz/quic/tests/test_quic_conformance.c +++ b/src/waltz/quic/tests/test_quic_conformance.c @@ -231,6 +231,40 @@ test_quic_server_alpn_fail( fd_quic_sandbox_t * sandbox, } +/* Ensure that outgoing ACKs and metrics are done correctly if incoming + packets skip packet numbers aggressively. */ + +void +test_quic_pktnum_skip( fd_quic_sandbox_t * sandbox, + fd_rng_t * rng ) { + + fd_quic_sandbox_init( sandbox, FD_QUIC_ROLE_SERVER ); + fd_quic_conn_t * conn = fd_quic_sandbox_new_conn_established( sandbox, rng ); + fd_quic_ack_gen_t * ack_gen = conn->ack_gen; + fd_quic_metrics_t * metrics = &conn->quic->metrics; + FD_TEST( ack_gen->tail==0 && ack_gen->head==0 ); + + /* Fill the ACK TX buffer with pending ACK frames */ + ulong pktnum = 60UL; + for( ulong j=0UL; jpkt_decrypt_fail_cnt==0 ); + FD_TEST( ack_gen->head - ack_gen->tail == FD_QUIC_ACK_QUEUE_CNT ); + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_NOOP ] == 0 ); + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_NEW ] == FD_QUIC_ACK_QUEUE_CNT ); + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_MERGED ] == 0 ); + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_ENOSPC ] == 0 ); + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_CANCEL ] == 0 ); + + /* Overflow the ACK queue */ + fd_quic_sandbox_send_ping_pkt( sandbox, conn, pktnum ); + pktnum += 2UL; + FD_TEST( metrics->ack_tx[ FD_QUIC_ACK_TX_ENOSPC ] == 1 ); + +} + static __attribute__((noinline)) void test_quic_parse_path_challenge( void ) { fd_quic_path_challenge_frame_t path_challenge[1]; @@ -251,8 +285,6 @@ test_quic_parse_path_challenge( void ) { } while(0); } -/* Test FIN arriving out of place */ - int main( int argc, char ** argv ) { @@ -304,6 +336,7 @@ main( int argc, test_quic_stream_concurrency ( sandbox, rng ); test_quic_ping_frame ( sandbox, rng ); test_quic_server_alpn_fail ( sandbox, rng ); + test_quic_pktnum_skip ( sandbox, rng ); test_quic_parse_path_challenge(); /* Wind down */