Line data Source code
1 : #include "monitor_gossip.h"
2 : #include "gossip_diag.h"
3 : #include "generated/monitor_gossip_seccomp.h"
4 :
5 : #include "../../../shared/commands/monitor/monitor.h" /* reconstruct_topo */
6 : #include "../../../../disco/metrics/fd_metrics.h"
7 : #include "../../../../util/clock/fd_clock.h"
8 :
9 : #include <errno.h>
10 : #include <unistd.h>
11 : #include <signal.h>
12 : #include <stdio.h>
13 : #include <sys/resource.h>
14 : #include <linux/capability.h>
15 :
16 : void
17 : monitor_gossip_cmd_args( int * pargc,
18 : char *** pargv,
19 0 : args_t * args ) {
20 0 : if( FD_UNLIKELY( fd_env_strip_cmdline_contains( pargc, pargv, "--help" ) ) ) {
21 0 : fputs(
22 0 : "\nUsage: firedancer monitor-gossip [GLOBAL FLAGS] [FLAGS]\n"
23 0 : "\n"
24 0 : " Monitor gossip diagnostics on a running Firedancer\n"
25 0 : " instance. Attaches read-only to the validator's\n"
26 0 : " shared memory and prints CRDS tables, message\n"
27 0 : " statistics, and tile performance.\n"
28 0 : "\n"
29 0 : "Global Flags:\n"
30 0 : " --mainnet Use Solana mainnet-beta defaults\n"
31 0 : " --testnet Use Solana testnet defaults\n"
32 0 : " --devnet Use Solana devnet defaults\n"
33 0 : "\n"
34 0 : "Flags:\n"
35 0 : " --topo <name> Reconstruct topology from a named\n"
36 0 : " action (e.g. gossip). Default uses\n"
37 0 : " the production topology.\n"
38 0 : " --compact Use compact output format\n"
39 0 : "\n",
40 0 : stderr );
41 0 : exit( EXIT_SUCCESS );
42 0 : }
43 :
44 0 : char const * topo_name = fd_env_strip_cmdline_cstr( pargc, pargv, "--topo", NULL, "" );
45 0 : ulong topo_name_len = strlen( topo_name );
46 0 : if( FD_UNLIKELY( topo_name_len > sizeof(args->monitor_gossip.topo)-1 ) ) FD_LOG_ERR(( "Unknown --topo %s", topo_name ));
47 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( args->monitor_gossip.topo ), topo_name, topo_name_len ) );
48 :
49 0 : args->monitor_gossip.compact_mode = fd_env_strip_cmdline_contains( pargc, pargv, "--compact" );
50 0 : }
51 :
52 : static void
53 0 : signal_handler( int sig ) {
54 0 : (void)sig;
55 0 : exit( 0 );
56 0 : }
57 :
58 : void
59 : monitor_gossip_cmd_perm( args_t * args FD_PARAM_UNUSED,
60 : fd_cap_chk_t * chk,
61 0 : config_t const * config ) {
62 0 : ulong mlock_limit = fd_topo_mlock( &config->topo );
63 :
64 0 : fd_cap_chk_raise_rlimit( chk, "monitor-gossip", RLIMIT_MEMLOCK, mlock_limit, "call `rlimit(2)` to increase `RLIMIT_MEMLOCK` so all memory can be locked with `mlock(2)`" );
65 :
66 0 : if( fd_sandbox_requires_cap_sys_admin( config->uid, config->gid ) )
67 0 : fd_cap_chk_cap( chk, "monitor-gossip", CAP_SYS_ADMIN, "call `unshare(2)` with `CLONE_NEWUSER` to sandbox the process in a user namespace" );
68 0 : if( FD_LIKELY( getuid() != config->uid ) )
69 0 : fd_cap_chk_cap( chk, "monitor-gossip", CAP_SETUID, "call `setresuid(2)` to switch uid to the sandbox user" );
70 0 : if( FD_LIKELY( getgid() != config->gid ) )
71 0 : fd_cap_chk_cap( chk, "monitor-gossip", CAP_SETGID, "call `setresgid(2)` to switch gid to the sandbox user" );
72 0 : }
73 :
74 : void
75 : monitor_gossip_cmd_fn( args_t * args,
76 0 : config_t * config ) {
77 0 : reconstruct_topo( config, args->monitor_gossip.topo );
78 :
79 0 : struct sigaction sa = {
80 0 : .sa_handler = signal_handler,
81 0 : .sa_flags = 0,
82 0 : };
83 0 : if( FD_UNLIKELY( sigaction( SIGTERM, &sa, NULL ) ) )
84 0 : FD_LOG_ERR(( "sigaction(SIGTERM) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
85 0 : if( FD_UNLIKELY( sigaction( SIGINT, &sa, NULL ) ) )
86 0 : FD_LOG_ERR(( "sigaction(SIGINT) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
87 :
88 0 : int allow_fds[ 4 ];
89 0 : ulong allow_fds_cnt = 0;
90 0 : allow_fds[ allow_fds_cnt++ ] = 0; /* stdin */
91 0 : allow_fds[ allow_fds_cnt++ ] = 1; /* stdout */
92 0 : allow_fds[ allow_fds_cnt++ ] = 2; /* stderr */
93 0 : if( FD_LIKELY( fd_log_private_logfile_fd()!=-1 ) )
94 0 : allow_fds[ allow_fds_cnt++ ] = fd_log_private_logfile_fd();
95 :
96 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
97 :
98 0 : struct sock_filter seccomp_filter[ 128UL ];
99 0 : populate_sock_filter_policy_monitor_gossip( 128UL, seccomp_filter, (uint)fd_log_private_logfile_fd() );
100 :
101 0 : if( FD_LIKELY( config->development.sandbox ) ) {
102 0 : if( FD_UNLIKELY( close( config->log.lock_fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
103 :
104 0 : fd_sandbox_enter( config->uid,
105 0 : config->gid,
106 0 : 0,
107 0 : 0,
108 0 : 0,
109 0 : 1, /* Keep controlling terminal for Ctrl+C */
110 0 : 0,
111 0 : 0UL,
112 0 : 0UL,
113 0 : 0UL,
114 0 : 0UL,
115 0 : allow_fds_cnt,
116 0 : allow_fds,
117 0 : sock_filter_policy_monitor_gossip_instr_cnt,
118 0 : seccomp_filter );
119 0 : } else {
120 0 : fd_sandbox_switch_uid_gid( config->uid, config->gid );
121 0 : }
122 :
123 0 : fd_topo_fill( &config->topo );
124 :
125 0 : fd_gossip_diag_ctx_t diag_ctx[1];
126 0 : if( FD_UNLIKELY( fd_gossip_diag_init( diag_ctx, &config->topo, config ) ) ) {
127 0 : FD_LOG_ERR(( "Failed to initialize gossip diagnostics. "
128 0 : "Is a Firedancer instance running with gossip tiles?" ));
129 0 : }
130 :
131 0 : printf( "Found %lu gossvf tiles\n", diag_ctx->gossvf.tile_count );
132 :
133 0 : fd_clock_t clock_lmem[1];
134 0 : void * clock_mem = aligned_alloc( FD_CLOCK_ALIGN, FD_CLOCK_FOOTPRINT );
135 0 : FD_TEST( clock_mem );
136 0 : fd_clock_default_init( clock_lmem, clock_mem );
137 :
138 0 : long next_report_time = fd_clock_now( clock_lmem ) + 1000000000L;
139 :
140 0 : for(;;) {
141 0 : long current_time = fd_clock_now( clock_lmem );
142 0 : if( FD_LIKELY( current_time < next_report_time ) ) continue;
143 0 : next_report_time += 1000000000L;
144 :
145 0 : fd_gossip_diag_render( diag_ctx, args->monitor_gossip.compact_mode );
146 0 : }
147 0 : }
148 :
149 : action_t fd_action_monitor_gossip = {
150 : .name = "monitor-gossip",
151 : .args = monitor_gossip_cmd_args,
152 : .fn = monitor_gossip_cmd_fn,
153 : .require_config = 1,
154 : .perm = monitor_gossip_cmd_perm,
155 : .is_diagnostic = 1,
156 : .description = "Monitor gossip diagnostics on a running Firedancer instance",
157 : };
|