LCOV - code coverage report
Current view: top level - app/shared_dev/commands/pktgen - pktgen.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 209 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include "../../../shared/commands/configure/configure.h" /* CONFIGURE_CMD_INIT */
       2             : #include "../../../shared/commands/run/run.h" /* fdctl_check_configure */
       3             : #include "../../../../disco/net/fd_net_tile.h"
       4             : #include "../../../../disco/metrics/fd_metrics.h"
       5             : #include "../../../../disco/topo/fd_topob.h"
       6             : #include "../../../../disco/topo/fd_cpu_topo.h"
       7             : #include "../../../../util/net/fd_ip4.h"
       8             : #include "../../../../util/tile/fd_tile_private.h" /* fd_tile_private_cpus_parse */
       9             : 
      10             : #include <stdio.h> /* printf */
      11             : #include <unistd.h> /* isatty */
      12             : #include <sys/ioctl.h>
      13             : #include <poll.h>
      14             : 
      15             : ulong
      16             : fdctl_obj_align( fd_topo_t const *     topo,
      17             :                  fd_topo_obj_t const * obj );
      18             : 
      19             : ulong
      20             : fdctl_obj_footprint( fd_topo_t const *     topo,
      21             :                      fd_topo_obj_t const * obj );
      22             : 
      23             : ulong
      24             : fdctl_obj_loose( fd_topo_t const *     topo,
      25             :                  fd_topo_obj_t const * obj );
      26             : 
      27             : fd_topo_run_tile_t
      28             : fdctl_tile_run( fd_topo_tile_t const * tile );
      29             : 
      30             : static void
      31           0 : pktgen_topo( config_t * config ) {
      32           0 :   char const * affinity = config->development.pktgen.affinity;
      33           0 :   int is_auto_affinity = !strcmp( affinity, "auto" );
      34             : 
      35           0 :   ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
      36           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
      37             : 
      38           0 :   fd_topo_cpus_t cpus[1];
      39           0 :   fd_topo_cpus_init( cpus );
      40             : 
      41           0 :   ulong affinity_tile_cnt = 0UL;
      42           0 :   if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_tile_private_cpus_parse( affinity, parsed_tile_to_cpu );
      43             : 
      44           0 :   ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
      45           0 :   for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
      46           0 :     if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=cpus->cpu_cnt ) )
      47           0 :       FD_LOG_ERR(( "The CPU affinity string in the configuration file under [development.pktgen.affinity] specifies a CPU index of %hu, but the system "
      48           0 :                    "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
      49           0 :                    "in the system.",
      50           0 :                    parsed_tile_to_cpu[ i ], cpus->cpu_cnt ));
      51           0 :     tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
      52           0 :   }
      53           0 :   if( FD_LIKELY( !is_auto_affinity ) ) {
      54           0 :     if( FD_UNLIKELY( affinity_tile_cnt!=4UL ) )
      55           0 :       FD_LOG_ERR(( "Invalid [development.pktgen.affinity]: must include exactly three CPUs" ));
      56           0 :   }
      57             : 
      58             :   /* Reset topology from scratch */
      59           0 :   fd_topo_t * topo = &config->topo;
      60           0 :   fd_topob_new( &config->topo, config->name );
      61           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
      62             : 
      63           0 :   fd_topob_wksp( topo, "metric" );
      64           0 :   fd_topob_wksp( topo, "metric_in" );
      65           0 :   fd_topos_net_tiles( topo, config->layout.net_tile_count, config->tiles.netlink.max_routes, config->tiles.netlink.max_neighbors, config->development.net.provider, config->tiles.net.interface, config->tiles.net.flush_timeout_micros,
      66           0 :                       config->tiles.net.xdp_rx_queue_size, config->tiles.net.xdp_tx_queue_size, config->tiles.net.xdp_zero_copy, config->tiles.net.xdp_mode, tile_to_cpu );
      67           0 :   fd_topob_tile( topo, "metric",  "metric", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
      68             : 
      69           0 :   fd_topob_wksp( topo, "pktgen" );
      70           0 :   fd_topo_tile_t * pktgen_tile = fd_topob_tile( topo, "pktgen", "pktgen", "pktgen", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
      71           0 :   if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->development.pktgen.fake_dst_ip, &pktgen_tile->pktgen.fake_dst_ip ) ) ) {
      72           0 :     FD_LOG_ERR(( "Invalid [development.pktgen.fake_dst_ip]" ));
      73           0 :   }
      74           0 :   fd_topob_link( topo, "pktgen_out", "pktgen", 2048UL, FD_NET_MTU, 1UL );
      75           0 :   fd_topob_tile_out( topo, "pktgen", 0UL, "pktgen_out", 0UL );
      76           0 :   fd_topob_tile_in( topo, "net", 0UL, "metric_in", "pktgen_out", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
      77             : 
      78             :   /* Create dummy RX link */
      79           0 :   fd_topos_net_rx_link( topo, "net_quic", 0UL, config->tiles.net.send_buffer_size );
      80           0 :   fd_topob_tile_out( topo, "net", 0UL, "net_quic", 0UL );
      81           0 :   fd_topob_tile_in( topo, "pktgen", 0UL, "metric_in", "net_quic", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
      82             : 
      83           0 :   fd_topos_net_tile_finish( topo, 0UL );
      84           0 :   if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo );
      85           0 :   topo->agave_affinity_cnt = 0;
      86           0 :   fd_topob_finish( topo, fdctl_obj_align, fdctl_obj_footprint, fdctl_obj_loose );
      87           0 :   fd_topo_print_log( /* stdout */ 1, topo );
      88           0 : }
      89             : 
      90             : void
      91             : pktgen_cmd_args( int *    pargc,
      92             :                  char *** pargv,
      93           0 :                  args_t * args ) {
      94             :   /* FIXME add config options here */
      95           0 :   (void)pargc; (void)pargv; (void)args;
      96           0 : }
      97             : 
      98             : /* Hacky: Since the pktgen runs in the same process, use globals to
      99             :    share state */
     100             : extern uint fd_pktgen_active;
     101             : 
     102             : /* render_status prints statistics at the top of the screen.
     103             :    Should be called at a low rate (~500ms). */
     104             : 
     105             : static void
     106           0 : render_status( ulong volatile const * net_metrics ) {
     107           0 :   fputs( "\0337"      /* save cursor position */
     108           0 :          "\033[H"     /* move cursor to (0,0) */
     109           0 :          "\033[2K\n", /* create an empty line to avoid spamming look back buffer */
     110           0 :          stdout );
     111           0 :   printf( "\033[2K" "[Firedancer pktgen] mode=%s\n",
     112           0 :           FD_VOLATILE_CONST( fd_pktgen_active ) ? "send+recv" : "recv" );
     113             : 
     114             :   /* Render packet per second rates */
     115           0 :   static long   ts_last       = -1L;
     116           0 :   static ulong  cum_idle_last = 0UL;
     117           0 :   static ulong  cum_tick_last = 0UL;
     118           0 :   static ulong  rx_ok_last    = 0UL;
     119           0 :   static ulong  rx_byte_last  = 0UL;
     120           0 :   static ulong  rx_drop_last  = 0UL;
     121           0 :   static ulong  tx_ok_last    = 0UL;
     122           0 :   static ulong  tx_byte_last  = 0UL;
     123             : 
     124           0 :   static double busy_r       = 0.0;
     125           0 :   static double rx_ok_pps    = 0.0;
     126           0 :   static double rx_bps       = 0.0;
     127           0 :   static double rx_drop_pps  = 0.0;
     128           0 :   static double tx_ok_pps    = 0.0;
     129           0 :   static double tx_bps       = 0.0;
     130             : 
     131           0 :   if( FD_UNLIKELY( ts_last==-1 ) ) ts_last = fd_log_wallclock();
     132           0 :   long now = fd_log_wallclock();
     133           0 :   long dt  = now-ts_last;
     134           0 :   if( dt>(long)10e6 ) {
     135           0 :     ulong cum_idle_now  = net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG  ) ];
     136           0 :     ulong cum_tick_now  = cum_idle_now;
     137           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_HOUSEKEEPING    ) ];
     138           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_PROCESSING_HOUSEKEEPING   ) ];
     139           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_HOUSEKEEPING ) ];
     140           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_PREFRAG         ) ];
     141           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_PROCESSING_PREFRAG        ) ];
     142           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG      ) ];
     143           0 :     /* */ cum_tick_now += net_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_PROCESSING_POSTFRAG       ) ];
     144           0 :     ulong rx_ok_now     = net_metrics[ MIDX( COUNTER, NET, RX_PKT_CNT           ) ];
     145           0 :     ulong rx_byte_now   = net_metrics[ MIDX( COUNTER, NET, RX_BYTES_TOTAL       ) ];
     146           0 :     ulong rx_drop_now   = net_metrics[ MIDX( COUNTER, NET, RX_FILL_BLOCKED_CNT  ) ];
     147           0 :     /* */ rx_drop_now  += net_metrics[ MIDX( COUNTER, NET, RX_BACKPRESSURE_CNT  ) ];
     148           0 :     /* */ rx_drop_now  += net_metrics[ MIDX( COUNTER, NET, XDP_RX_DROPPED_OTHER ) ];
     149           0 :     /* */ rx_drop_now  += net_metrics[ MIDX( COUNTER, NET, XDP_RX_INVALID_DESCS ) ];
     150           0 :     /* */ rx_drop_now  += net_metrics[ MIDX( COUNTER, NET, XDP_RX_RING_FULL     ) ];
     151           0 :     ulong tx_ok_now     = net_metrics[ MIDX( COUNTER, NET, TX_COMPLETE_CNT      ) ];
     152           0 :     ulong tx_byte_now   = net_metrics[ MIDX( COUNTER, NET, TX_BYTES_TOTAL       ) ];
     153             : 
     154           0 :     ulong cum_idle_delta = cum_idle_now-cum_idle_last;
     155           0 :     ulong cum_tick_delta = cum_tick_now-cum_tick_last;
     156           0 :     ulong rx_ok_delta    = rx_ok_now   -rx_ok_last;
     157           0 :     ulong rx_byte_delta  = rx_byte_now -rx_byte_last;
     158           0 :     ulong rx_drop_delta  = rx_drop_now -rx_drop_last;
     159           0 :     ulong tx_ok_delta    = tx_ok_now   -tx_ok_last;
     160           0 :     ulong tx_byte_delta  = tx_byte_now -tx_byte_last;
     161             : 
     162           0 :     busy_r               = 1.0 - ( (double)cum_idle_delta / (double)cum_tick_delta );
     163           0 :     rx_ok_pps            = 1e9*( (double)rx_ok_delta  /(double)dt );
     164           0 :     rx_bps               = 8e9*( (double)rx_byte_delta/(double)dt );
     165           0 :     rx_drop_pps          = 1e9*( (double)rx_drop_delta/(double)dt );
     166           0 :     tx_ok_pps            = 1e9*( (double)tx_ok_delta  /(double)dt );
     167           0 :     tx_bps               = 8e9*( (double)tx_byte_delta/(double)dt );
     168             : 
     169           0 :     ts_last              = now;
     170           0 :     cum_idle_last        = cum_idle_now;
     171           0 :     cum_tick_last        = cum_tick_now;
     172           0 :     rx_ok_last           = rx_ok_now;
     173           0 :     rx_byte_last         = rx_byte_now;
     174           0 :     rx_drop_last         = rx_drop_now;
     175           0 :     tx_ok_last           = tx_ok_now;
     176           0 :     tx_byte_last         = tx_byte_now;
     177           0 :   }
     178             : 
     179           0 :   ulong rx_idle = net_metrics[ MIDX( GAUGE, NET, RX_IDLE_CNT ) ];
     180           0 :   ulong rx_busy = net_metrics[ MIDX( GAUGE, NET, RX_BUSY_CNT ) ];
     181           0 :   ulong tx_idle = net_metrics[ MIDX( GAUGE, NET, TX_IDLE_CNT ) ];
     182           0 :   ulong tx_busy = net_metrics[ MIDX( GAUGE, NET, TX_BUSY_CNT ) ];
     183           0 :   printf( "\033[2K" "  Net busy: %.2f%%\n"
     184           0 :           "\033[2K" "  RX ok:   %10.3e pps %10.3e bps\n"
     185           0 :           "\033[2K" "  RX drop: %10.3e pps\n"
     186           0 :           "\033[2K" "  TX ok:   %10.3e pps %10.3e bps\n"
     187           0 :           "\033[2K" "  RX bufs: %6lu idle %6lu busy\n"
     188           0 :           "\033[2K" "  TX bufs: %6lu idle %6lu busy\n",
     189           0 :           100.*busy_r,
     190           0 :           rx_ok_pps,   rx_bps,
     191           0 :           rx_drop_pps,
     192           0 :           tx_ok_pps,   tx_bps,
     193           0 :           rx_idle,     rx_busy,
     194           0 :           tx_idle,     tx_busy );
     195             : 
     196           0 :   fputs( "\0338", stdout ); /* restore cursor position */
     197           0 :   fflush( stdout );
     198           0 : }
     199             : 
     200             : /* FIXME fixup screen on window size changes */
     201             : 
     202             : void
     203             : pktgen_cmd_fn( args_t *   args FD_PARAM_UNUSED,
     204           0 :                config_t * config ) {
     205           0 :   pktgen_topo( config );
     206           0 :   fd_topo_t *      topo        = &config->topo;
     207           0 :   fd_topo_tile_t * net_tile    = &topo->tiles[ fd_topo_find_tile( topo, "net",    0UL ) ];
     208           0 :   fd_topo_tile_t * metric_tile = &topo->tiles[ fd_topo_find_tile( topo, "metric", 0UL ) ];
     209             : 
     210           0 :   ushort const listen_port = 9000;
     211           0 :   net_tile->net.legacy_transaction_listen_port = listen_port;
     212             : 
     213           0 :   if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &metric_tile->metric.prometheus_listen_addr ) ) )
     214           0 :     FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
     215           0 :   metric_tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
     216             : 
     217           0 :   configure_stage( &fd_cfg_stage_sysctl,           CONFIGURE_CMD_INIT, config );
     218           0 :   configure_stage( &fd_cfg_stage_hugetlbfs,        CONFIGURE_CMD_INIT, config );
     219           0 :   configure_stage( &fd_cfg_stage_ethtool_channels, CONFIGURE_CMD_INIT, config );
     220           0 :   configure_stage( &fd_cfg_stage_ethtool_gro,      CONFIGURE_CMD_INIT, config );
     221             : 
     222           0 :   fdctl_check_configure( config );
     223             :   /* FIXME this allocates lots of memory unnecessarily */
     224           0 :   initialize_workspaces( config );
     225           0 :   initialize_stacks( config );
     226           0 :   fdctl_setup_netns( config, 1 );
     227           0 :   (void)fd_topo_install_xdp( topo );
     228           0 :   fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_WRITE );
     229             : 
     230             :   /* FIXME allow running sandboxed/multiprocess */
     231           0 :   fd_topo_run_single_process( topo, 2, config->uid, config->gid, fdctl_tile_run, NULL );
     232             : 
     233           0 :   ulong volatile const * net_metrics = fd_metrics_tile( net_tile->metrics );
     234             : 
     235             :   /* Don't attempt to render TTY */
     236           0 :   if( !isatty( STDOUT_FILENO ) ) {
     237           0 :     puts( "stdout is not a tty, not taking commands" );
     238           0 :     FD_VOLATILE( fd_pktgen_active ) = 1;
     239           0 :     for(;;) pause();
     240           0 :     return;
     241           0 :   }
     242             : 
     243             :   /* Clear screen */
     244           0 :   struct winsize w;
     245           0 :   if( FD_UNLIKELY( 0!=ioctl( STDOUT_FILENO, TIOCGWINSZ, &w ) ) ) {
     246           0 :     FD_LOG_WARNING(( "ioctl(STDOUT_FILENO,TIOCGWINSZ) failed" ));
     247           0 :   } else {
     248           0 :     for( ulong i=0UL; i<w.ws_row; i++ ) putc( '\n', stdout );
     249           0 :   }
     250             : 
     251             :   /* Simple REPL loop */
     252           0 :   puts( "Running fddev pktgen" );
     253           0 :   printf( "XDP socket listening on port %u\n", (uint)listen_port );
     254           0 :   puts( "Available commands: start, stop, quit" );
     255           0 :   puts( "" );
     256           0 :   char input[ 256 ] = {0};
     257           0 :   for(;;) {
     258           0 :     render_status( net_metrics );
     259           0 :     fputs( "pktgen> ", stdout );
     260           0 :     fflush( stdout );
     261             : 
     262           0 :     for(;;) {
     263           0 :       struct pollfd fds[1] = {{ .fd=STDIN_FILENO, .events=POLLIN }};
     264           0 :       int poll_res = poll( fds, 1, 500 );
     265           0 :       if( poll_res==0 ) {
     266           0 :         render_status( net_metrics );
     267           0 :         continue;
     268           0 :       } else if( poll_res>0 ) {
     269           0 :         break;
     270           0 :       } else {
     271           0 :         FD_LOG_ERR(( "poll(STDIN_FILENO) failed" ));
     272           0 :         break;
     273           0 :       }
     274           0 :     }
     275             : 
     276           0 :     if( fgets( input, sizeof(input), stdin )==NULL ) {
     277           0 :       putc( '\n', stdout );
     278           0 :       break;
     279           0 :     }
     280           0 :     input[ strcspn( input, "\n" ) ] = '\0';
     281           0 :     input[ sizeof(input)-1        ] = '\0';
     282             : 
     283           0 :     if( !input[0] ) {
     284             :       /* No command */
     285           0 :     } else if( !strcmp( input, "exit" ) || !strcmp( input, "quit" ) ) {
     286           0 :       break;
     287           0 :     } else if( !strcmp( input, "start" ) ) {
     288           0 :       FD_VOLATILE( fd_pktgen_active ) = 1U;
     289           0 :     } else if( !strcmp( input, "stop" ) ) {
     290           0 :       FD_VOLATILE( fd_pktgen_active ) = 0U;
     291           0 :     } else {
     292           0 :       fputs( "Unknown command\n", stdout );
     293           0 :     }
     294           0 :   }
     295           0 :   puts( "Exiting" );
     296           0 : }

Generated by: LCOV version 1.14