Line data Source code
1 : /* This directory provides the 'fddev quic-trace' subcommand. 2 : 3 : The goal of quic-trace is to tap QUIC traffic on a live system, which 4 : requires encryption keys and other annoying connection state. 5 : 6 : quic-trace does this by tapping into the shared memory segments of an 7 : fd_quic_tile running on the same host. It does so strictly read-only 8 : to minimize impact to a production system. 9 : 10 : This file (fd_quic_trace_main.c) provides the glue code required to 11 : join remote fd_quic_tile objects. 12 : 13 : fd_quic_trace_rx_tile.c provides a fd_tango consumer for incoming 14 : QUIC packets. */ 15 : 16 : #include "fd_quic_trace.h" 17 : #include "../fddev.h" 18 : #include "../../../disco/quic/fd_quic_tile.h" 19 : #include "../../../waltz/quic/log/fd_quic_log_user.h" 20 : 21 : /* Define global variables */ 22 : 23 : fd_quic_ctx_t fd_quic_trace_ctx; 24 : fd_quic_ctx_t const * fd_quic_trace_ctx_remote; 25 : ulong fd_quic_trace_ctx_raddr; 26 : ulong ** fd_quic_trace_target_fseq; 27 : ulong volatile * fd_quic_trace_link_metrics; 28 : void const * fd_quic_trace_log_base; 29 : 30 0 : #define EVENT_STREAM 0 31 0 : #define EVENT_ERROR 1 32 : 33 : void 34 : quic_trace_cmd_args( int * pargc, 35 : char *** pargv, 36 0 : args_t * args ) { 37 0 : char const * event = fd_env_strip_cmdline_cstr( pargc, pargv, "--event", NULL, "stream" ); 38 0 : if( 0==strcmp( event, "stream" ) ) { 39 0 : args->quic_trace.event = EVENT_STREAM; 40 0 : } else if( 0==strcmp( event, "error" ) ) { 41 0 : args->quic_trace.event = EVENT_ERROR; 42 0 : } else { 43 0 : FD_LOG_ERR(( "Unsupported QUIC event type \"%s\"", event )); 44 0 : } 45 : 46 0 : args->quic_trace.dump = fd_env_strip_cmdline_contains( pargc, pargv, "--dump" ); 47 0 : } 48 : 49 : void 50 : quic_trace_cmd_fn( args_t * args, 51 0 : config_t * config ) { 52 0 : fd_topo_t * topo = &config->topo; 53 0 : fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_ONLY ); 54 0 : fd_topo_fill( topo ); 55 : 56 0 : fd_topo_tile_t * quic_tile = NULL; 57 0 : for( ulong tile_idx=0UL; tile_idx < topo->tile_cnt; tile_idx++ ) { 58 0 : if( 0==strcmp( topo->tiles[ tile_idx ].name, "quic" ) ) { 59 0 : quic_tile = &topo->tiles[ tile_idx ]; 60 0 : break; 61 0 : } 62 0 : } 63 0 : if( !quic_tile ) FD_LOG_ERR(( "QUIC tile not found in topology" )); 64 : 65 : /* Ugly: fd_quic_ctx_t uses non-relocatable object addressing. 66 : We need to rebase pointers. foreign_{...} refer to the original 67 : objects in shared memory, local_{...} refer to translated copies. */ 68 : 69 0 : void * quic_tile_base = fd_topo_obj_laddr( topo, quic_tile->tile_obj_id ); 70 0 : fd_quic_ctx_t const * foreign_quic_ctx = quic_tile_base; 71 0 : fd_quic_ctx_t * quic_ctx = &fd_quic_trace_ctx; 72 0 : *quic_ctx = *foreign_quic_ctx; 73 0 : fd_quic_trace_ctx_remote = foreign_quic_ctx; 74 : 75 0 : ulong quic_raddr = (ulong)foreign_quic_ctx->quic; 76 0 : ulong ctx_raddr = quic_raddr - fd_ulong_align_up( sizeof(fd_quic_ctx_t), fd_ulong_max( alignof(fd_quic_ctx_t), fd_quic_align() ) ); 77 0 : fd_quic_trace_ctx_raddr = ctx_raddr; 78 : 79 0 : FD_LOG_INFO(( "fd_quic_tile state at %p in tile address space", (void *)ctx_raddr )); 80 0 : FD_LOG_INFO(( "fd_quic_tile state at %p in local address space", quic_tile_base )); 81 : 82 0 : quic_ctx->reasm = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->reasm - ctx_raddr ); 83 0 : quic_ctx->stem = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->stem - ctx_raddr ); 84 0 : quic_ctx->quic = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->quic - ctx_raddr ); 85 : 86 0 : fd_topo_link_t * net_quic = &topo->links[ quic_tile->in_link_id[ 0 ] ]; 87 0 : fd_net_rx_bounds_init( &quic_ctx->net_in_bounds, net_quic->dcache ); 88 0 : FD_LOG_INFO(( "net->quic dcache at %p", (void *)net_quic->dcache )); 89 : 90 : /* Join shared memory objects 91 : Mostly nops but verifies object magic numbers to ensure that 92 : derived pointers are correct. */ 93 : 94 0 : FD_LOG_INFO(( "Joining fd_quic" )); 95 0 : fd_quic_t * quic = fd_quic_join( quic_ctx->quic ); 96 0 : if( !quic ) FD_LOG_ERR(( "Failed to join fd_quic" )); 97 : 98 : /* Locate original fseq objects 99 : These are monitored to ensure the trace RX tile doesn't skip ahead 100 : of the quic tile. */ 101 0 : fd_quic_trace_target_fseq = malloc( quic_tile->in_cnt * sizeof(ulong) ); 102 0 : for( ulong i=0UL; i<quic_tile->in_cnt; i++ ) { 103 0 : fd_quic_trace_target_fseq[ i ] = quic_tile->in_link_fseq[ i ]; 104 0 : } 105 : 106 : /* Locate log buffer */ 107 : 108 0 : void * log = (void *)( (ulong)quic + quic->layout.log_off ); 109 0 : fd_quic_log_rx_t log_rx[1]; 110 0 : FD_LOG_DEBUG(( "Joining quic_log" )); 111 0 : if( FD_UNLIKELY( !fd_quic_log_rx_join( log_rx, log ) ) ) { 112 0 : FD_LOG_ERR(( "fd_quic_log_rx_join failed" )); 113 0 : } 114 0 : fd_quic_trace_log_base = log_rx->base; 115 : 116 : /* Redirect metadata writes to dummy buffers. 117 : Without this hack, stem_run would attempt to write metadata updates 118 : into the target topology which is read-only. */ 119 : 120 : /* ... redirect metric updates */ 121 0 : ulong * metrics = aligned_alloc( FD_METRICS_ALIGN, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) ); 122 0 : if( !metrics ) FD_LOG_ERR(( "out of memory" )); 123 0 : fd_memset( metrics, 0, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) ); 124 0 : fd_metrics_register( metrics ); 125 : 126 0 : fd_quic_trace_link_metrics = fd_metrics_link_in( fd_metrics_base_tl, 0 ); 127 : 128 : /* Join net->quic link consumer */ 129 : 130 0 : FD_LOG_NOTICE(( "quic-trace starting ..." )); 131 0 : switch( args->quic_trace.event ) { 132 0 : case EVENT_STREAM: 133 0 : fd_quic_trace_rx_tile( net_quic->mcache, args->quic_trace.dump ); 134 0 : break; 135 0 : case EVENT_ERROR: 136 0 : fd_quic_trace_log_tile( log_rx->mcache ); 137 0 : break; 138 0 : default: 139 0 : __builtin_unreachable(); 140 0 : } 141 : 142 0 : fd_quic_log_rx_leave( log_rx ); 143 0 : }