LCOV - code coverage report
Current view: top level - app/shared_dev/commands/quic_trace - fd_quic_trace_main.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 259 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 8 0.0 %

          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             : 
      18             : #include "../../../shared/fd_config.h"
      19             : #include "../../../../disco/metrics/fd_metrics.h"
      20             : #include "../../../../disco/quic/fd_quic_tile.h"
      21             : #include "../../../../waltz/quic/log/fd_quic_log_user.h"
      22             : #include "../../../../ballet/hex/fd_hex.h"
      23             : #include <stdlib.h>
      24             : 
      25             : /* Define global variables */
      26             : 
      27             : fd_quic_ctx_t         fd_quic_trace_ctx;
      28             : fd_quic_ctx_t const * fd_quic_trace_ctx_remote;
      29             : ulong                 fd_quic_trace_ctx_raddr;
      30             : ulong **              fd_quic_trace_target_fseq;
      31             : ulong volatile *      fd_quic_trace_link_metrics;
      32             : void const *          fd_quic_trace_log_base;
      33             : peer_conn_id_map_t    _fd_quic_trace_peer_map[1UL<<PEER_MAP_LG_SLOT_CNT];
      34             : peer_conn_id_map_t *  fd_quic_trace_peer_map;
      35             : 
      36           0 : #define EVENT_STREAM 0
      37           0 : #define EVENT_ERROR  1
      38             : 
      39             : void
      40             : quic_trace_cmd_args( int *    pargc,
      41             :                      char *** pargv,
      42           0 :                      args_t * args ) {
      43           0 :   char const * event = fd_env_strip_cmdline_cstr( pargc, pargv, "--event", NULL, "stream" );
      44           0 :   if( 0==strcmp( event, "stream" ) ) {
      45           0 :     args->quic_trace.event = EVENT_STREAM;
      46           0 :   } else if( 0==strcmp( event, "error" ) ) {
      47           0 :     args->quic_trace.event = EVENT_ERROR;
      48           0 :   } else {
      49           0 :     FD_LOG_ERR(( "Unsupported QUIC event type \"%s\"", event ));
      50           0 :   }
      51             : 
      52           0 :   args->quic_trace.dump        = fd_env_strip_cmdline_contains( pargc, pargv, "--dump" );
      53           0 :   args->quic_trace.dump_config = fd_env_strip_cmdline_contains( pargc, pargv, "--dump-config" );
      54           0 :   args->quic_trace.dump_conns  = fd_env_strip_cmdline_contains( pargc, pargv, "--dump-conns" );
      55           0 : }
      56             : 
      57             : static char const *
      58           0 : dump_val_enum_role( int role ) {
      59           0 :   switch( role ) {
      60           0 :     case FD_QUIC_ROLE_CLIENT:
      61           0 :       return "ROLE_CLIENT";
      62           0 :     case FD_QUIC_ROLE_SERVER:
      63           0 :       return "ROLE_SERVER";
      64           0 :     default:
      65           0 :       return "ROLE_UNKNOWN";
      66           0 :   }
      67           0 : }
      68             : 
      69             : static char const *
      70           0 : dump_val_bool( int value ) {
      71           0 :   switch( value ) {
      72           0 :     case 0:  return "false";
      73           0 :     case 1:  return "true";
      74           0 :     default: return "invalid"; /* in case something is assuming a config is in {0,1} */
      75           0 :   }
      76           0 : }
      77             : 
      78             : void
      79           0 : dump_quic_config( fd_quic_config_t * config ) {
      80           0 :   switch( config->role ) {
      81           0 :     case FD_QUIC_ROLE_CLIENT:
      82           0 :       FD_LOG_NOTICE(( "CONFIG: role: %d FD_QUIC_ROLE_CLIENT", config->role ));
      83           0 :       break;
      84           0 :     case FD_QUIC_ROLE_SERVER:
      85           0 :       FD_LOG_NOTICE(( "CONFIG: role: %d FD_QUIC_ROLE_SERVER", config->role ));
      86           0 :       break;
      87           0 :     default:
      88           0 :       FD_LOG_NOTICE(( "CONFIG: role: %d UNKNOWN",             config->role ));
      89           0 :   }
      90             : 
      91           0 : #define HEXFMT32 "%02x%02x%02x%02x" "%02x%02x%02x%02x" \
      92           0 :                  "%02x%02x%02x%02x" "%02x%02x%02x%02x" \
      93           0 :                  "%02x%02x%02x%02x" "%02x%02x%02x%02x" \
      94           0 :                  "%02x%02x%02x%02x" "%02x%02x%02x%02x"
      95           0 : #define HEXARG32(X) (X)[0],  (X)[1],  (X)[2],  (X)[3],  \
      96           0 :                     (X)[4],  (X)[5],  (X)[6],  (X)[7],  \
      97           0 :                     (X)[8],  (X)[9],  (X)[10], (X)[11], \
      98           0 :                     (X)[12], (X)[13], (X)[14], (X)[15], \
      99           0 :                     (X)[16], (X)[17], (X)[18], (X)[19], \
     100           0 :                     (X)[20], (X)[21], (X)[22], (X)[23], \
     101           0 :                     (X)[24], (X)[25], (X)[26], (X)[27], \
     102           0 :                     (X)[28], (X)[29], (X)[30], (X)[31]
     103             : 
     104           0 : #define dump_val_class_enum( NAME, FMT, CLASS, UNIT, VAL ) \
     105           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": " FMT " - %s", config->NAME, dump_val_enum_##NAME( config->NAME ) ));
     106           0 : #define dump_val_class_bool( NAME, FMT, CLASS, UNIT, VAL ) \
     107           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": " FMT " - %s", config->NAME, dump_val_bool( config->NAME ) ));
     108           0 : #define dump_val_class_units( NAME, FMT, CLASS, UNIT, VAL ) \
     109           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": " FMT " %s", config->NAME, UNIT ));
     110           0 : #define dump_val_class_value( NAME, FMT, CLASS, UNIT, VAL ) \
     111           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": " FMT, config->NAME ));
     112           0 : #define dump_val_class_ptr( NAME, FMT, CLASS, UNIT, VAL ) \
     113           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": 0x%lx", (ulong)config->NAME ));
     114           0 : #define dump_val_class_hex32( NAME, FMT, CLASS, UNIT, VAL ) \
     115           0 :   FD_LOG_NOTICE(( "CONFIG: " #NAME ": 0x" HEXFMT32, HEXARG32(config->NAME) ));
     116             : 
     117           0 : #define dump_val( NAME, FMT, CLASS, UNIT, VAL ) \
     118           0 :   dump_val_class_##CLASS( NAME, FMT, CLASS, UNIT, VAL )
     119             : 
     120           0 :   FD_QUIC_CONFIG_LIST( dump_val, x )
     121           0 : }
     122             : 
     123             : static char const *
     124           0 : peer_cid_str( fd_quic_conn_t const * conn ) {
     125           0 :   static char buf[FD_QUIC_MAX_CONN_ID_SZ*2];
     126           0 :   ulong         sz  = conn->peer_cids[0].sz;
     127           0 :   uchar const * cid = conn->peer_cids[0].conn_id;
     128           0 :   sz = fd_ulong_min( sz, FD_QUIC_MAX_CONN_ID_SZ );
     129             : 
     130           0 :   fd_hex_encode( buf, cid, sz );
     131             : 
     132           0 :   return buf;
     133           0 : }
     134             : 
     135             : static void
     136           0 : dump_connection( fd_quic_conn_t const * conn ) {
     137           0 :   (void)conn;
     138             : 
     139           0 : #define CONN_MEMB_LIST(X,CONN,...) \
     140           0 :   X( conn_idx,               "%u",         ( (CONN).conn_idx               ), __VA_ARGS__ ) \
     141           0 :   X( state,                  "%u",         ( (CONN).state                  ), __VA_ARGS__ ) \
     142           0 :   X( reason,                 "%u",         ( (CONN).reason                 ), __VA_ARGS__ ) \
     143           0 :   X( app_reason,             "%u",         ( (CONN).app_reason             ), __VA_ARGS__ ) \
     144           0 :   X( tx_ptr,                 "%p",         ( ((void*)(CONN).tx_ptr)        ), __VA_ARGS__ ) \
     145           0 :   X( unacked_sz,             "%lu",        ( (CONN).unacked_sz             ), __VA_ARGS__ ) \
     146           0 :   X( flags,                  "%x",         ( (CONN).flags                  ), __VA_ARGS__ ) \
     147           0 :   X( conn_gen,               "%u",         ( (CONN).conn_gen               ), __VA_ARGS__ ) \
     148           0 :   X( server,                 "%d",         ( (CONN).server                 ), __VA_ARGS__ ) \
     149           0 :   X( established,            "%d",         ( (CONN).established            ), __VA_ARGS__ ) \
     150           0 :   X( transport_params_set,   "%d",         ( (CONN).transport_params_set   ), __VA_ARGS__ ) \
     151           0 :   X( called_conn_new,        "%d",         ( (CONN).called_conn_new        ), __VA_ARGS__ ) \
     152           0 :   X( visited,                "%d",         ( (CONN).visited                ), __VA_ARGS__ ) \
     153           0 :   X( key_phase,              "%d",         ( (CONN).key_phase              ), __VA_ARGS__ ) \
     154           0 :   X( key_update,             "%d",         ( (CONN).key_update             ), __VA_ARGS__ ) \
     155           0 :   X( our_conn_id,            "%016lx",     ( (CONN).our_conn_id            ), __VA_ARGS__ ) \
     156           0 :   X( peer[0].ip_addr,        "%08x",       ( (uint)(CONN).peer[0].ip_addr  ), __VA_ARGS__ ) \
     157           0 :   X( peer[0].udp_port,       "%u",         ( (uint)(CONN).peer[0].udp_port ), __VA_ARGS__ ) \
     158           0 :   X( handshake_complete,     "%d",         ( (CONN).handshake_complete     ), __VA_ARGS__ ) \
     159           0 :   X( handshake_done_send,    "%d",         ( (CONN).handshake_done_send    ), __VA_ARGS__ ) \
     160           0 :   X( handshake_done_ackd,    "%d",         ( (CONN).handshake_done_ackd    ), __VA_ARGS__ ) \
     161           0 :   X( exp_pkt_number[0],      "%lu",        ( (CONN).exp_pkt_number[0]      ), __VA_ARGS__ ) \
     162           0 :   X( exp_pkt_number[1],      "%lu",        ( (CONN).exp_pkt_number[1]      ), __VA_ARGS__ ) \
     163           0 :   X( exp_pkt_number[2],      "%lu",        ( (CONN).exp_pkt_number[2]      ), __VA_ARGS__ ) \
     164           0 :   X( pkt_number[0],          "%lu",        ( (CONN).pkt_number[0]          ), __VA_ARGS__ ) \
     165           0 :   X( pkt_number[1],          "%lu",        ( (CONN).pkt_number[1]          ), __VA_ARGS__ ) \
     166           0 :   X( pkt_number[2],          "%lu",        ( (CONN).pkt_number[2]          ), __VA_ARGS__ ) \
     167           0 :   X( last_pkt_number[0],     "%lu",        ( (CONN).last_pkt_number[0]     ), __VA_ARGS__ ) \
     168           0 :   X( last_pkt_number[1],     "%lu",        ( (CONN).last_pkt_number[1]     ), __VA_ARGS__ ) \
     169           0 :   X( last_pkt_number[2],     "%lu",        ( (CONN).last_pkt_number[2]     ), __VA_ARGS__ ) \
     170           0 :   X( idle_timeout_ticks,     "%lu",        ( (CONN).idle_timeout_ticks     ), __VA_ARGS__ ) \
     171           0 :   X( last_activity,          "%lu",        ( (CONN).last_activity          ), __VA_ARGS__ ) \
     172           0 :   X( last_ack,               "%lu",        ( (CONN).last_ack               ), __VA_ARGS__ ) \
     173           0 :   X( used_pkt_meta,          "%lu",        ( (CONN).used_pkt_meta          ), __VA_ARGS__ ) \
     174           0 :   X( peer_cid,               "%s",         ( peer_cid_str(&(CONN))         ), __VA_ARGS__ )
     175             : 
     176           0 : #define UNPACK(...) __VA_ARGS__
     177           0 : #define CONN_MEMB_FMT(NAME,FMT,ARGS,...)  " " #NAME "=" FMT
     178           0 : #define CONN_MEMB_ARGS(NAME,FMT,ARGS,...) , UNPACK ARGS
     179           0 :   FD_LOG_NOTICE(( "CONN: "
     180           0 :         CONN_MEMB_LIST(CONN_MEMB_FMT,*conn,_)
     181           0 :         CONN_MEMB_LIST(CONN_MEMB_ARGS,*conn,_)
     182           0 :         ));
     183           0 : }
     184             : 
     185             : static fd_quic_conn_t const *
     186           0 : fd_quic_trace_conn_at_idx( fd_quic_t const * quic, ulong idx, ulong quic_raddr ) {
     187           0 :   fd_quic_state_t const * state = fd_quic_get_state_const( quic );
     188           0 :   ulong const conn_base_off = state->conn_base - quic_raddr;
     189           0 :   ulong const local_conn_base = (ulong)quic + conn_base_off;
     190           0 :   return (fd_quic_conn_t *)( local_conn_base + idx * state->conn_sz );
     191           0 : }
     192             : 
     193             : void
     194             : quic_trace_cmd_fn( args_t *   args,
     195           0 :                    config_t * config ) {
     196           0 :   fd_topo_t * topo = &config->topo;
     197           0 :   fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_ONLY );
     198           0 :   fd_topo_fill( topo );
     199             : 
     200           0 :   fd_topo_tile_t * quic_tile = NULL;
     201           0 :   for( ulong tile_idx=0UL; tile_idx < topo->tile_cnt; tile_idx++ ) {
     202           0 :     if( 0==strcmp( topo->tiles[ tile_idx ].name, "quic" ) ) {
     203           0 :       quic_tile = &topo->tiles[ tile_idx ];
     204           0 :       break;
     205           0 :     }
     206           0 :   }
     207           0 :   if( !quic_tile ) FD_LOG_ERR(( "QUIC tile not found in topology" ));
     208           0 :   if( FD_UNLIKELY( quic_tile->in_cnt!=1UL ) ) { /* FIXME */
     209           0 :     FD_LOG_ERR(( "Sorry, fd_quic_trace does not support multiple net tiles yet" ));
     210           0 :   }
     211             : 
     212             :   /* Ugly: fd_quic_ctx_t uses non-relocatable object addressing.
     213             :      We need to rebase pointers.  foreign_{...} refer to the original
     214             :      objects in shared memory, local_{...} refer to translated copies. */
     215             : 
     216           0 :   void *                quic_tile_base   = fd_topo_obj_laddr( topo, quic_tile->tile_obj_id );
     217           0 :   fd_quic_ctx_t const * foreign_quic_ctx = quic_tile_base;
     218           0 :   fd_quic_ctx_t * quic_ctx = &fd_quic_trace_ctx;
     219           0 :   *quic_ctx                = *foreign_quic_ctx;
     220           0 :   fd_quic_trace_ctx_remote =  foreign_quic_ctx;
     221             : 
     222           0 :   ulong quic_raddr = (ulong)foreign_quic_ctx->quic;
     223           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() ) );
     224           0 :   fd_quic_trace_ctx_raddr = ctx_raddr;
     225             : 
     226           0 :   FD_LOG_INFO(( "fd_quic_tile state at %p in tile address space", (void *)ctx_raddr ));
     227           0 :   FD_LOG_INFO(( "fd_quic_tile state at %p in local address space", quic_tile_base ));
     228             : 
     229           0 :   quic_ctx->reasm = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->reasm - ctx_raddr );
     230           0 :   quic_ctx->stem  = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->stem  - ctx_raddr );
     231           0 :   quic_ctx->quic  = (void *)( (ulong)quic_tile_base + (ulong)quic_ctx->quic  - ctx_raddr );
     232             : 
     233             :   /* find quic_net in topology */
     234           0 :   ulong link_id = fd_topo_find_link( topo, "quic_net", 0 );
     235             : 
     236           0 :   if( link_id == ULONG_MAX ) {
     237           0 :     FD_LOG_ERR(( "quic_net not found" ));
     238           0 :   }
     239           0 :   fd_topo_link_t * quic_net = &topo->links[ link_id ];
     240             : 
     241           0 :   fd_quic_trace_ctx_t trace_ctx[1] =
     242           0 :                         {{ .dump        = args->quic_trace.dump,
     243           0 :                            .dump_config = args->quic_trace.dump_config,
     244           0 :                            .dump_conns  = args->quic_trace.dump_conns }};
     245           0 :   fd_wksp_t * quic_net_wksp = fd_wksp_containing( quic_net->dcache );
     246             : 
     247             :   /* quic_net_wksp is the base address for locating chunks */
     248           0 :   trace_ctx->net_out_base = (ulong)quic_net_wksp;
     249           0 :   trace_ctx->net_out      = 1;
     250             : 
     251           0 :   fd_topo_link_t * net_quic = &topo->links[ quic_tile->in_link_id[ 0 ] ];
     252           0 :   fd_net_rx_bounds_init( &quic_ctx->net_in_bounds[ 0 ], net_quic->dcache );
     253           0 :   FD_LOG_INFO(( "net->quic dcache at %p", (void *)net_quic->dcache ));
     254             : 
     255             :   /* Join shared memory objects
     256             :      Mostly nops but verifies object magic numbers to ensure that
     257             :      derived pointers are correct. */
     258             : 
     259           0 :   FD_LOG_INFO(( "Joining fd_quic" ));
     260           0 :   fd_quic_t * quic = fd_quic_join( quic_ctx->quic );
     261           0 :   if( !quic ) FD_LOG_ERR(( "Failed to join fd_quic" ));
     262             : 
     263             :   /* dump config */
     264           0 :   if( trace_ctx->dump_config ) {
     265           0 :     dump_quic_config( &quic->config );
     266           0 :   }
     267             : 
     268             :   /* initialize peer conn_id map */
     269           0 :   void *               shmap    = peer_conn_id_map_new( _fd_quic_trace_peer_map );
     270           0 :   peer_conn_id_map_t * peer_map = peer_conn_id_map_join( shmap );
     271             : 
     272             :   /* set the global */
     273           0 :   fd_quic_trace_peer_map = peer_map;
     274             : 
     275             :   /* iterate connections - dump and/or insert */
     276             : 
     277           0 : #define CONN_STATE_LIST(X,SEP,...) \
     278           0 :   X( INVALID            , __VA_ARGS__ ) SEP \
     279           0 :   X( HANDSHAKE          , __VA_ARGS__ ) SEP \
     280           0 :   X( HANDSHAKE_COMPLETE , __VA_ARGS__ ) SEP \
     281           0 :   X( ACTIVE             , __VA_ARGS__ ) SEP \
     282           0 :   X( PEER_CLOSE         , __VA_ARGS__ ) SEP \
     283           0 :   X( ABORT              , __VA_ARGS__ ) SEP \
     284           0 :   X( CLOSE_PENDING      , __VA_ARGS__ ) SEP \
     285           0 :   X( DEAD               , __VA_ARGS__ )
     286             : 
     287           0 :   ulong conn_cnt      = quic->limits.conn_cnt;
     288           0 :   ulong state_unknown = 0;
     289           0 : #define COMMA ,
     290           0 : #define _(X,Y) [FD_QUIC_CONN_STATE_##X] = 0
     291           0 :   ulong state_cnt[] = { CONN_STATE_LIST(_,COMMA,Y) };
     292           0 :   ulong state_cap = sizeof( state_cnt) / sizeof( state_cnt[0] );
     293           0 : #undef _
     294             : 
     295           0 :   for( ulong j = 0; j < conn_cnt; ++j ) {
     296           0 :     fd_quic_conn_t const * conn = fd_quic_trace_conn_at_idx( quic, j, quic_raddr );
     297           0 :     ulong state = conn->state;
     298           0 :     ulong *state_bucket = state < state_cap ? &state_cnt[state] : &state_unknown;
     299             : 
     300           0 :     (*state_bucket)++;
     301             : 
     302           0 :     switch( conn->state ) {
     303           0 :       case FD_QUIC_CONN_STATE_INVALID:
     304             :         /* indicates the connection is free */
     305           0 :         break;
     306           0 :       default:
     307           0 :         if( trace_ctx->dump_conns ) {
     308           0 :           dump_connection( conn );
     309           0 :         }
     310             : 
     311             :         /* add connection to the peer_conn_id_map */
     312             : 
     313             :         /* when we receive a one-rtt quic packet, we don't know the conn_id
     314             :            size, so we assume its longer than 8 bytes, and truncate the rest */
     315           0 :         ulong key;
     316           0 :         memcpy( &key, conn->peer_cids[0].conn_id, sizeof( key ) );
     317           0 :         peer_conn_id_map_t * entry = peer_conn_id_map_insert( peer_map, key );
     318           0 :         if( entry ) {
     319           0 :           entry->conn_idx = (uint)j;
     320           0 :         } else {
     321             :           /* this is a diagnostics tool, so we'll continue here */
     322           0 :           FD_LOG_WARNING(( "Peer connection id map full. Continuing with partial functionality" ));
     323           0 :         }
     324           0 :     }
     325           0 :   }
     326             : 
     327           0 : #define _FMT(X,Y) "%s=%lu"
     328           0 : #define _ARG(X,Y) #X, state_cnt[FD_QUIC_CONN_STATE_##X]
     329           0 :   FD_LOG_NOTICE(( "Total connections: %lu  "
     330           0 :         CONN_STATE_LIST(_FMT,"  ",Y), conn_cnt,
     331           0 :         CONN_STATE_LIST(_ARG,COMMA,Y) ));
     332           0 : #undef _FMT
     333           0 : #undef _ARG
     334             : 
     335             :   /* Locate original fseq objects
     336             :      These are monitored to ensure the trace RX tile doesn't skip ahead
     337             :      of the quic tile. */
     338           0 :   fd_quic_trace_target_fseq = malloc( quic_tile->in_cnt * sizeof(ulong) );
     339           0 :   for( ulong i=0UL; i<quic_tile->in_cnt; i++ ) {
     340           0 :     fd_quic_trace_target_fseq[ i ] = quic_tile->in_link_fseq[ i ];
     341           0 :   }
     342             : 
     343             :   /* Locate log buffer */
     344             : 
     345           0 :   void * log = (void *)( (ulong)quic + quic->layout.log_off );
     346           0 :   fd_quic_log_rx_t log_rx[1];
     347           0 :   FD_LOG_DEBUG(( "Joining quic_log" ));
     348           0 :   if( FD_UNLIKELY( !fd_quic_log_rx_join( log_rx, log ) ) ) {
     349           0 :     FD_LOG_ERR(( "fd_quic_log_rx_join failed" ));
     350           0 :   }
     351           0 :   fd_quic_trace_log_base = log_rx->base;
     352             : 
     353             :   /* Redirect metadata writes to dummy buffers.
     354             :      Without this hack, stem_run would attempt to write metadata updates
     355             :      into the target topology which is read-only. */
     356             : 
     357             :   /* ... redirect metric updates */
     358           0 :   ulong * metrics = aligned_alloc( FD_METRICS_ALIGN, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) );
     359           0 :   if( !metrics ) FD_LOG_ERR(( "out of memory" ));
     360           0 :   fd_memset( metrics, 0, FD_METRICS_FOOTPRINT( quic_tile->in_cnt, quic_tile->out_cnt ) );
     361           0 :   fd_metrics_register( metrics );
     362             : 
     363           0 :   fd_quic_trace_link_metrics = fd_metrics_link_in( fd_metrics_base_tl, 0 );
     364             : 
     365             :   /* Join net->quic link consumer */
     366             : 
     367           0 :   fd_frag_meta_t const * rx_mcache = net_quic->mcache;
     368           0 :   fd_frag_meta_t const * tx_mcache = quic_net->mcache;
     369             : 
     370           0 :   FD_LOG_NOTICE(( "quic-trace starting ..." ));
     371           0 :   switch( args->quic_trace.event ) {
     372           0 :   case EVENT_STREAM:
     373           0 :     fd_quic_trace_rx_tile( trace_ctx, rx_mcache, tx_mcache );
     374           0 :     break;
     375           0 :   case EVENT_ERROR:
     376           0 :     fd_quic_trace_log_tile( log_rx->mcache );
     377           0 :     break;
     378           0 :   default:
     379           0 :     __builtin_unreachable();
     380           0 :   }
     381             : 
     382           0 :   fd_quic_log_rx_leave( log_rx );
     383           0 : }
     384             : 
     385             : action_t fd_action_quic_trace = {
     386             :   .name          = "quic-trace",
     387             :   .args          = quic_trace_cmd_args,
     388             :   .fn            = quic_trace_cmd_fn,
     389             :   .description   = "Trace quic tile",
     390             :   .is_diagnostic = 1
     391             : };

Generated by: LCOV version 1.14