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 * const config ) { 52 0 : (void)args; 53 : 54 0 : fd_topo_t * topo = &config->topo; 55 0 : fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_ONLY ); 56 0 : fd_topo_fill( topo ); 57 : 58 0 : fd_topo_tile_t * quic_tile = NULL; 59 0 : for( ulong tile_idx=0UL; tile_idx < topo->tile_cnt; tile_idx++ ) { 60 0 : if( 0==strcmp( topo->tiles[ tile_idx ].name, "quic" ) ) { 61 0 : quic_tile = &topo->tiles[ tile_idx ]; 62 0 : break; 63 0 : } 64 0 : } 65 0 : if( !quic_tile ) FD_LOG_ERR(( "QUIC tile not found in topology" )); 66 : 67 : /* Ugly: fd_quic_ctx_t uses non-relocatable object addressing. 68 : We need to rebase pointers. foreign_{...} refer to the original 69 : objects in shared memory, local_{...} refer to translated copies. */ 70 : 71 0 : void * quic_tile_base = fd_topo_obj_laddr( topo, quic_tile->tile_obj_id ); 72 0 : fd_quic_ctx_t const * foreign_quic_ctx = quic_tile_base; 73 0 : fd_quic_ctx_t * quic_ctx = &fd_quic_trace_ctx; 74 0 : *quic_ctx = *foreign_quic_ctx; 75 0 : fd_quic_trace_ctx_remote = foreign_quic_ctx; 76 : 77 0 : ulong quic_raddr = (ulong)foreign_quic_ctx->quic; 78 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() ) ); 79 0 : fd_quic_trace_ctx_raddr = ctx_raddr; 80 : 81 0 : FD_LOG_INFO(( "fd_quic_tile state at %p in tile address space", (void *)ctx_raddr )); 82 0 : FD_LOG_INFO(( "fd_quic_tile state at %p in local address space", quic_tile_base )); 83 : 84 0 : quic_ctx->reasm = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->reasm - ctx_raddr ); 85 0 : quic_ctx->stem = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->stem - ctx_raddr ); 86 0 : quic_ctx->quic = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->quic - ctx_raddr ); 87 : 88 0 : fd_topo_link_t * net_quic = &topo->links[ quic_tile->in_link_id[ 0 ] ]; 89 0 : quic_ctx->in_mem = topo->workspaces[ topo->objs[ net_quic->dcache_obj_id ].wksp_id ].wksp; 90 0 : FD_LOG_INFO(( "net->quic link at %p", (void *)quic_ctx->in_mem )); 91 : 92 : /* Join shared memory objects 93 : Mostly nops but verifies object magic numbers to ensure that 94 : derived pointers are correct. */ 95 : 96 0 : FD_LOG_INFO(( "Joining fd_quic" )); 97 0 : fd_quic_t * quic = fd_quic_join( quic_ctx->quic ); 98 0 : if( !quic ) FD_LOG_ERR(( "Failed to join fd_quic" )); 99 : 100 : /* Locate original fseq objects 101 : These are monitored to ensure the trace RX tile doesn't skip ahead 102 : of the quic tile. */ 103 0 : fd_quic_trace_target_fseq = malloc( quic_tile->in_cnt * sizeof(ulong) ); 104 0 : for( ulong i=0UL; i<quic_tile->in_cnt; i++ ) { 105 0 : fd_quic_trace_target_fseq[ i ] = quic_tile->in_link_fseq[ i ]; 106 0 : } 107 : 108 : /* Locate log buffer */ 109 : 110 0 : void * log = (void *)( (ulong)quic + quic->layout.log_off ); 111 0 : fd_quic_log_rx_t log_rx[1]; 112 0 : FD_LOG_DEBUG(( "Joining quic_log" )); 113 0 : if( FD_UNLIKELY( !fd_quic_log_rx_join( log_rx, log ) ) ) { 114 0 : FD_LOG_ERR(( "fd_quic_log_rx_join failed" )); 115 0 : } 116 0 : fd_quic_trace_log_base = log_rx->base; 117 : 118 : /* Redirect metadata writes to dummy buffers. 119 : Without this hack, stem_run would attempt to write metadata updates 120 : into the target topology which is read-only. */ 121 : 122 : /* ... redirect metric updates */ 123 0 : ulong * metrics = aligned_alloc( FD_METRICS_ALIGN, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) ); 124 0 : if( !metrics ) FD_LOG_ERR(( "out of memory" )); 125 0 : fd_memset( metrics, 0, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) ); 126 0 : fd_metrics_register( metrics ); 127 : 128 0 : fd_quic_trace_link_metrics = fd_metrics_link_in( fd_metrics_base_tl, 0 ); 129 : 130 : /* Join net->quic link consumer */ 131 : 132 0 : FD_LOG_NOTICE(( "quic-trace starting ..." )); 133 0 : switch( args->quic_trace.event ) { 134 0 : case EVENT_STREAM: 135 0 : fd_quic_trace_rx_tile( net_quic->mcache, args->quic_trace.dump ); 136 0 : break; 137 0 : case EVENT_ERROR: 138 0 : fd_quic_trace_log_tile( log_rx->mcache ); 139 0 : break; 140 0 : default: 141 0 : __builtin_unreachable(); 142 0 : } 143 : 144 0 : fd_quic_log_rx_leave( log_rx ); 145 0 : }