LCOV - code coverage report
Current view: top level - discof/ipecho - fd_ipecho_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 182 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #include "fd_ipecho_client.h"
       2             : #include "fd_ipecho_server.h"
       3             : #include "fd_ipecho_server_port_check.h"
       4             : 
       5             : #include "../genesis/fd_genesi_tile.h"
       6             : #include "../genesis/genesis_hash.h"
       7             : #include "../../disco/topo/fd_topo.h"
       8             : #include "../../disco/topo/fd_dns_resolve.h"
       9             : #include "../../disco/metrics/fd_metrics.h"
      10             : #include "../../disco/waker/fd_waker.h"
      11             : #include "../../disco/fd_clock_tile.h"
      12             : 
      13             : #include <netinet/in.h>
      14             : #include <sys/socket.h>
      15             : #include <time.h> /* CLOCK_REALTIME for seccomp filter */
      16             : #include <poll.h>
      17             : 
      18             : #include <linux/futex.h>
      19             : #include "generated/fd_ipecho_tile_seccomp.h"
      20             : 
      21           0 : #define FD_IPECHO_MAX_CONNECTION_CNT (1024UL)
      22             : 
      23             : struct fd_ipecho_tile_ctx {
      24             :   int retrieving;
      25             : 
      26             :   fd_ipecho_server_t * server;
      27             :   fd_ipecho_client_t * client;
      28             : 
      29             :   ulong   waker_client_idx;
      30             :   ulong * waker_fseq;
      31             : 
      32             :   fd_clock_tile_t clock[1];
      33             : 
      34             :   uint   bind_address;
      35             :   ushort bind_port;
      36             : 
      37             :   ushort expected_shred_version;
      38             : 
      39             :   fd_ip4_port_t entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ];
      40             :   ulong         entrypoints_cnt;
      41             : 
      42             :   fd_wksp_t * genesi_in_mem;
      43             :   ulong       genesi_in_chunk0;
      44             :   ulong       genesi_in_wmark;
      45             : };
      46             : 
      47             : typedef struct fd_ipecho_tile_ctx fd_ipecho_tile_ctx_t;
      48             : 
      49             : FD_FN_CONST static inline ulong
      50           0 : scratch_align( void ) {
      51           0 :   return alignof( fd_ipecho_tile_ctx_t );
      52           0 : }
      53             : 
      54             : FD_FN_PURE static inline ulong
      55           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
      56           0 :   (void)tile;
      57             : 
      58           0 :   ulong l = FD_LAYOUT_INIT;
      59           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_ipecho_tile_ctx_t), sizeof(fd_ipecho_tile_ctx_t)                               );
      60           0 :   l = FD_LAYOUT_APPEND( l, fd_ipecho_client_align(),      fd_ipecho_client_footprint()                               );
      61           0 :   l = FD_LAYOUT_APPEND( l, fd_ipecho_server_align(),      fd_ipecho_server_footprint( FD_IPECHO_MAX_CONNECTION_CNT ) );
      62           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
      63           0 : }
      64             : 
      65             : static inline void
      66           0 : metrics_write( fd_ipecho_tile_ctx_t * ctx ) {
      67           0 :   fd_ipecho_server_metrics_t * metrics = fd_ipecho_server_metrics( ctx->server );
      68             : 
      69           0 :   FD_MGAUGE_SET( IPECHO, CONN_OPEN,         metrics->connection_cnt           );
      70           0 :   FD_MCNT_SET(   IPECHO, CONN_RX_BYTES,            metrics->bytes_read               );
      71           0 :   FD_MCNT_SET(   IPECHO, CONN_TX_BYTES,            metrics->bytes_written            );
      72           0 :   ulong conn_closed[ FD_METRICS_ENUM_CONN_CLOSE_RESULT_CNT ];
      73           0 :   conn_closed[ FD_METRICS_ENUM_CONN_CLOSE_RESULT_V_ACCEPTED_IDX ] = metrics->connections_closed_ok;
      74           0 :   conn_closed[ FD_METRICS_ENUM_CONN_CLOSE_RESULT_V_ERROR_IDX    ] = metrics->connections_closed_error;
      75           0 :   FD_MCNT_ENUM_COPY( IPECHO, CONN_CLOSED, conn_closed );
      76             : 
      77           0 :   fd_ipecho_server_port_check_metrics_t * pc_metrics = fd_ipecho_server_port_check_metrics(
      78           0 :     fd_ipecho_server_port_check( ctx->server ) );
      79           0 :   FD_MCNT_SET(       IPECHO, PORT_CHECK_UDP_TX,        pc_metrics->udp_sent );
      80           0 :   FD_MCNT_ENUM_COPY( IPECHO, PORT_CHECK_TCP_ATTEMPTED, pc_metrics->tcp      );
      81           0 :   FD_MGAUGE_SET(     IPECHO, PORT_CHECK_TCP_IN_FLIGHT, pc_metrics->active   );
      82           0 : }
      83             : 
      84             : static inline void
      85             : poll_client( fd_ipecho_tile_ctx_t * ctx,
      86             :              fd_stem_context_t *    stem,
      87           0 :              int *                  charge_busy ) {
      88           0 :   if( FD_UNLIKELY( !ctx->client ) ) return;
      89             : 
      90           0 :   ushort shred_version;
      91           0 :   int result = fd_ipecho_client_poll( ctx->client, fd_clock_tile_now( ctx->clock ), &shred_version, charge_busy );
      92           0 :   if( FD_UNLIKELY( !result ) ) {
      93           0 :     if( FD_UNLIKELY( ctx->expected_shred_version && ctx->expected_shred_version!=shred_version ) ) {
      94           0 :       FD_LOG_ERR(( "Expected shred version %hu but entrypoint returned %hu",
      95           0 :                    ctx->expected_shred_version, shred_version ));
      96           0 :     }
      97             : 
      98           0 :     FD_LOG_INFO(( "retrieved shred version %hu from entrypoint", shred_version ));
      99           0 :     FD_MGAUGE_SET( IPECHO, SHRED_VERSION, shred_version );
     100           0 :     fd_stem_publish( stem, 0UL, shred_version, 0UL, 0UL, 0UL, 0UL, 0UL );
     101           0 :     fd_ipecho_server_set_shred_version( ctx->server, shred_version );
     102           0 :     ctx->retrieving = 0;
     103           0 :     return;
     104           0 :   } else if( FD_UNLIKELY( -1==result ) ) {
     105           0 :     FD_LOG_ERR(( "Could not determine shred version from entrypoints.  Please "
     106           0 :                  "check you can connect to the entrypoints provided." ));
     107           0 :   }
     108           0 : }
     109             : 
     110             : static void
     111           0 : during_housekeeping( fd_ipecho_tile_ctx_t * ctx ) {
     112           0 :   if( FD_UNLIKELY( fd_clock_tile_recal_due( ctx->clock ) ) ) fd_clock_tile_recal( ctx->clock );
     113           0 :   fd_ipecho_server_port_check_prune( fd_ipecho_server_port_check( ctx->server ), fd_tickcount() );
     114           0 : }
     115             : 
     116             : static inline long
     117           0 : next_deadline( fd_ipecho_tile_ctx_t * ctx ) {
     118           0 :   if( FD_LIKELY( !ctx->retrieving || !ctx->client ) ) return LONG_MAX;
     119             : 
     120           0 :   long deadline = fd_ipecho_client_deadline_nanos( ctx->client );
     121           0 :   if( FD_UNLIKELY( deadline==LONG_MAX ) ) return 0L; /* first poll starts the clock */
     122           0 :   return fd_clock_tile_wallclock_to_tickcount( ctx->clock, deadline );
     123           0 : }
     124             : 
     125             : static inline void
     126             : after_credit( fd_ipecho_tile_ctx_t * ctx,
     127             :               fd_stem_context_t *    stem,
     128             :               int *                  opt_poll_in,
     129           0 :               int *                  charge_busy ) {
     130           0 :   (void)opt_poll_in;
     131             : 
     132           0 :   if( FD_UNLIKELY( ctx->retrieving ) ) {
     133           0 :     int fired = fd_fseq_query( ctx->waker_fseq )==1UL;
     134           0 :     if( FD_LIKELY( fired ) ) fd_fseq_update( ctx->waker_fseq, 0UL );
     135           0 :     poll_client( ctx, stem, charge_busy );
     136           0 :     if( FD_LIKELY( fired ) ) fd_waker_client_rearm( ctx->waker_client_idx );
     137           0 :     return;
     138           0 :   }
     139             : 
     140           0 :   if( FD_UNLIKELY( fd_fseq_query( ctx->waker_fseq )==1UL ) ) {
     141           0 :     fd_fseq_update( ctx->waker_fseq, 0UL );
     142           0 :     fd_ipecho_server_epoll_poll( ctx->server, fd_tickcount(), charge_busy ); /* one batch; the rearm re-fires leftovers */
     143           0 :     fd_waker_client_rearm( ctx->waker_client_idx );
     144           0 :   } else if( FD_LIKELY( !stem->sleep ) ) {
     145           0 :     fd_log_sleep( (long)1e6 );
     146           0 :   }
     147           0 : }
     148             : 
     149             : static inline int
     150             : returnable_frag( fd_ipecho_tile_ctx_t * ctx,
     151             :                  ulong                  in_idx,
     152             :                  ulong                  seq,
     153             :                  ulong                  sig,
     154             :                  ulong                  chunk,
     155             :                  ulong                  sz,
     156             :                  ulong                  ctl,
     157             :                  ulong                  tsorig,
     158             :                  ulong                  tspub,
     159           0 :                  fd_stem_context_t *    stem ) {
     160           0 :   (void)in_idx; (void)seq; (void)sig; (void)sz; (void)ctl; (void)tspub;
     161           0 :   fd_genesis_meta_t const * genesis_meta = fd_chunk_to_laddr( ctx->genesi_in_mem, chunk );
     162             : 
     163           0 :   if( FD_UNLIKELY( genesis_meta->bootstrap ) ) {
     164           0 :     ushort shred_version = compute_shred_version( genesis_meta->genesis_hash.uc, NULL, 0UL );
     165           0 :     FD_TEST( shred_version );
     166             : 
     167           0 :     FD_MGAUGE_SET( IPECHO, SHRED_VERSION, shred_version );
     168           0 :     fd_stem_publish( stem, 0UL, shred_version, 0UL, 0UL, 0UL, tsorig, fd_frag_meta_ts_comp( fd_tickcount() ) );
     169           0 :     fd_ipecho_server_set_shred_version( ctx->server, shred_version );
     170           0 :     ctx->retrieving = 0;
     171           0 :   }
     172             : 
     173           0 :   return 0;
     174           0 : }
     175             : 
     176             : static void
     177             : privileged_init( fd_topo_t const *      topo,
     178           0 :                  fd_topo_tile_t const * tile ) {
     179           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     180             : 
     181           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     182           0 :   fd_ipecho_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_ipecho_tile_ctx_t ), sizeof( fd_ipecho_tile_ctx_t )                             );
     183           0 :   void * _client             = FD_SCRATCH_ALLOC_APPEND( l, fd_ipecho_client_align(),        fd_ipecho_client_footprint()                               );
     184           0 :   void * _server             = FD_SCRATCH_ALLOC_APPEND( l, fd_ipecho_server_align(),        fd_ipecho_server_footprint( FD_IPECHO_MAX_CONNECTION_CNT ) );
     185             : 
     186           0 :   ctx->bind_address = tile->ipecho.bind_address;
     187           0 :   ctx->bind_port    = tile->ipecho.bind_port;
     188             : 
     189           0 :   ctx->expected_shred_version = tile->ipecho.expected_shred_version;
     190             : 
     191           0 :   ctx->entrypoints_cnt = tile->ipecho.entrypoints_cnt;
     192           0 :   fd_dns_resolve_peers( tile->ipecho.entrypoints[ 0 ], sizeof(tile->ipecho.entrypoints[ 0 ]), tile->ipecho.entrypoints_cnt, "gossip.entrypoints", ctx->entrypoints );
     193             : 
     194           0 :   ctx->retrieving = 1;
     195           0 :   if( FD_LIKELY( ctx->entrypoints_cnt ) ) {
     196           0 :     ctx->client = fd_ipecho_client_join( fd_ipecho_client_new( _client ) );
     197           0 :     FD_TEST( ctx->client );
     198           0 :     fd_ipecho_client_init( ctx->client, ctx->entrypoints, ctx->entrypoints_cnt, FD_WAKER_INNER_FD( tile->waker_client_idx ) );
     199           0 :   } else {
     200           0 :     ctx->client = NULL;
     201           0 :   }
     202             : 
     203           0 :   ctx->server = fd_ipecho_server_join( fd_ipecho_server_new( _server, FD_IPECHO_MAX_CONNECTION_CNT ) );
     204           0 :   FD_TEST( ctx->server );
     205           0 :   ctx->waker_client_idx = tile->waker_client_idx;
     206           0 :   FD_TEST( ctx->waker_client_idx!=ULONG_MAX );
     207           0 :   fd_ipecho_server_init( ctx->server, FD_WAKER_INNER_FD( ctx->waker_client_idx ), ctx->bind_address, ctx->bind_port, ctx->expected_shred_version );
     208             : 
     209           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
     210           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     211           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     212           0 : }
     213             : 
     214             : static void
     215             : unprivileged_init( fd_topo_t const *      topo,
     216           0 :                    fd_topo_tile_t const * tile ) {
     217           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     218             : 
     219           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     220           0 :   fd_ipecho_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_ipecho_tile_ctx_t ), sizeof( fd_ipecho_tile_ctx_t )       );
     221             : 
     222           0 :   FD_MGAUGE_SET( IPECHO, SHRED_VERSION, tile->ipecho.expected_shred_version );
     223             : 
     224           0 :   FD_TEST( ctx->waker_client_idx!=ULONG_MAX );
     225           0 :   ctx->waker_fseq = fd_fseq_join( fd_topo_obj_laddr( topo, tile->waker_fseq_obj_id ) );
     226           0 :   FD_TEST( ctx->waker_fseq );
     227             : 
     228           0 :   fd_clock_tile_init( ctx->clock );
     229             : 
     230             :   /* In some topologies (e.g. firedancer-dev gossip), the ipecho tile
     231             :      has no input links. Guard against dereferencing a missing
     232             :      link/dcache. */
     233           0 :   if( FD_LIKELY( tile->in_cnt>0UL ) ) {
     234           0 :     ulong link_id = tile->in_link_id[ 0UL ];
     235           0 :     void * dcache = topo->links[ link_id ].dcache;
     236           0 :     ctx->genesi_in_mem    = topo->workspaces[ topo->objs[ topo->links[ link_id ].dcache_obj_id ].wksp_id ].wksp;
     237           0 :     ctx->genesi_in_chunk0 = fd_dcache_compact_chunk0( ctx->genesi_in_mem, dcache );
     238           0 :     ctx->genesi_in_wmark  = fd_dcache_compact_wmark ( ctx->genesi_in_mem, dcache, topo->links[ link_id ].mtu );
     239           0 :   } else {
     240           0 :     ctx->genesi_in_mem    = NULL;
     241           0 :     ctx->genesi_in_chunk0 = 0UL;
     242           0 :     ctx->genesi_in_wmark  = 0UL;
     243           0 :   }
     244           0 : }
     245             : 
     246             : static ulong
     247             : rlimit_file_cnt( fd_topo_t const *      topo FD_PARAM_UNUSED,
     248           0 :                  fd_topo_tile_t const * tile ) {
     249             :   /* stderr, logfile, the listen socket, the waker's inner and outer
     250             :      epoll fds, and one spare for new accept() connections */
     251           0 :   ulong base = 6UL;
     252           0 :   return base +
     253           0 :          tile->ipecho.entrypoints_cnt +        /* for the client */
     254           0 :          1UL +                                 /* for the port check's UDP socket */
     255           0 :          FD_IPECHO_MAX_CONNECTION_CNT +        /* for the server's connections */
     256           0 :          FD_IPECHO_SERVER_PORT_CHECK_CONN_MAX; /* for the port check's outgoing TCP connections */
     257           0 : }
     258             : 
     259             : static ulong
     260             : populate_allowed_seccomp( fd_topo_t const *      topo,
     261             :                           fd_topo_tile_t const * tile,
     262             :                           ulong                  out_cnt,
     263           0 :                           struct sock_filter *   out ) {
     264           0 :   void * scratch             = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     265           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     266           0 :   fd_ipecho_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_ipecho_tile_ctx_t), sizeof(fd_ipecho_tile_ctx_t) );
     267             : 
     268           0 :   uint epoll_inner_fd    = (uint)FD_WAKER_INNER_FD( tile->waker_client_idx );
     269           0 :   uint epoll_outer_fd    = (uint)FD_WAKER_OUTER_FD;
     270           0 :   uint port_check_udp_fd = (uint)fd_ipecho_server_port_check_udp_sockfd( fd_ipecho_server_port_check( ctx->server ) );
     271             : 
     272           0 :   populate_sock_filter_policy_fd_ipecho_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), epoll_inner_fd, epoll_outer_fd, port_check_udp_fd );
     273           0 :   return sock_filter_policy_fd_ipecho_tile_instr_cnt;
     274           0 : }
     275             : 
     276             : static ulong
     277             : populate_allowed_fds( fd_topo_t const *      topo,
     278             :                       fd_topo_tile_t const * tile,
     279             :                       ulong                  out_fds_cnt,
     280           0 :                       int *                  out_fds ) {
     281             : 
     282           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     283           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     284           0 :   fd_ipecho_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_ipecho_tile_ctx_t), sizeof(fd_ipecho_tile_ctx_t) );
     285             : 
     286           0 :   if( FD_UNLIKELY( out_fds_cnt<6UL+tile->ipecho.entrypoints_cnt ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     287             : 
     288           0 :   ulong out_cnt = 0UL;
     289           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     290           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     291           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     292             : 
     293             :   /* All of the fds managed by the client. */
     294           0 :   for( ulong i=0UL; i<tile->ipecho.entrypoints_cnt; i++ ) {
     295           0 :     int fd = fd_ipecho_client_get_pollfds( ctx->client )[ i ].fd;
     296           0 :     if( FD_LIKELY( fd!=-1 ) ) out_fds[ out_cnt++ ] = fd;
     297           0 :   }
     298             : 
     299             :   /* The server's listen socket and the port check's UDP socket. */
     300           0 :   out_fds[ out_cnt++ ] = fd_ipecho_server_sockfd( ctx->server );
     301           0 :   out_fds[ out_cnt++ ] = fd_ipecho_server_port_check_udp_sockfd( fd_ipecho_server_port_check( ctx->server ) );
     302             : 
     303           0 :   out_fds[ out_cnt++ ] = FD_WAKER_OUTER_FD;                           /* waker outer epoll fd (rearm) */
     304           0 :   out_fds[ out_cnt++ ] = FD_WAKER_INNER_FD( tile->waker_client_idx ); /* waker inner epoll fd */
     305           0 :   return out_cnt;
     306           0 : }
     307             : 
     308           0 : #define STEM_BURST (2UL)
     309           0 : #define STEM_LAZY  ((long)10e6) /* 10ms */
     310             : 
     311           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_ipecho_tile_ctx_t
     312           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_ipecho_tile_ctx_t)
     313             : 
     314           0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
     315           0 : #define STEM_CALLBACK_NEXT_DEADLINE       next_deadline
     316           0 : #define STEM_CALLBACK_METRICS_WRITE       metrics_write
     317           0 : #define STEM_CALLBACK_AFTER_CREDIT        after_credit
     318           0 : #define STEM_CALLBACK_RETURNABLE_FRAG     returnable_frag
     319             : 
     320             : #include "../../disco/stem/fd_stem.c"
     321             : 
     322             : fd_topo_run_tile_t fd_tile_ipecho = {
     323             :   .name                     = "ipecho",
     324             :   .rlimit_file_cnt_fn       = rlimit_file_cnt,
     325             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     326             :   .populate_allowed_fds     = populate_allowed_fds,
     327             :   .scratch_align            = scratch_align,
     328             :   .scratch_footprint        = scratch_footprint,
     329             :   .privileged_init          = privileged_init,
     330             :   .unprivileged_init        = unprivileged_init,
     331             :   .run                      = stem_run,
     332             :   .allow_connect            = 1,
     333             :   .keep_host_networking     = 1
     334             : };

Generated by: LCOV version 1.14