Line data Source code
1 : #include "monitor_gossip.h"
2 : #include "../../../shared/fd_bootinfo.h"
3 : #include "gossip_diag.h"
4 : #include "generated/monitor_gossip_seccomp.h"
5 :
6 : #include "../../../shared/commands/monitor/monitor.h" /* reconstruct_topo */
7 : #include "../../../../disco/fd_clock_tile.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 : char const * topo_name = fd_env_strip_cmdline_cstr( pargc, pargv, "--topo", NULL, "" );
21 0 : ulong topo_name_len = strlen( topo_name );
22 0 : if( FD_UNLIKELY( topo_name_len > sizeof(args->monitor_gossip.topo)-1 ) ) FD_LOG_ERR(( "Unknown --topo %s", topo_name ));
23 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( args->monitor_gossip.topo ), topo_name, topo_name_len ) );
24 :
25 0 : args->monitor_gossip.compact_mode = fd_env_strip_cmdline_contains( pargc, pargv, "--compact" );
26 0 : }
27 :
28 : static void
29 0 : signal_handler( int sig ) {
30 0 : (void)sig;
31 0 : exit( 0 );
32 0 : }
33 :
34 : void
35 : monitor_gossip_cmd_perm( args_t * args FD_PARAM_UNUSED,
36 : fd_cap_chk_t * chk,
37 0 : config_t const * config ) {
38 0 : ulong mlock_limit = fd_topo_mlock( &config->topo );
39 :
40 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)`" );
41 :
42 0 : if( fd_sandbox_requires_cap_sys_admin( config->uid, config->gid ) )
43 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" );
44 0 : if( FD_LIKELY( getuid() != config->uid ) )
45 0 : fd_cap_chk_cap( chk, "monitor-gossip", CAP_SETUID, "call `setresuid(2)` to switch uid to the sandbox user" );
46 0 : if( FD_LIKELY( getgid() != config->gid ) )
47 0 : fd_cap_chk_cap( chk, "monitor-gossip", CAP_SETGID, "call `setresgid(2)` to switch gid to the sandbox user" );
48 0 : }
49 :
50 : void
51 : monitor_gossip_cmd_fn( args_t * args,
52 0 : config_t * config ) {
53 0 : fd_bootinfo_adopt( config );
54 0 : reconstruct_topo( config, args->monitor_gossip.topo );
55 :
56 0 : struct sigaction sa = {
57 0 : .sa_handler = signal_handler,
58 0 : .sa_flags = 0,
59 0 : };
60 0 : if( FD_UNLIKELY( sigaction( SIGTERM, &sa, NULL ) ) )
61 0 : FD_LOG_ERR(( "sigaction(SIGTERM) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
62 0 : if( FD_UNLIKELY( sigaction( SIGINT, &sa, NULL ) ) )
63 0 : FD_LOG_ERR(( "sigaction(SIGINT) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
64 :
65 0 : int allow_fds[ 4 ];
66 0 : ulong allow_fds_cnt = 0;
67 0 : allow_fds[ allow_fds_cnt++ ] = 0; /* stdin */
68 0 : allow_fds[ allow_fds_cnt++ ] = 1; /* stdout */
69 0 : allow_fds[ allow_fds_cnt++ ] = 2; /* stderr */
70 0 : if( FD_LIKELY( fd_log_private_logfile_fd()!=-1 ) )
71 0 : allow_fds[ allow_fds_cnt++ ] = fd_log_private_logfile_fd();
72 :
73 0 : fd_bootinfo_check_layout( config );
74 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
75 :
76 0 : struct sock_filter seccomp_filter[ 128UL ];
77 0 : populate_sock_filter_policy_monitor_gossip( 128UL, seccomp_filter, (uint)fd_log_private_logfile_fd() );
78 :
79 0 : if( FD_LIKELY( config->development.sandbox ) ) {
80 0 : fd_sandbox_enter( config->uid,
81 0 : config->gid,
82 0 : 0,
83 0 : 0,
84 0 : 0,
85 0 : 1, /* Keep controlling terminal for Ctrl+C */
86 0 : 0,
87 0 : 0UL,
88 0 : 0UL,
89 0 : 0UL,
90 0 : 0UL,
91 0 : allow_fds_cnt,
92 0 : allow_fds,
93 0 : sock_filter_policy_monitor_gossip_instr_cnt,
94 0 : seccomp_filter );
95 0 : } else {
96 0 : fd_sandbox_switch_uid_gid( config->uid, config->gid );
97 0 : }
98 :
99 0 : fd_topo_fill( &config->topo );
100 :
101 0 : fd_gossip_diag_ctx_t diag_ctx[1];
102 0 : if( FD_UNLIKELY( fd_gossip_diag_init( diag_ctx, &config->topo, config ) ) ) {
103 0 : FD_LOG_ERR(( "Failed to initialize gossip diagnostics. "
104 0 : "Is a Firedancer instance running with gossip tiles?" ));
105 0 : }
106 :
107 0 : printf( "Found %lu gossvf tiles\n", diag_ctx->gossvf.tile_count );
108 :
109 0 : fd_clock_tile_t clock[1];
110 0 : fd_clock_tile_init( clock );
111 :
112 0 : long next_report_time = fd_clock_tile_now( clock ) + 1000000000L;
113 0 : for(;;) {
114 0 : long current_time = fd_clock_tile_now( clock );
115 0 : if( FD_LIKELY( current_time < next_report_time ) ) continue;
116 0 : next_report_time += 1000000000L;
117 :
118 0 : fd_gossip_diag_render( diag_ctx, args->monitor_gossip.compact_mode );
119 0 : fd_clock_tile_recal( clock );
120 0 : }
121 0 : }
122 :
123 : static void
124 0 : monitor_gossip_args_help( fd_action_help_t * help ) {
125 0 : fd_action_help_arg( help, "--topo", "<command>", "Build the topology from another subcommand (e.g. `gossip`) instead of\n"
126 0 : "the default validator topology. <command> is the name of a subcommand\n"
127 0 : "that builds its own topology" );
128 : fd_action_help_arg( help, "--compact", NULL, "Use a denser output format" );
129 0 : }
130 :
131 : action_t fd_action_monitor_gossip = {
132 : .name = "monitor-gossip",
133 : .args = monitor_gossip_cmd_args,
134 : .fn = monitor_gossip_cmd_fn,
135 : .require_config = 0,
136 : .perm = monitor_gossip_cmd_perm,
137 : .is_diagnostic = 1,
138 : .description = "Monitor gossip diagnostics on a running Firedancer instance",
139 : .detail = "Connects to a running validator's shared memory and prints gossip diagnostics,\n"
140 : "including gossip table statistics, message statistics, and per-tile\n"
141 : "performance.",
142 : .usage = "monitor-gossip [OPTIONS]",
143 : .args_help = monitor_gossip_args_help,
144 : };
|