Line data Source code
1 : #ifndef HEADER_fd_src_disco_topo_fd_topo_h
2 : #define HEADER_fd_src_disco_topo_fd_topo_h
3 :
4 : #include "../stem/fd_stem.h"
5 : #include "../../tango/fd_tango.h"
6 : #include "../../waltz/xdp/fd_xdp1.h"
7 : #include "../../waltz/http/fd_url.h"
8 : #include "../../ballet/base58/fd_base58.h"
9 : #include "../../flamenco/fd_flamenco_base.h"
10 : #include "../../util/net/fd_net_headers.h"
11 : #include "../../util/net/fd_ip6.h"
12 : #include "../pack/fd_pack_acct_blocklist.h"
13 : #include "../keyguard/fd_keyguard.h"
14 :
15 : /* Maximum number of workspaces that may be present in a topology. */
16 : #define FD_TOPO_MAX_WKSPS ( 256UL)
17 : /* Maximum number of links that may be present in a topology. */
18 0 : #define FD_TOPO_MAX_LINKS (1024UL)
19 : /* Maximum number of tiles that may be present in a topology. */
20 0 : #define FD_TOPO_MAX_TILES ( 256UL)
21 : /* Maximum number of objects that may be present in a topology. */
22 : #define FD_TOPO_MAX_OBJS (4096UL)
23 : /* Maximum number of links that may go into any one tile in the
24 : topology. */
25 0 : #define FD_TOPO_MAX_TILE_IN_LINKS ( 256UL)
26 : /* Maximum number of links that a tile may write to. */
27 : #define FD_TOPO_MAX_TILE_OUT_LINKS ( 64UL)
28 : /* Maximum number of objects that a tile can use. */
29 : #define FD_TOPO_MAX_TILE_OBJS (1024UL)
30 :
31 : FD_STATIC_ASSERT( FD_SLEEP_LINK_MAX==FD_TOPO_MAX_LINKS, sleep_limits );
32 : FD_STATIC_ASSERT( FD_SLEEP_IN_MAX ==FD_TOPO_MAX_TILE_IN_LINKS, sleep_limits );
33 : FD_STATIC_ASSERT( FD_SLEEP_OUT_MAX ==FD_TOPO_MAX_TILE_OUT_LINKS, sleep_limits );
34 :
35 : /* Maximum number of additional ip addresses */
36 : #define FD_NET_MAX_SRC_ADDR 4
37 :
38 : /* Maximum number of additional destinations for leader shreds and for retransmitted shreds */
39 : #define FD_TOPO_ADTL_DESTS_MAX ( 32UL)
40 :
41 0 : #define FD_TOPO_CORE_DUMP_LEVEL_DISABLED (0)
42 0 : #define FD_TOPO_CORE_DUMP_LEVEL_MINIMAL (1)
43 0 : #define FD_TOPO_CORE_DUMP_LEVEL_REGULAR (2)
44 0 : #define FD_TOPO_CORE_DUMP_LEVEL_FULL (3)
45 0 : #define FD_TOPO_CORE_DUMP_LEVEL_NEVER (4)
46 :
47 : /* A workspace is a Firedancer specific memory management structure that
48 : sits on top of 1 or more memory mapped gigantic or huge pages mounted
49 : to the hugetlbfs. */
50 : typedef struct {
51 : ulong id; /* The ID of this workspace. Indexed from [0, wksp_cnt). When placed in a topology, the ID must be the index of the workspace in the workspaces list. */
52 : char name[ 14UL ]; /* The name of this workspace, like "pack". There can be at most one of each workspace name in a topology. */
53 :
54 : ulong numa_idx; /* The index of the NUMA node on the system that this workspace should be allocated from. */
55 :
56 : ulong min_part_max; /* Artificially raise part_max */
57 : ulong min_loose_sz; /* Artificially raise loose footprint */
58 :
59 : /* Computed fields. These are not supplied as configuration but calculated as needed. */
60 : struct {
61 : ulong page_sz; /* The size of the pages that this workspace is backed by. One of FD_PAGE_SIZE_*. */
62 : ulong page_cnt; /* The number of pages that must be mapped to this workspace to store all the data needed by consumers. */
63 : ulong part_max; /* The maximum number of partitions in the underlying workspace. There can only be this many allocations made at any one time. */
64 :
65 : int core_dump_level; /* The core dump level required to be set in the application configuration to have this workspace appear in core dumps. */
66 :
67 : fd_wksp_t * wksp; /* The workspace memory in the local process. */
68 : ulong known_footprint; /* Total size in bytes of all data in Firedancer that will be stored in this workspace at startup. */
69 : ulong total_footprint; /* Total size in bytes of all data in Firedancer that could be stored in this workspace, includes known data and loose data. */
70 : };
71 : } fd_topo_wksp_t;
72 :
73 : /* A link is an mcache in a workspace that has one producer and one or
74 : more consumers. A link may optionally also have a dcache, that holds
75 : fragments referred to by the mcache entries.
76 :
77 : A link belongs to exactly one workspace. A link has exactly one
78 : producer, and 1 or more consumers. Each consumer is either reliable
79 : or not reliable. A link has a depth and a MTU, which correspond to
80 : the depth and MTU of the mcache and dcache respectively. A MTU of
81 : zero means no dcache is needed, as there is no data. */
82 : typedef struct {
83 : ulong id; /* The ID of this link. Indexed from [0, link_cnt). When placed in a topology, the ID must be the index of the link in the links list. */
84 : char name[ 14UL ]; /* The name of this link, like "pack_execle". There can be multiple of each link name in a topology. */
85 : ulong kind_id; /* The ID of this link within its name. If there are N links of a particular name, they have IDs [0, N). The pair (name, kind_id) uniquely identifies a link, as does "id" on its own. */
86 :
87 : ulong depth; /* The depth of the mcache representing the link. */
88 : ulong mtu; /* The MTU of data fragments in the mcache. A value of 0 means there is no dcache. */
89 : ulong burst; /* The max amount of MTU sized data fragments that might be bursted to the dcache. */
90 :
91 : ulong mcache_obj_id;
92 : ulong dcache_obj_id;
93 :
94 : /* Computed fields. These are not supplied as configuration but calculated as needed. */
95 : struct {
96 : fd_frag_meta_t * mcache; /* The mcache of this link. */
97 : void * dcache; /* The dcache of this link, if it has one. */
98 : };
99 :
100 : uint permit_no_consumers : 1; /* Permit a topology where this link has no consumers */
101 : uint permit_no_producers : 1; /* Permit a topology where this link has no producers */
102 : } fd_topo_link_t;
103 :
104 : struct fd_topo_net_tile {
105 : ulong umem_dcache_obj_id; /* dcache for network UMEM frames */
106 : uint bind_address;
107 :
108 : ushort shred_listen_port;
109 : ushort quic_transaction_listen_port;
110 : ushort legacy_transaction_listen_port;
111 : ushort gossip_listen_port;
112 : ushort repair_client_listen_port;
113 : ushort repair_serve_listen_port;
114 : ushort votor_quic_client_listen_port;
115 : ushort votor_quic_server_listen_port;
116 : };
117 : typedef struct fd_topo_net_tile fd_topo_net_tile_t;
118 :
119 : /* A tile is a unique process that is spawned by Firedancer to represent
120 : one thread of execution. Firedancer sandboxes all tiles to their own
121 : process for security reasons.
122 :
123 : A tile belongs to exactly one workspace. A tile is a consumer of 0
124 : or more links, it's inputs. A tile is a producer of 0 or more output
125 : links.
126 :
127 : All input links will be automatically polled by the tile
128 : infrastructure, and output links will automatically source and manage
129 : credits from consumers. */
130 : struct fd_topo_tile {
131 : ulong id; /* The ID of this tile. Indexed from [0, tile_cnt). When placed in a topology, the ID must be the index of the tile in the tiles list. */
132 : char name[ 7UL ]; /* The name of this tile. There can be multiple of each tile name in a topology. */
133 : ulong kind_id; /* The ID of this tile within its name. If there are n tile of a particular name, they have IDs [0, N). The pair (name, kind_id) uniquely identifies a tile, as does "id" on its own. */
134 :
135 : int is_waker_client; /* Tile has file descriptors which must be serviced by the external waker tile. */
136 : int allow_shutdown; /* If the tile is allowed to shutdown gracefully. If false, when the tile exits it will tear down the entire application. */
137 :
138 : ulong cpu_idx; /* The CPU index to pin the tile on. A value of ULONG_MAX or more indicates the tile should be floating and not pinned to a core. */
139 : int floats; /* Scheduled by the kernel over the CPUs of the floating tiles on its NUMA node, never a pinned tile's CPU, instead of pinned to cpu_idx (efficient mode). cpu_idx still places memory and isolation, and is the fallback when no such CPU remains. */
140 : int sleep_eventfd; /* Parks in epoll on its own fds and is woken through the eventfd FD_SLEEP_EVENTFD( id ), not FUTEX_WAKE (efficient mode only) */
141 :
142 : ulong waker_client_idx; /* Client slot in the fixed inherited fd range (inner epoll fd FD_WAKER_INNER_FD( idx )), or ULONG_MAX if not a waker client */
143 : ulong waker_fseq_obj_id; /* fseq object holding the tile's waker readiness word or ULONG_MAX */
144 :
145 : ulong in_cnt; /* The number of links that this tile reads from. */
146 : ulong in_link_id[ FD_TOPO_MAX_TILE_IN_LINKS ]; /* The link_id of each link that this tile reads from, indexed in [0, in_cnt). */
147 : int in_link_reliable[ FD_TOPO_MAX_TILE_IN_LINKS ]; /* If each link that this tile reads from is a reliable or unreliable consumer, indexed in [0, in_cnt). */
148 : int in_link_poll[ FD_TOPO_MAX_TILE_IN_LINKS ]; /* If each link that this tile reads from should be polled by the tile infrastructure, indexed in [0, in_cnt).
149 : If the link is not polled, the tile will not receive frags for it and the tile writer is responsible for
150 : reading from the link. The link must be marked as unreliable as it is not flow controlled. */
151 :
152 : ulong out_cnt; /* The number of links that this tile writes to. */
153 : ulong out_link_id[ FD_TOPO_MAX_TILE_OUT_LINKS ]; /* The link_id of each link that this tile writes to, indexed in [0, link_cnt). */
154 :
155 : ulong event_link_id; /* If not ULONG_MAX, the link_id of a dedicated unreliable link to the event tile that this tile reports
156 : telemetry events on via the thread-local fd_event_report_* macros. This link is deliberately NOT part
157 : of out_link_id[] / out_cnt: it is written directly (outside fd_stem) by the thread-local reporter. */
158 :
159 : ulong tile_obj_id;
160 : ulong metrics_obj_id;
161 : ulong id_keyswitch_obj_id; /* keyswitch object id for identity key updates */
162 : ulong av_keyswitch_obj_id; /* keyswitch object id for authority key updates */
163 : ulong in_link_fseq_obj_id[ FD_TOPO_MAX_TILE_IN_LINKS ];
164 :
165 : ulong uses_obj_cnt;
166 : ulong uses_obj_id[ FD_TOPO_MAX_TILE_OBJS ];
167 : int uses_obj_mode[ FD_TOPO_MAX_TILE_OBJS ];
168 :
169 : /* Computed fields. These are not supplied as configuration but calculated as needed. */
170 : struct {
171 : ulong * metrics; /* The shared memory for metrics that this tile should write. Consumer by monitoring and metrics writing tiles. */
172 :
173 : /* The fseq of each link that this tile reads from. Multiple fseqs
174 : may point to the link, if there are multiple consumers. An fseq
175 : can be uniquely identified via (link_id, tile_id), or (link_kind,
176 : link_kind_id, tile_kind, tile_kind_id) */
177 : ulong * in_link_fseq[ FD_TOPO_MAX_TILE_IN_LINKS ];
178 : };
179 :
180 : /* Configuration fields. These are required to be known by the topology so it can determine the
181 : total size of Firedancer in memory. */
182 : union {
183 : fd_topo_net_tile_t net;
184 :
185 : struct {
186 : fd_topo_net_tile_t net;
187 :
188 : char if_virt[ 16 ]; /* device name (virtual, for routing) */
189 : char if_phys[ 16 ]; /* device name (physical, for RX/TX) */
190 : uint if_queue; /* device queue index */
191 :
192 : /* xdp specific options */
193 : ulong xdp_rx_queue_size;
194 : ulong xdp_tx_queue_size;
195 : ulong free_ring_depth;
196 : long tx_flush_timeout_ns;
197 : char xdp_mode[8];
198 : int zero_copy;
199 :
200 : char poll_mode[ 16 ]; /* "softirq" or "prefbusy" */
201 :
202 : ulong netdev_tbl_obj_id;
203 :
204 : ulong route_max;
205 : ulong route_peer_max;
206 : ulong route_peer_seed;
207 : ulong neigh4_obj_id; /* neigh4 hash map */
208 : } xdp;
209 :
210 : struct {
211 : fd_topo_net_tile_t net;
212 :
213 : char if_name[ 16 ];
214 : uint rx_queue_size;
215 : uint tx_queue_size;
216 : uint batch_size;
217 :
218 : ulong netdev_tbl_obj_id;
219 : ulong route_max;
220 : ulong route_peer_max;
221 : ulong route_peer_seed;
222 : ulong neigh4_obj_id;
223 : } mlx5;
224 :
225 : struct {
226 : fd_topo_net_tile_t net;
227 :
228 : char if_name[ 16 ];
229 : char members[ 16 ][ 16 ];
230 : ulong member_cnt;
231 : uint rx_queue_size;
232 : uint tx_queue_size;
233 :
234 : ulong netdev_tbl_obj_id;
235 : ulong route_max;
236 : ulong route_peer_max;
237 : ulong route_peer_seed;
238 : ulong neigh4_obj_id;
239 : } iavf;
240 :
241 : struct {
242 : fd_topo_net_tile_t net;
243 : /* sock specific options */
244 : int so_sndbuf;
245 : int so_rcvbuf;
246 : int only_recv_lo;
247 : ulong net_tile_id;
248 : } sock;
249 :
250 : struct {
251 : ulong netdev_tbl_obj_id;
252 : ulong route_max;
253 : ulong route_peer_max;
254 : char neigh_if[ 16 ]; /* neigh4 interface name */
255 : ulong neigh4_obj_id; /* neigh4 hash map */
256 : } netlink;
257 :
258 : struct {
259 : char identity_key_path[ PATH_MAX ];
260 : } admin;
261 :
262 : struct {
263 : char identity_key_path[ PATH_MAX ]; /* the key this machine boots under */
264 : char target_key_path[ PATH_MAX ]; /* the identity failover hands off, [paths.identity_key] */
265 : int listen; /* open the network listener so we can hand over our identity to another machine */
266 : uint listen_addr; /* network byte order */
267 : ushort port;
268 :
269 : char gossip_host[ FD_FQDN_BUF_MAX ];
270 : fd_ip4_port_t gossip_addr; /* our own gossip socket, gossip_host overrides the address */
271 : } failov;
272 :
273 0 : #define FD_TOPO_GOSSIP_ENTRYPOINTS_MAX 16UL
274 :
275 : struct {
276 : char identity_key_path[ PATH_MAX ];
277 :
278 : ulong entrypoints_cnt;
279 : char entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
280 :
281 : long boot_timestamp_nanos;
282 :
283 : ulong tcache_depth;
284 :
285 : ushort shred_version;
286 : int allow_private_address;
287 :
288 : char gossip_host[ FD_FQDN_BUF_MAX ];
289 : fd_ip4_port_t gossip_addr;
290 : fd_ip4_port_t src_addr;
291 : } gossvf;
292 :
293 : struct {
294 : char identity_key_path[ PATH_MAX ];
295 :
296 : ulong entrypoints_cnt;
297 : char entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
298 :
299 : long boot_timestamp_nanos;
300 :
301 : char gossip_host[ FD_FQDN_BUF_MAX ];
302 : uint net_ip_addr; /* net.ip_addr fallback when gossip_host empty */
303 : uint ip_addr;
304 : uint bind_ip_addr;
305 : ushort expected_shred_version;
306 :
307 : ulong max_entries;
308 : ulong max_purged;
309 : ulong max_failed;
310 :
311 : ulong wait_for_supermajority_at_slot;
312 : int wait_for_supermajority_hash_is_zero;
313 :
314 : struct {
315 : ushort gossip;
316 : ushort tvu;
317 : ushort tvu_quic;
318 : ushort tpu;
319 : ushort tpu_quic;
320 : ushort repair;
321 : ushort rserve;
322 : ushort votor;
323 : } ports;
324 : } gossip;
325 :
326 : struct {
327 : uint out_depth;
328 : uint reasm_cnt;
329 : ulong max_concurrent_connections;
330 : ulong max_concurrent_handshakes;
331 : ushort quic_transaction_listen_port;
332 : long idle_timeout_millis;
333 : uint ack_delay_millis;
334 : int retry;
335 : char key_log_path[ PATH_MAX ];
336 : } quic;
337 :
338 : struct {
339 : ulong tcache_depth;
340 : } verify;
341 :
342 : struct {
343 : ulong tcache_depth;
344 : } dedup;
345 :
346 : struct {
347 : char url[ FD_URL_MAX ];
348 : ulong url_len;
349 : char sni[ FD_SNI_BUF_MAX ];
350 : ulong sni_len;
351 : char identity_key_path[ PATH_MAX ];
352 : char key_log_path[ PATH_MAX ];
353 : ulong buf_sz;
354 : ulong keepalive_interval_nanos;
355 : uchar tls_cert_verify : 1;
356 : } bundle;
357 :
358 : struct {
359 : char url[ FD_URL_MAX ];
360 : char identity_key_path[ PATH_MAX ];
361 : char action[ 16 ];
362 : uchar genesis_hash[ 32 ];
363 : ushort shred_version;
364 :
365 : char accounts_path [ PATH_MAX ];
366 : char snapshots_path[ PATH_MAX ];
367 : char log_path [ PATH_MAX ];
368 : char shredb_path [ PATH_MAX ];
369 : char guidb_path [ PATH_MAX ];
370 : char net_interface [ 16 ];
371 : long boot_timestamp_nanos;
372 : ulong launch_cpus[ 1024UL/64UL ];
373 : char launch_cgroup[ PATH_MAX ];
374 : ulong tx_rate_mbps;
375 : } event;
376 :
377 : struct {
378 : ulong max_pending_transactions;
379 : ulong execle_tile_count;
380 : ulong max_cost_per_block;
381 : ulong max_shreds_per_block;
382 : ulong bench_max_shreds_per_block; /* [development.bench], floors the leader's per-slot shred limit */
383 : int use_consumed_cus;
384 : int schedule_strategy;
385 : struct {
386 : int enabled;
387 : uchar tip_distribution_program_addr[ 32 ];
388 : uchar tip_payment_program_addr[ 32 ];
389 : uchar tip_distribution_authority[ 32 ];
390 : ulong commission_bps;
391 : char identity_key_path[ PATH_MAX ];
392 : char vote_account_path[ PATH_MAX ]; /* or pubkey is okay */
393 : } bundle;
394 : ulong acct_blocklist_cnt;
395 : fd_pubkey_t acct_blocklist[ FD_PACK_ACCT_BLOCKLIST_MAX ];
396 : } pack;
397 :
398 : struct {
399 : ulong execle_cnt;
400 : char identity_key_path[ PATH_MAX ];
401 : ulong max_txn_per_slot;
402 : } poh;
403 :
404 : struct {
405 : ulong execle_cnt;
406 : char identity_key_path[ PATH_MAX ];
407 : ulong max_txn_per_slot;
408 : } motor;
409 :
410 : struct {
411 : ulong fec_exposure;
412 : ulong fec_resolver_depth;
413 : ulong slot_max;
414 : char identity_key_path[ PATH_MAX ];
415 : ushort shred_listen_port;
416 : ulong max_shreds_per_block;
417 : ulong bench_max_shreds_per_block; /* [development.bench], floors the chain's per-slot limit */
418 : ushort expected_shred_version;
419 : ulong adtl_dests_retransmit_cnt;
420 : char adtl_dests_retransmit[ FD_TOPO_ADTL_DESTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
421 : ulong adtl_dests_leader_cnt;
422 : char adtl_dests_leader[ FD_TOPO_ADTL_DESTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
423 : } shred;
424 :
425 : struct {
426 : ulong disable_blockstore_from_slot;
427 : } store;
428 :
429 : struct {
430 : char identity_key_path[ PATH_MAX ];
431 : int failover_junk_fd; /* private startup pipe for the failover junk key, -1 without failover */
432 : int failover_enabled;
433 : ulong authorized_voter_paths_cnt;
434 : char authorized_voter_paths[ FD_KEYGUARD_AUTH_VOTERS_MAX ][ PATH_MAX ];
435 : struct {
436 : uchar tip_payment_program_addr[ 32 ];
437 : uchar tip_distribution_program_addr[ 32 ];
438 : } bundle;
439 : } sign;
440 :
441 : struct {
442 : uint listen_addr;
443 : ushort listen_port;
444 :
445 : int is_voting;
446 :
447 : char cluster[ 32 ];
448 : char identity_key_path[ PATH_MAX ];
449 : char vote_key_path[ PATH_MAX ];
450 : char accounts_database_path[ PATH_MAX ];
451 : char gui_database_path[ PATH_MAX ];
452 :
453 : ulong max_http_connections;
454 : ulong max_websocket_connections;
455 : ulong send_buffer_size_mb;
456 : ulong db_size_gib;
457 : int schedule_strategy;
458 :
459 : int websocket_compression;
460 : ulong tile_cnt;
461 : ulong max_live_slots;
462 :
463 : char wfs_bank_hash[ FD_BASE58_ENCODED_32_SZ ];
464 : ulong wfs_slot;
465 : ushort expected_shred_version;
466 : ulong cache_size_gib;
467 : ulong accdb_obj_id;
468 : ulong max_txn_per_slot;
469 : } gui;
470 :
471 : struct {
472 : fd_ip6_addr_t listen_addr;
473 : ushort listen_port;
474 :
475 : ulong max_http_connections;
476 : ulong max_websocket_connections;
477 : ulong send_buffer_size_mb;
478 :
479 : ulong max_live_slots;
480 : ulong genesis_max_message_size;
481 :
482 : ulong accdb_obj_id;
483 : ulong accdb_epoch_fseq_obj_id;
484 :
485 : char identity_key_path[ PATH_MAX ];
486 : int delay_startup;
487 :
488 : int snapshot_server_enabled;
489 : char snapshot_server_host[ FD_FQDN_BUF_MAX ];
490 : ushort snapshot_server_port;
491 : } rpc;
492 :
493 : struct {
494 : uint prometheus_listen_addr;
495 : ushort prometheus_listen_port;
496 : } metric;
497 :
498 : struct {
499 : int is_voting;
500 :
501 : char accounts_path [ PATH_MAX ];
502 : char shreds_path [ PATH_MAX ];
503 : char snapshots_path[ PATH_MAX ];
504 : char gui_path [ PATH_MAX ];
505 : char log_path [ PATH_MAX ];
506 : } diag;
507 :
508 : struct {
509 : ulong accdb_obj_id;
510 : ulong txncache_obj_id;
511 :
512 : char identity_key_path[ PATH_MAX ];
513 : char vote_account_path[ PATH_MAX ];
514 :
515 : fd_hash_t wait_for_supermajority_with_bank_hash;
516 : ulong wait_for_supermajority_at_slot;
517 : ushort expected_shred_version;
518 : int wait_for_vote_to_start_leader;
519 :
520 : ulong sched_depth;
521 : ulong max_live_slots;
522 : ulong genesis_max_message_size;
523 : ulong full_snapshot_interval_blocks;
524 : ulong incremental_snapshot_interval_blocks;
525 :
526 : /* not specified in TOML */
527 :
528 : long boot_timestamp_nanos;
529 :
530 : ulong enable_features_cnt;
531 : char enable_features[ 16 ][ FD_BASE58_ENCODED_32_SZ ];
532 :
533 : char genesis_path[ PATH_MAX ];
534 :
535 : ulong max_txn_per_slot; /* config->limits */
536 : ulong max_shreds_per_block;
537 :
538 : ulong capture_start_slot;
539 : char solcap_capture[ PATH_MAX ];
540 : char dump_proto_dir[ PATH_MAX ];
541 : int dump_block_to_pb;
542 : int report_runtime_diffs;
543 :
544 : struct {
545 : int enabled;
546 : uchar tip_payment_program_addr[ 32 ];
547 : uchar tip_distribution_program_addr[ 32 ];
548 : char vote_account_path[ PATH_MAX ];
549 : } bundle;
550 : } replay;
551 :
552 : struct {
553 : ulong txncache_obj_id;
554 : ulong progcache_obj_id;
555 : ulong accdb_obj_id;
556 : ulong bpf_frames_obj_id;
557 :
558 : ulong max_live_slots;
559 :
560 : ulong capture_start_slot;
561 : char solcap_capture[ PATH_MAX ];
562 : char dump_proto_dir[ PATH_MAX ];
563 : char dump_syscall_name_filter[ PATH_MAX ];
564 : char dump_instr_program_id_filter[ FD_BASE58_ENCODED_32_SZ ];
565 : int dump_instr_to_pb;
566 : int dump_txn_to_pb;
567 : int dump_txn_as_fixture;
568 : int dump_syscall_to_pb;
569 : int report_runtime_diffs;
570 : } execrp;
571 :
572 : struct {
573 : ushort send_to_port;
574 : uint send_to_ip_addr;
575 : ulong conn_cnt;
576 : int no_quic;
577 : } benchs;
578 :
579 : struct {
580 : ushort rpc_port;
581 : uint rpc_ip_addr;
582 : ulong duration_s;
583 : } bencho;
584 :
585 : struct {
586 : ulong accounts_cnt;
587 : int mode;
588 : float contending_fraction;
589 : float cu_price_spread;
590 : } benchg;
591 :
592 : struct {
593 : ushort repair_client_listen_port;
594 : char identity_key_path[ PATH_MAX ];
595 : ulong slot_max;
596 : ulong fec_max;
597 : ulong max_shreds_per_block;
598 : int allow_private_address;
599 : int report_repair_requests;
600 :
601 : ulong repair_sign_depth;
602 : ulong repair_sign_cnt;
603 : } repair;
604 :
605 : struct {
606 : ushort repair_serve_listen_port;
607 : char identity_key_path[ PATH_MAX ];
608 : ulong ping_cache_entries;
609 : ulong max_shreds_per_block;
610 : ulong blockdb_max; /* 0 disables the block metadata db */
611 : } rserve;
612 :
613 : struct {
614 : uint fake_dst_ip;
615 : } pktgen;
616 :
617 : struct {
618 : char ledger_format[ 16 ];
619 : char ledger_path[ PATH_MAX ];
620 : ulong end_slot;
621 : ulong root_distance;
622 : long boot_timestamp_nanos;
623 : } backtest;
624 :
625 : struct {
626 : char identity_key_path[ PATH_MAX ];
627 : char vote_history_path[ PATH_MAX ];
628 : uint target_gid;
629 : uint target_uid;
630 : ulong authorized_voter_paths_cnt;
631 : ushort quic_client_listen_port;
632 : ushort quic_server_listen_port;
633 : uint ip_addr;
634 : ulong max_live_slots;
635 : ulong wait_for_supermajority_at_slot;
636 : int wait_for_supermajority_hash_is_zero;
637 : ushort expected_shred_version;
638 : } votor;
639 :
640 : struct {
641 : ulong accdb_obj_id;
642 : ulong max_live_slots;
643 :
644 : ulong rpc_epoch_obj_id;
645 : ulong resolv_epoch_obj_ids[ 16 ];
646 : ulong resolv_epoch_obj_cnt;
647 : ulong snapmk_epoch_obj_id;
648 : ulong snapzp_epoch_obj_ids[ 64 ];
649 : ulong snapzp_epoch_obj_cnt;
650 : } accdb;
651 :
652 : struct {
653 : ulong max_live_slots;
654 : ulong accdb_obj_id;
655 : ulong accdb_epoch_fseq_obj_id;
656 : } resolv;
657 :
658 :
659 : #define FD_TOPO_SNAPSHOTS_GOSSIP_LIST_MAX (32UL)
660 0 : #define FD_TOPO_SNAPSHOTS_SERVERS_MAX (16UL)
661 0 : #define FD_TOPO_MAX_RESOLVED_ADDRS ( 4UL)
662 0 : #define FD_TOPO_SNAPSHOTS_SERVERS_MAX_RESOLVED (FD_TOPO_MAX_RESOLVED_ADDRS*FD_TOPO_SNAPSHOTS_SERVERS_MAX)
663 :
664 : struct fd_topo_tile_snapct {
665 : char snapshots_path[ PATH_MAX ];
666 :
667 : ulong entrypoints_cnt;
668 : char entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
669 :
670 : struct {
671 : uint max_local_full_effective_age;
672 : uint max_local_incremental_age;
673 :
674 : struct {
675 : int allow_any;
676 : ulong allow_list_cnt;
677 : fd_pubkey_t allow_list[ FD_TOPO_SNAPSHOTS_GOSSIP_LIST_MAX ];
678 : ulong block_list_cnt;
679 : fd_pubkey_t block_list[ FD_TOPO_SNAPSHOTS_GOSSIP_LIST_MAX ];
680 : } gossip;
681 :
682 : ulong servers_cnt;
683 : char servers[ FD_TOPO_SNAPSHOTS_SERVERS_MAX ][ FD_URL_MAX ];
684 : } sources;
685 :
686 : int incremental_snapshots;
687 : uint max_full_snapshots_to_keep;
688 : uint max_incremental_snapshots_to_keep;
689 : uint max_retry_abort;
690 : long wait_for_peers_timeout_nanos;
691 : ulong wfs_slot;
692 : int wfs_hash_is_zero;
693 : ushort wfs_shred_version;
694 : } snapct;
695 :
696 : struct {
697 : char snapshots_path[ PATH_MAX ];
698 : int incremental_snapshots;
699 : uint min_download_speed_mibs;
700 : ulong wfs_slot;
701 : int wfs_hash_is_zero;
702 : ushort wfs_shred_version;
703 : } snapld;
704 :
705 : struct {
706 : ulong wait_for_supermajority_at_slot;
707 : fd_hash_t wait_for_supermajority_with_bank_hash;
708 : ushort expected_shred_version;
709 : ulong max_live_slots;
710 : ulong accdb_obj_id;
711 : ulong txncache_obj_id;
712 : ulong banks_obj_id;
713 : ulong shmem_obj_id; /* shared parallel snapin state */
714 : ulong max_txn_per_slot;
715 : } snapin;
716 :
717 : struct {
718 :
719 : uint bind_address;
720 : ushort bind_port;
721 :
722 : ushort expected_shred_version;
723 : ulong entrypoints_cnt;
724 : char entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
725 : } ipecho;
726 :
727 : struct {
728 : ulong max_live_slots;
729 : ulong txncache_obj_id;
730 : ulong progcache_obj_id;
731 : ulong accdb_obj_id;
732 : ulong bpf_frames_obj_id;
733 : int report_runtime_diffs;
734 : } execle;
735 :
736 : struct {
737 : int validate_genesis_hash;
738 : int allow_download;
739 :
740 : ushort expected_shred_version;
741 : ulong entrypoints_cnt;
742 : char entrypoints[ FD_TOPO_GOSSIP_ENTRYPOINTS_MAX ][ FD_HOSTPORT_BUF_MAX ];
743 :
744 : int has_expected_genesis_hash;
745 : uchar expected_genesis_hash[ 32UL ];
746 :
747 : char genesis_path[ PATH_MAX ];
748 :
749 : uint target_gid;
750 : uint target_uid;
751 :
752 : ulong max_live_slots;
753 : ulong accdb_obj_id;
754 : ulong max_message_size;
755 : } genesi;
756 :
757 : struct {
758 : ulong capture_start_slot;
759 : char solcap_capture[ PATH_MAX ];
760 : int recent_only;
761 : ulong recent_slots_per_file;
762 : } solcap;
763 :
764 : struct {
765 : ulong accdb_obj_id;
766 : ulong accdb_epoch_obj_id;
767 : ulong visited_set_obj_id;
768 : ulong banks_obj_id;
769 : ulong zp_fseq_id;
770 : ulong txncache_obj_id;
771 : ulong max_accounts;
772 : ulong max_live_slots;
773 : ulong max_txn_per_slot;
774 : uint max_full_snapshots_to_keep;
775 : char snapshots_path[ PATH_MAX ];
776 : uint max_incremental_snapshots_to_keep;
777 : } snapmk;
778 :
779 : struct {
780 : ulong accdb_obj_id;
781 : ulong accdb_epoch_obj_id;
782 : ulong visited_set_obj_id;
783 : ulong zp_fseq_id;
784 : ulong max_live_slots;
785 : uint snap_fd_cnt;
786 : } snapzp;
787 :
788 : struct {
789 : ulong accdb_obj_id;
790 : } snaprd;
791 :
792 : struct {
793 : ulong snap_max;
794 : ulong conn_max;
795 : uint io_worker_cnt;
796 : ulong idle_timeout_millis;
797 : ulong send_timeout_millis;
798 : ulong send_buffer_size_kib;
799 : fd_ip6_addr_t listen_addr;
800 : ushort listen_port;
801 : } snapsv;
802 : };
803 : };
804 :
805 : typedef struct fd_topo_tile fd_topo_tile_t;
806 :
807 : typedef struct {
808 : ulong id;
809 : char name[ 14UL ]; /* object type */
810 : ulong wksp_id;
811 :
812 : /* Optional label for object */
813 : char label[ 13UL ]; /* object label */
814 : ulong label_idx; /* index of object for this label (ULONG_MAX if not labelled) */
815 :
816 : ulong offset;
817 : ulong footprint;
818 : } fd_topo_obj_t;
819 :
820 : /* An fd_topo_t represents the overall structure of a Firedancer
821 : configuration, describing all the workspaces, tiles, and links
822 : between them. */
823 : struct fd_topo {
824 : char app_name[ 256UL ];
825 : uchar failover_junk[ 32 ]; /* public half of the junk key generated at boot for failover, zero without failover */
826 : uchar props[ 32768UL ];
827 :
828 : ulong sleep_obj_id;
829 :
830 : ulong wksp_cnt;
831 : ulong link_cnt;
832 : ulong tile_cnt;
833 : ulong obj_cnt;
834 :
835 : fd_topo_wksp_t workspaces[ FD_TOPO_MAX_WKSPS ];
836 : fd_topo_link_t links[ FD_TOPO_MAX_LINKS ];
837 : fd_topo_tile_t tiles[ FD_TOPO_MAX_TILES ];
838 : fd_topo_obj_t objs[ FD_TOPO_MAX_OBJS ];
839 :
840 : ulong blocklist_cores_cnt;
841 : ulong blocklist_cores_cpu_idx[ FD_TILE_MAX ];
842 :
843 : ulong max_page_size; /* 2^21 or 2^30 */
844 : ulong gigantic_page_threshold; /* see [hugetlbfs.gigantic_page_threshold_mib]*/
845 :
846 : /* Rendered configuration documents for the boot telemetry event,
847 : filled by the app during topology construction. */
848 : ulong resolved_config_json_len;
849 : char resolved_config_json[ 262144UL ];
850 : ulong user_config_json_len;
851 : char user_config_json[ 131072UL ];
852 :
853 : ulong layout_hash;
854 : };
855 : typedef struct fd_topo fd_topo_t;
856 :
857 : typedef struct {
858 : char const * name;
859 :
860 : int keep_host_networking;
861 : int allow_connect;
862 : int allow_renameat;
863 : ulong rlimit_file_cnt;
864 : ulong rlimit_address_space;
865 : ulong rlimit_data;
866 : ulong rlimit_nproc;
867 : int for_tpool;
868 :
869 : ulong (*max_event_sz )( fd_topo_tile_t const * tile );
870 : ulong (*populate_allowed_seccomp)( fd_topo_t const * topo, fd_topo_tile_t const * tile, ulong out_cnt, struct sock_filter * out );
871 : ulong (*populate_allowed_fds )( fd_topo_t const * topo, fd_topo_tile_t const * tile, ulong out_fds_sz, int * out_fds );
872 : ulong (*scratch_align )( void );
873 : ulong (*scratch_footprint )( fd_topo_tile_t const * tile );
874 : ulong (*loose_footprint )( fd_topo_tile_t const * tile );
875 : void (*privileged_init )( fd_topo_t const * topo, fd_topo_tile_t const * tile );
876 : void (*unprivileged_init )( fd_topo_t const * topo, fd_topo_tile_t const * tile );
877 : void (*run )( fd_topo_t * topo, fd_topo_tile_t * tile );
878 : ulong (*rlimit_file_cnt_fn )( fd_topo_t const * topo, fd_topo_tile_t const * tile );
879 : } fd_topo_run_tile_t;
880 :
881 : struct fd_topo_obj_callbacks {
882 : char const * name;
883 : ulong (* footprint )( fd_topo_t const * topo, fd_topo_obj_t const * obj );
884 : ulong (* align )( fd_topo_t const * topo, fd_topo_obj_t const * obj );
885 : ulong (* loose )( fd_topo_t const * topo, fd_topo_obj_t const * obj );
886 : void (* new )( fd_topo_t const * topo, fd_topo_obj_t const * obj );
887 : };
888 :
889 : typedef struct fd_topo_obj_callbacks fd_topo_obj_callbacks_t;
890 :
891 : FD_PROTOTYPES_BEGIN
892 :
893 : FD_FN_CONST static inline ulong
894 0 : fd_topo_workspace_align( void ) {
895 : /* This needs to be the max( align ) of all the child members that
896 : could be aligned into this workspace, otherwise our footprint
897 : calculation will not be correct. For now just set to 4096 but this
898 : should probably be calculated dynamically, or we should reduce
899 : those child aligns if we can. */
900 0 : return 4096UL;
901 0 : }
902 :
903 : void *
904 : fd_topo_obj_laddr( fd_topo_t const * topo,
905 : ulong obj_id );
906 :
907 : /* Returns a pointer in the local address space to the base address of
908 : the workspace out of which the given object was allocated. */
909 :
910 : static inline void *
911 : fd_topo_obj_wksp_base( fd_topo_t const * topo,
912 0 : ulong obj_id ) {
913 0 : FD_TEST( obj_id<FD_TOPO_MAX_OBJS );
914 0 : fd_topo_obj_t const * obj = &topo->objs[ obj_id ];
915 0 : FD_TEST( obj->id == obj_id );
916 0 : ulong const wksp_id = obj->wksp_id;
917 :
918 0 : FD_TEST( wksp_id<FD_TOPO_MAX_WKSPS );
919 0 : fd_topo_wksp_t const * wksp = &topo->workspaces[ wksp_id ];
920 0 : FD_TEST( wksp->id == wksp_id );
921 0 : return wksp->wksp;
922 0 : }
923 :
924 : FD_FN_PURE static inline ulong
925 : fd_topo_tile_name_cnt( fd_topo_t const * topo,
926 0 : char const * name ) {
927 0 : ulong cnt = 0;
928 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
929 0 : if( FD_UNLIKELY( !strcmp( topo->tiles[ i ].name, name ) ) ) cnt++;
930 0 : }
931 0 : return cnt;
932 0 : }
933 :
934 : /* Finds the workspace of a given name in the topology. Returns
935 : ULONG_MAX if there is no such workspace. There can be at most one
936 : workspace of a given name. */
937 :
938 : FD_FN_PURE static inline ulong
939 : fd_topo_find_wksp( fd_topo_t const * topo,
940 0 : char const * name ) {
941 0 : for( ulong i=0; i<topo->wksp_cnt; i++ ) {
942 0 : if( FD_UNLIKELY( !strcmp( topo->workspaces[ i ].name, name ) ) ) return i;
943 0 : }
944 0 : return ULONG_MAX;
945 0 : }
946 :
947 : /* Find the tile of a given name and kind_id in the topology, there will
948 : be at most one such tile, since kind_id is unique among the name.
949 : Returns ULONG_MAX if there is no such tile. */
950 :
951 : FD_FN_PURE static inline ulong
952 : fd_topo_find_tile( fd_topo_t const * topo,
953 : char const * name,
954 0 : ulong kind_id ) {
955 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
956 0 : if( FD_UNLIKELY( !strcmp( topo->tiles[ i ].name, name ) ) && topo->tiles[ i ].kind_id == kind_id ) return i;
957 0 : }
958 0 : return ULONG_MAX;
959 0 : }
960 :
961 : /* Find the link of a given name and kind_id in the topology, there will
962 : be at most one such link, since kind_id is unique among the name.
963 : Returns ULONG_MAX if there is no such link. */
964 :
965 : FD_FN_PURE static inline ulong
966 : fd_topo_find_link( fd_topo_t const * topo,
967 : char const * name,
968 0 : ulong kind_id ) {
969 0 : for( ulong i=0; i<topo->link_cnt; i++ ) {
970 0 : if( FD_UNLIKELY( !strcmp( topo->links[ i ].name, name ) ) && topo->links[ i ].kind_id == kind_id ) return i;
971 0 : }
972 0 : return ULONG_MAX;
973 0 : }
974 :
975 : FD_FN_PURE static inline ulong
976 : fd_topo_find_tile_in_link( fd_topo_t const * topo,
977 : fd_topo_tile_t const * tile,
978 : char const * name,
979 0 : ulong kind_id ) {
980 0 : for( ulong i=0; i<tile->in_cnt; i++ ) {
981 0 : if( FD_UNLIKELY( !strcmp( topo->links[ tile->in_link_id[ i ] ].name, name ) )
982 0 : && topo->links[ tile->in_link_id[ i ] ].kind_id == kind_id ) return i;
983 0 : }
984 0 : return ULONG_MAX;
985 0 : }
986 :
987 : FD_FN_PURE static inline ulong
988 : fd_topo_find_tile_out_link( fd_topo_t const * topo,
989 : fd_topo_tile_t const * tile,
990 : char const * name,
991 0 : ulong kind_id ) {
992 0 : for( ulong i=0; i<tile->out_cnt; i++ ) {
993 0 : if( FD_UNLIKELY( !strcmp( topo->links[ tile->out_link_id[ i ] ].name, name ) )
994 0 : && topo->links[ tile->out_link_id[ i ] ].kind_id == kind_id ) return i;
995 0 : }
996 0 : return ULONG_MAX;
997 0 : }
998 :
999 : /* Find the id of the tile which is a producer for the given link. If
1000 : no tile is a producer for the link, returns ULONG_MAX. This should
1001 : not be possible for a well formed and validated topology. */
1002 : FD_FN_PURE static inline ulong
1003 : fd_topo_find_link_producer( fd_topo_t const * topo,
1004 0 : fd_topo_link_t const * link ) {
1005 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
1006 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1007 :
1008 0 : for( ulong j=0; j<tile->out_cnt; j++ ) {
1009 0 : if( FD_UNLIKELY( tile->out_link_id[ j ] == link->id ) ) return i;
1010 0 : }
1011 0 : }
1012 0 : return ULONG_MAX;
1013 0 : }
1014 :
1015 : /* Find the id of the tile which is a consumer of the given link. If
1016 : no tile is a consumer of the link, returns ULONG_MAX. */
1017 : FD_FN_PURE static inline ulong
1018 : fd_topo_find_link_consumer( fd_topo_t const * topo,
1019 0 : fd_topo_link_t const * link ) {
1020 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
1021 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1022 :
1023 0 : for( ulong j=0; j<tile->in_cnt; j++ ) {
1024 0 : if( FD_UNLIKELY( tile->in_link_id[ j ] == link->id ) ) return i;
1025 0 : }
1026 0 : }
1027 0 : return ULONG_MAX;
1028 0 : }
1029 :
1030 : /* Given a link, count the number of consumers of that link among all
1031 : the tiles in the topology. */
1032 : FD_FN_PURE static inline ulong
1033 : fd_topo_link_consumer_cnt( fd_topo_t const * topo,
1034 0 : fd_topo_link_t const * link ) {
1035 0 : ulong cnt = 0;
1036 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
1037 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1038 0 : for( ulong j=0; j<tile->in_cnt; j++ ) {
1039 0 : if( FD_UNLIKELY( tile->in_link_id[ j ] == link->id ) ) cnt++;
1040 0 : }
1041 0 : }
1042 :
1043 0 : return cnt;
1044 0 : }
1045 :
1046 : /* Given a link, count the number of reliable consumers of that link
1047 : among all the tiles in the topology. */
1048 : FD_FN_PURE static inline ulong
1049 : fd_topo_link_reliable_consumer_cnt( fd_topo_t const * topo,
1050 0 : fd_topo_link_t const * link ) {
1051 0 : ulong cnt = 0;
1052 0 : for( ulong i=0; i<topo->tile_cnt; i++ ) {
1053 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1054 0 : for( ulong j=0; j<tile->in_cnt; j++ ) {
1055 0 : if( FD_UNLIKELY( tile->in_link_id[ j ] == link->id && tile->in_link_reliable[ j ] ) ) cnt++;
1056 0 : }
1057 0 : }
1058 0 :
1059 0 : return cnt;
1060 0 : }
1061 :
1062 : FD_FN_PURE static inline ulong
1063 : fd_topo_tile_consumer_cnt( fd_topo_t const * topo,
1064 0 : fd_topo_tile_t const * tile ) {
1065 0 : (void)topo;
1066 0 : return tile->out_cnt;
1067 0 : }
1068 :
1069 : FD_FN_PURE static inline ulong
1070 : fd_topo_tile_reliable_consumer_cnt( fd_topo_t const * topo,
1071 0 : fd_topo_tile_t const * tile ) {
1072 0 : ulong reliable_cons_cnt = 0UL;
1073 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
1074 0 : fd_topo_tile_t const * consumer_tile = &topo->tiles[ i ];
1075 0 : for( ulong j=0UL; j<consumer_tile->in_cnt; j++ ) {
1076 0 : for( ulong k=0UL; k<tile->out_cnt; k++ ) {
1077 0 : if( FD_UNLIKELY( consumer_tile->in_link_id[ j ]==tile->out_link_id[ k ] && consumer_tile->in_link_reliable[ j ] ) ) {
1078 0 : reliable_cons_cnt++;
1079 0 : }
1080 0 : }
1081 0 : }
1082 0 : }
1083 0 : return reliable_cons_cnt;
1084 0 : }
1085 :
1086 : FD_FN_PURE static inline ulong
1087 : fd_topo_tile_producer_cnt( fd_topo_t const * topo,
1088 0 : fd_topo_tile_t const * tile ) {
1089 0 : (void)topo;
1090 0 : ulong in_cnt = 0UL;
1091 0 : for( ulong i=0UL; i<tile->in_cnt; i++ ) {
1092 0 : if( FD_UNLIKELY( !tile->in_link_poll[ i ] ) ) continue;
1093 0 : in_cnt++;
1094 0 : }
1095 0 : return in_cnt;
1096 0 : }
1097 :
1098 : FD_FN_PURE FD_FN_UNUSED static ulong
1099 : fd_topo_obj_cnt( fd_topo_t const * topo,
1100 : char const * obj_type,
1101 0 : char const * label ) {
1102 0 : ulong cnt = 0UL;
1103 0 : for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
1104 0 : fd_topo_obj_t const * obj = &topo->objs[ i ];
1105 0 : if( strncmp( obj->name, obj_type, sizeof(obj->name) ) ) continue;
1106 0 : if( label &&
1107 0 : strncmp( obj->label, label, sizeof(obj->label) ) ) continue;
1108 0 : cnt++;
1109 0 : }
1110 0 : return cnt;
1111 0 : }
1112 :
1113 : FD_FN_PURE FD_FN_UNUSED static fd_topo_obj_t const *
1114 : fd_topo_find_obj( fd_topo_t const * topo,
1115 : char const * obj_type,
1116 : char const * label,
1117 0 : ulong label_idx ) {
1118 0 : for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
1119 0 : fd_topo_obj_t const * obj = &topo->objs[ i ];
1120 0 : if( strncmp( obj->name, obj_type, sizeof(obj->name) ) ) continue;
1121 0 : if( label &&
1122 0 : strncmp( obj->label, label, sizeof(obj->label) ) ) continue;
1123 0 : if( label_idx != ULONG_MAX && obj->label_idx != label_idx ) continue;
1124 0 : return obj;
1125 0 : }
1126 0 : return NULL;
1127 0 : }
1128 :
1129 : FD_FN_PURE FD_FN_UNUSED static fd_topo_obj_t const *
1130 : fd_topo_find_tile_obj( fd_topo_t const * topo,
1131 : fd_topo_tile_t const * tile,
1132 0 : char const * obj_type ) {
1133 0 : for( ulong i=0UL; i<(tile->uses_obj_cnt); i++ ) {
1134 0 : fd_topo_obj_t const * obj = &topo->objs[ tile->uses_obj_id[ i ] ];
1135 0 : if( strncmp( obj->name, obj_type, sizeof(obj->name) ) ) continue;
1136 0 : return obj;
1137 0 : }
1138 0 : return NULL;
1139 0 : }
1140 :
1141 : /* Join (map into the process) all shared memory (huge/gigantic pages)
1142 : needed by the tile, in the given topology. All memory associated
1143 : with the tile (aka. used by links that the tile either produces to or
1144 : consumes from, or used by the tile itself for its cnc) will be
1145 : attached (mapped into the process).
1146 :
1147 : This is needed to play nicely with the sandbox. Once a process is
1148 : sandboxed we can no longer map any memory. */
1149 : void
1150 : fd_topo_join_tile_workspaces( fd_topo_t * topo,
1151 : fd_topo_tile_t * tile,
1152 : int core_dump_level );
1153 :
1154 : /* Join (map into the process) the shared memory (huge/gigantic pages)
1155 : for the given workspace. Mode is one of
1156 : FD_SHMEM_JOIN_MODE_READ_WRITE or FD_SHMEM_JOIN_MODE_READ_ONLY and
1157 : determines the prot argument that will be passed to mmap when mapping
1158 : the pages in (PROT_WRITE or PROT_READ respectively).
1159 :
1160 : Dump should be set to 1 if the workspace memory should be dumpable
1161 : when the process crashes, or 0 if not. */
1162 : void
1163 : fd_topo_join_workspace( fd_topo_t * topo,
1164 : fd_topo_wksp_t * wksp,
1165 : int mode,
1166 : int dump );
1167 :
1168 : /* Join (map into the process) all shared memory (huge/gigantic pages)
1169 : needed by all tiles in the topology. Mode is one of
1170 : FD_SHMEM_JOIN_MODE_READ_WRITE or FD_SHMEM_JOIN_MODE_READ_ONLY and
1171 : determines the prot argument that will be passed to mmap when
1172 : mapping the pages in (PROT_WRITE or PROT_READ respectively). */
1173 : void
1174 : fd_topo_join_workspaces( fd_topo_t * topo,
1175 : int mode,
1176 : int core_dump_level );
1177 :
1178 : /* Leave (unmap from the process) the shared memory needed for the
1179 : given workspace in the topology, if it was previously mapped.
1180 :
1181 : topo and wksp are assumed non-NULL. It is OK if the workspace
1182 : has not been previously joined, in which case this is a no-op. */
1183 :
1184 : void
1185 : fd_topo_leave_workspace( fd_topo_t * topo,
1186 : fd_topo_wksp_t * wksp );
1187 :
1188 : /* Leave (unmap from the process) all shared memory needed by all
1189 : tiles in the topology, if each of them was mapped.
1190 :
1191 : topo is assumed non-NULL. Only workspaces which were previously
1192 : joined are unmapped. */
1193 :
1194 : void
1195 : fd_topo_leave_workspaces( fd_topo_t * topo );
1196 :
1197 : /* Create the given workspace needed by the topology on the system.
1198 : This does not "join" the workspaces (map their memory into the
1199 : process), but only creates the .wksp file and formats it correctly
1200 : as a workspace.
1201 :
1202 : Returns 0 on success and -1 on failure, with errno set to the error.
1203 : The only reason for failure currently that will be returned is
1204 : ENOMEM, as other unexpected errors will cause the program to exit.
1205 :
1206 : If update_existing is 1, the workspace will not be created from
1207 : scratch but it will be assumed that it already exists from a prior
1208 : run and needs to be maybe resized and then have the header
1209 : structures reinitialized. This can save a very expensive operation
1210 : of zeroing all of the workspace pages. This is dangerous in
1211 : production because it can leave stray memory from prior runs around,
1212 : and should only be used in development environments. */
1213 :
1214 : int
1215 : fd_topo_create_workspace( fd_topo_t * topo,
1216 : fd_topo_wksp_t * wksp,
1217 : int update_existing );
1218 :
1219 : /* Join the standard IPC objects needed by the topology of this particular
1220 : tile */
1221 :
1222 : void
1223 : fd_topo_fill_tile( fd_topo_t * topo,
1224 : fd_topo_tile_t * tile );
1225 :
1226 : /* Same as fd_topo_fill_tile but fills in all the objects for a
1227 : particular workspace with the given mode. */
1228 : void
1229 : fd_topo_workspace_fill( fd_topo_t * topo,
1230 : fd_topo_wksp_t * wksp );
1231 :
1232 : /* Apply a new function to every object that is resident in the given
1233 : workspace in the topology. */
1234 :
1235 : void
1236 : fd_topo_wksp_new( fd_topo_t const * topo,
1237 : fd_topo_wksp_t const * wksp,
1238 : fd_topo_obj_callbacks_t ** callbacks );
1239 :
1240 : /* Same as fd_topo_fill_tile but fills in all tiles in the topology. */
1241 :
1242 : void
1243 : fd_topo_fill( fd_topo_t * topo );
1244 :
1245 : /* fd_topo_tile_stack_join joins a huge page optimized stack for the
1246 : provided tile. The stack is assumed to already exist at a known
1247 : path in the hugetlbfs mount. */
1248 :
1249 : void *
1250 : fd_topo_tile_stack_join( char const * app_name,
1251 : char const * tile_name,
1252 : ulong tile_kind_id );
1253 :
1254 : /* fd_topo_run_single_process runs all the tiles in a single process
1255 : (the calling process). This spawns a thread for each tile, switches
1256 : that thread to the given UID and GID and then runs the tile in it.
1257 : Each thread will never exit, as tiles are expected to run forever.
1258 : An error is logged and the application will exit if a tile exits.
1259 : The function itself does return after spawning all the threads.
1260 :
1261 : The threads will not be sandboxed in any way, except switching to the
1262 : provided UID and GID, so they will share the same address space, and
1263 : not have any seccomp restrictions or use any Linux namespaces. The
1264 : calling thread will also switch to the provided UID and GID before
1265 : it returns.
1266 :
1267 : This is useful for tooling and debugging, but is not how the main
1268 : production Firedancer process runs. For production, each tile is run
1269 : in its own address space with a separate process and full security
1270 : sandbox. */
1271 :
1272 : void
1273 : fd_topo_run_single_process( fd_topo_t * topo,
1274 : uint uid,
1275 : uint gid,
1276 : fd_topo_run_tile_t (* tile_run )( fd_topo_tile_t const * tile ) );
1277 :
1278 : /* fd_topo_run_tile runs the given tile directly within the current
1279 : process (and thread). The function will never return, as tiles are
1280 : expected to run forever. An error is logged and the application will
1281 : exit if the tile exits.
1282 :
1283 : The sandbox argument determines if the current process will be
1284 : sandboxed fully before starting the tile. The thread will switch to
1285 : the UID and GID provided before starting the tile, even if the thread
1286 : is not being sandboxed. Although POSIX specifies that all threads in
1287 : a process must share a UID and GID, this is not the case on Linux.
1288 : The thread will switch to the provided UID and GID without switching
1289 : the other threads in the process.
1290 :
1291 : If keep_controlling_terminal is set to 0, and the sandbox is enabled
1292 : the controlling terminal will be detached as an additional sandbox
1293 : measure, but you will not be able to send Ctrl+C or other signals
1294 : from the terminal. See fd_sandbox.h for more information.
1295 :
1296 : The allow_fd argument is only used if sandbox is true, and is a file
1297 : descriptor which will be allowed to exist in the process. Normally
1298 : the sandbox code rejects and aborts if there is an unexpected file
1299 : descriptor present on boot. This is helpful to allow a parent
1300 : process to be notified on termination of the tile by waiting for a
1301 : pipe file descriptor to get closed.
1302 :
1303 : wait and debugger are both used in debugging. If wait is non-NULL,
1304 : the runner will wait until the value pointed to by wait is non-zero
1305 : before launching the tile. Likewise, if debugger is non-NULL, the
1306 : runner will wait until a debugger is attached before setting the
1307 : value pointed to by debugger to non-zero. These are intended to be
1308 : used as a pair, where many tiles share a waiting reference, and then
1309 : one of the tiles (a tile you want to attach the debugger to) has the
1310 : same reference provided as the debugger, so all tiles will stop and
1311 : wait for the debugger to attach to it before proceeding. */
1312 :
1313 : void
1314 : fd_topo_run_tile( fd_topo_t * topo,
1315 : fd_topo_tile_t * tile,
1316 : int sandbox,
1317 : int keep_controlling_terminal,
1318 : int dumpable,
1319 : uint uid,
1320 : uint gid,
1321 : int allow_fd,
1322 : fd_topo_run_tile_t * tile_run );
1323 :
1324 : /* This is for determining the value of RLIMIT_MLOCK that we need to
1325 : successfully run all tiles in separate processes. The value returned
1326 : is the maximum amount of memory that will be locked with mlock() by
1327 : any individual process in the tree. Specifically, if we have three
1328 : tile processes, and they each need to lock 5, 9, and 2 MiB of memory
1329 : respectively, RLIMIT_MLOCK needs to be 9 MiB to allow all three
1330 : process mlock() calls to succeed.
1331 :
1332 : Tiles lock memory in four ways. Any workspace they are using, they
1333 : lock the entire workspace. Then each tile uses huge pages for the
1334 : stack which are also locked, and finally some tiles use private
1335 : locked mmaps outside the workspace for storing key material. Every
1336 : tile also locks the executable code. The results here include all of
1337 : this memory together.
1338 :
1339 : The result is not necessarily the amount of memory used by the tile
1340 : process, although it will be quite close. Tiles could potentially
1341 : allocate memory (eg, with brk) without needing to lock it, which
1342 : would not need to included, and some kernel memory that tiles cause
1343 : to be allocated (for example XSK buffers) is also not included. The
1344 : actual amount of memory used will not be less than this value. */
1345 : FD_FN_PURE ulong
1346 : fd_topo_mlock_max_tile( fd_topo_t const * topo );
1347 :
1348 : /* fd_topo_mlock_code locks the code, rodata and initialized data of
1349 : every loaded ELF object into DRAM, so tiles cannot stall on major
1350 : faults when the page cache is evicted under memory pressure. */
1351 :
1352 : void
1353 : fd_topo_mlock_code( void );
1354 :
1355 : /* fd_topo_code_footprint returns the bytes that would be locked by
1356 : fd_topo_mlock_code, either the read-only segments (writable==0),
1357 : which are page cache shared by all tiles, or the writable segments
1358 : (writable==1), which are private to each tile process. */
1359 :
1360 : ulong
1361 : fd_topo_code_footprint( int writable );
1362 :
1363 : /* Same as fd_topo_mlock_max_tile, but for loading the entire topology
1364 : into one process, rather than a separate process per tile. This is
1365 : used, for example, by the configuration code when it creates all the
1366 : workspaces, or the monitor that maps the entire system into one
1367 : address space. */
1368 : FD_FN_PURE ulong
1369 : fd_topo_mlock( fd_topo_t const * topo );
1370 :
1371 : /* This returns the number of gigantic pages needed by the topology on
1372 : the provided numa node. It includes pages needed by the workspaces,
1373 : as well as additional allocations like huge pages for process stacks
1374 : and private key storage. */
1375 :
1376 : FD_FN_PURE ulong
1377 : fd_topo_gigantic_page_cnt( fd_topo_t const * topo,
1378 : ulong numa_idx );
1379 :
1380 : /* This returns the number of huge pages in the application needed by
1381 : the topology on the provided numa node. It includes pages needed by
1382 : things placed in the hugetlbfs (workspaces, process stacks). If
1383 : include_anonymous is true, it also includes anonymous hugepages which
1384 : are needed but are not placed in the hugetlbfs. */
1385 :
1386 : FD_FN_PURE ulong
1387 : fd_topo_huge_page_cnt( fd_topo_t const * topo,
1388 : ulong numa_idx,
1389 : int include_anonymous );
1390 :
1391 : /* Returns the number of normal (4 KiB) pages needed by the topology
1392 : for extra allocations like private key storage and XSK rings, plus
1393 : the locked code (read-only segments once, writable ones per tile). */
1394 :
1395 : FD_FN_PURE ulong
1396 : fd_topo_normal_page_cnt( fd_topo_t const * topo );
1397 :
1398 : /* Prints a message describing the topology to an output stream. If
1399 : stdout is true, will be written to stdout, otherwise will be written
1400 : as a NOTICE log message to the log file. */
1401 : void
1402 : fd_topo_print_log( int stdout,
1403 : fd_topo_t * topo );
1404 :
1405 : /* fd_topo_print_json prints the same topology description as
1406 : fd_topo_print_log to stdout, as a JSON document. */
1407 : void
1408 : fd_topo_print_json( fd_topo_t * topo );
1409 :
1410 : FD_PROTOTYPES_END
1411 :
1412 : #endif /* HEADER_fd_src_disco_topo_fd_topo_h */
|