Line data Source code
1 : #include "../shared/fd_config.h"
2 :
3 : #include "../../disco/net/fd_net_tile.h"
4 : #include "../../disco/quic/fd_tpu.h"
5 : #include "../../disco/tiles.h"
6 : #include "../../disco/topo/fd_topob.h"
7 : #include "../../disco/topo/fd_cpu_topo.h"
8 : #include "../../disco/plugin/fd_plugin.h"
9 : #include "../../util/pod/fd_pod_format.h"
10 : #include "../../util/net/fd_ip4.h"
11 : #include "../../util/tile/fd_tile_private.h"
12 :
13 : extern fd_topo_obj_callbacks_t * CALLBACKS[];
14 :
15 : static void
16 0 : parse_ip_port( const char * name, const char * ip_port, fd_topo_ip_port_t *parsed_ip_port) {
17 0 : char buf[ sizeof( "255.255.255.255:65536" ) ];
18 0 : memcpy( buf, ip_port, sizeof( buf ) );
19 0 : char *ip_end = strchr( buf, ':' );
20 0 : if( FD_UNLIKELY( !ip_end ) )
21 0 : FD_LOG_ERR(( "[%s] must in the form ip:port", name ));
22 0 : *ip_end = '\0';
23 :
24 0 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( buf, &( parsed_ip_port->ip ) ) ) ) {
25 0 : FD_LOG_ERR(( "could not parse IP %s in [%s]", buf, name ));
26 0 : }
27 :
28 0 : parsed_ip_port->port = fd_cstr_to_ushort( ip_end+1 );
29 0 : if( FD_UNLIKELY( !parsed_ip_port->port ) )
30 0 : FD_LOG_ERR(( "could not parse port %s in [%s]", ip_end+1, name ));
31 0 : }
32 :
33 : void
34 : fd_topo_configure_tile( fd_topo_tile_t * tile,
35 : fd_config_t * config );
36 :
37 : void
38 3 : fd_topo_initialize( config_t * config ) {
39 3 : ulong net_tile_cnt = config->layout.net_tile_count;
40 3 : ulong quic_tile_cnt = config->layout.quic_tile_count;
41 3 : ulong verify_tile_cnt = config->layout.verify_tile_count;
42 3 : ulong resolv_tile_cnt = config->layout.resolv_tile_count;
43 3 : ulong bank_tile_cnt = config->layout.bank_tile_count;
44 3 : ulong shred_tile_cnt = config->layout.shred_tile_count;
45 :
46 3 : fd_topo_t * topo = { fd_topob_new( &config->topo, config->name ) };
47 3 : topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
48 3 : topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
49 :
50 : /* topo, name */
51 3 : fd_topob_wksp( topo, "metric_in" );
52 3 : fd_topob_wksp( topo, "net_quic" );
53 3 : fd_topob_wksp( topo, "net_shred" );
54 3 : fd_topob_wksp( topo, "quic_verify" );
55 3 : fd_topob_wksp( topo, "verify_dedup" );
56 3 : fd_topob_wksp( topo, "dedup_resolv" );
57 3 : fd_topob_wksp( topo, "resolv_pack" );
58 3 : fd_topob_wksp( topo, "pack_bank" );
59 3 : fd_topob_wksp( topo, "pack_poh" );
60 3 : fd_topob_wksp( topo, "bank_pack" );
61 3 : fd_topob_wksp( topo, "bank_poh" );
62 3 : fd_topob_wksp( topo, "bank_busy" );
63 3 : fd_topob_wksp( topo, "poh_shred" );
64 3 : fd_topob_wksp( topo, "gossip_dedup" );
65 3 : fd_topob_wksp( topo, "shred_store" );
66 3 : fd_topob_wksp( topo, "stake_out" );
67 3 : fd_topob_wksp( topo, "executed_txn" );
68 :
69 3 : fd_topob_wksp( topo, "shred_sign" );
70 3 : fd_topob_wksp( topo, "sign_shred" );
71 :
72 3 : fd_topob_wksp( topo, "quic" );
73 3 : fd_topob_wksp( topo, "verify" );
74 3 : fd_topob_wksp( topo, "dedup" );
75 3 : fd_topob_wksp( topo, "resolv" );
76 3 : fd_topob_wksp( topo, "pack" );
77 3 : fd_topob_wksp( topo, "bank" );
78 3 : fd_topob_wksp( topo, "poh" );
79 3 : fd_topob_wksp( topo, "shred" );
80 3 : fd_topob_wksp( topo, "store" );
81 3 : fd_topob_wksp( topo, "sign" );
82 3 : fd_topob_wksp( topo, "metric" );
83 3 : fd_topob_wksp( topo, "cswtch" );
84 :
85 396 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
86 :
87 : /* topo, link_name, wksp_name, depth, mtu, burst */
88 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_net", "net_quic", config->net.ingress_buffer_size, FD_NET_MTU, 1UL );
89 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_net", "net_shred", 32768UL, FD_NET_MTU, 1UL );
90 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_verify", "quic_verify", config->tiles.verify.receive_buffer_size, FD_TPU_REASM_MTU, config->tiles.quic.txn_reassembly_count );
91 18 : FOR(verify_tile_cnt) fd_topob_link( topo, "verify_dedup", "verify_dedup", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU, 1UL );
92 3 : /**/ fd_topob_link( topo, "gossip_dedup", "gossip_dedup", 2048UL, FD_TPU_RAW_MTU, 1UL );
93 : /* dedup_resolv is large currently because pack can encounter stalls when running at very high throughput rates that would
94 : otherwise cause drops. */
95 3 : /**/ fd_topob_link( topo, "dedup_resolv", "dedup_resolv", 65536UL, FD_TPU_PARSED_MTU, 1UL );
96 3 : FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_pack", "resolv_pack", 65536UL, FD_TPU_RESOLVED_MTU, 1UL );
97 3 : /**/ fd_topob_link( topo, "stake_out", "stake_out", 128UL, FD_STAKE_OUT_MTU, 1UL );
98 : /* pack_bank is shared across all banks, so if one bank stalls due to complex transactions, the buffer neeeds to be large so that
99 : other banks can keep proceeding. */
100 3 : /**/ fd_topob_link( topo, "pack_bank", "pack_bank", 65536UL, USHORT_MAX, 1UL );
101 3 : /**/ fd_topob_link( topo, "pack_poh", "pack_poh", 65536UL, sizeof(fd_done_packing_t), 1UL );
102 12 : FOR(bank_tile_cnt) fd_topob_link( topo, "bank_poh", "bank_poh", 16384UL, USHORT_MAX, 1UL );
103 12 : FOR(bank_tile_cnt) fd_topob_link( topo, "bank_pack", "bank_pack", 16384UL, USHORT_MAX, 3UL );
104 3 : /**/ fd_topob_link( topo, "poh_pack", "bank_poh", 128UL, sizeof(fd_became_leader_t), 1UL );
105 3 : /**/ fd_topob_link( topo, "poh_shred", "poh_shred", 16384UL, USHORT_MAX, 2UL );
106 3 : /**/ fd_topob_link( topo, "crds_shred", "poh_shred", 128UL, 8UL + 40200UL * 38UL, 1UL );
107 3 : /**/ fd_topob_link( topo, "replay_resol", "bank_poh", 128UL, sizeof(fd_completed_bank_t), 1UL );
108 3 : /**/ fd_topob_link( topo, "executed_txn", "executed_txn", 16384UL, 64UL, 1UL );
109 : /* See long comment in fd_shred.c for an explanation about the size of this dcache. */
110 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_store", "shred_store", 65536UL, 4UL*FD_SHRED_STORE_MTU, 4UL+config->tiles.shred.max_pending_shred_sets );
111 :
112 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_sign", "shred_sign", 128UL, 32UL, 1UL );
113 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "sign_shred", "sign_shred", 128UL, 64UL, 1UL );
114 :
115 3 : ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
116 : /* Unassigned tiles will be floating, unless auto topology is enabled. */
117 3075 : for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
118 :
119 3 : int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
120 3 : int is_agave_auto_affinity = !strcmp( config->frankendancer.layout.agave_affinity, "auto" );
121 :
122 3 : if( FD_UNLIKELY( is_auto_affinity != is_agave_auto_affinity ) ) {
123 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] and [layout.agave_affinity] must both be set to 'auto' or both be set to a specific CPU affinity string." ));
124 0 : }
125 :
126 3 : fd_topo_cpus_t cpus[1];
127 3 : fd_topo_cpus_init( cpus );
128 :
129 3 : ulong affinity_tile_cnt = 0UL;
130 3 : if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_tile_private_cpus_parse( config->layout.affinity, parsed_tile_to_cpu );
131 :
132 3 : ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
133 3 : for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
134 0 : if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=cpus->cpu_cnt ) )
135 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] specifies a CPU index of %hu, but the system "
136 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
137 0 : "in the system.",
138 0 : parsed_tile_to_cpu[ i ], cpus->cpu_cnt ));
139 0 : tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
140 0 : }
141 :
142 3 : fd_topos_net_tiles( topo, config->layout.net_tile_count, &config->net, config->tiles.netlink.max_routes, config->tiles.netlink.max_peer_routes, config->tiles.netlink.max_neighbors, tile_to_cpu );
143 :
144 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_quic", i, config->net.ingress_buffer_size );
145 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_shred", i, config->net.ingress_buffer_size );
146 :
147 : /* topo, tile_name, tile_wksp, metrics_wksp, cpu_idx, is_agave, uses_keyswitch */
148 3 : FOR(quic_tile_cnt) fd_topob_tile( topo, "quic", "quic", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
149 18 : FOR(verify_tile_cnt) fd_topob_tile( topo, "verify", "verify", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
150 3 : /**/ fd_topob_tile( topo, "dedup", "dedup", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
151 3 : FOR(resolv_tile_cnt) fd_topob_tile( topo, "resolv", "resolv", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 0 );
152 3 : /**/ fd_topob_tile( topo, "pack", "pack", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, config->tiles.bundle.enabled );
153 12 : FOR(bank_tile_cnt) fd_topob_tile( topo, "bank", "bank", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 0 );
154 3 : /**/ fd_topob_tile( topo, "poh", "poh", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 1 );
155 3 : FOR(shred_tile_cnt) fd_topob_tile( topo, "shred", "shred", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
156 3 : /**/ fd_topob_tile( topo, "store", "store", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 0 );
157 3 : /**/ fd_topob_tile( topo, "sign", "sign", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
158 3 : /**/ fd_topob_tile( topo, "metric", "metric", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
159 3 : /**/ fd_topob_tile( topo, "cswtch", "cswtch", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
160 :
161 : /* topo, tile_name, tile_kind_id, fseq_wksp, link_name, link_kind_id, reliable, polled */
162 6 : for( ulong j=0UL; j<quic_tile_cnt; j++ )
163 3 : fd_topos_tile_in_net( topo, "metric_in", "quic_net", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
164 6 : for( ulong j=0UL; j<shred_tile_cnt; j++ )
165 3 : fd_topos_tile_in_net( topo, "metric_in", "shred_net", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
166 :
167 6 : FOR(quic_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
168 3 : fd_topob_tile_in( topo, "quic", i, "metric_in", "net_quic", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
169 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_verify", i );
170 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_net", i );
171 : /* All verify tiles read from all QUIC tiles, packets are round robin. */
172 36 : FOR(verify_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
173 18 : fd_topob_tile_in( topo, "verify", i, "metric_in", "quic_verify", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers, verify tiles may be overrun */
174 18 : FOR(verify_tile_cnt) fd_topob_tile_out( topo, "verify", i, "verify_dedup", i );
175 : /* Declare the single gossip link before the variable length verify-dedup links so we could have a compile-time index to the gossip link. */
176 3 : /**/ fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "gossip_dedup", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
177 18 : FOR(verify_tile_cnt) fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "verify_dedup", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
178 3 : /**/ fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "executed_txn", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
179 3 : /**/ fd_topob_tile_out( topo, "dedup", 0UL, "dedup_resolv", 0UL );
180 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "dedup_resolv", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
181 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "replay_resol", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
182 3 : FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv", i, "resolv_pack", i );
183 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "resolv_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
184 : /* The PoH to pack link is reliable, and must be. The fragments going
185 : across here are "you became leader" which pack must respond to
186 : by publishing microblocks, otherwise the leader TPU will hang
187 : forever.
188 :
189 : It's marked as unreliable since otherwise we have a reliable credit
190 : loop which will also starve the pack tile. This is OK because we
191 : will never send more than one leader message until the pack tile
192 : must acknowledge it with a packing done frag, so there will be at
193 : most one in flight at any time. */
194 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "poh_pack", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
195 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "executed_txn", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
196 3 : fd_topob_tile_out( topo, "pack", 0UL, "pack_bank", 0UL );
197 3 : fd_topob_tile_out( topo, "pack", 0UL, "pack_poh", 0UL );
198 12 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "bank", i, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
199 12 : FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_poh", i );
200 12 : FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_pack", i );
201 12 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "bank_poh", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
202 3 : if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) )
203 12 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "bank_pack", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
204 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
205 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "pack_poh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
206 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_shred", 0UL );
207 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_pack", 0UL );
208 6 : FOR(shred_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
209 3 : fd_topob_tile_in( topo, "shred", i, "metric_in", "net_shred", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
210 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "poh_shred", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
211 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
212 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "crds_shred", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
213 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_store", i );
214 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_net", i );
215 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "store", 0UL, "metric_in", "shred_store", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
216 :
217 : /* Sign links don't need to be reliable because they are synchronous,
218 : so there's at most one fragment in flight at a time anyway. The
219 : sign links are also not polled by fd_stem, instead the tiles will
220 : read the sign responses out of band in a dedicated spin loop. */
221 :
222 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
223 3 : /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "shred_sign", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
224 3 : /**/ fd_topob_tile_out( topo, "shred", i, "shred_sign", i );
225 3 : /**/ fd_topob_tile_in( topo, "shred", i, "metric_in", "sign_shred", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
226 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_shred", i );
227 3 : }
228 :
229 : /* PoH tile represents the Agave address space, so it's
230 : responsible for publishing Agave provided data to
231 : these links. */
232 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "gossip_dedup", 0UL );
233 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "stake_out", 0UL );
234 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "crds_shred", 0UL );
235 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "replay_resol", 0UL );
236 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "executed_txn", 0UL );
237 :
238 : /* For now the only plugin consumer is the GUI */
239 3 : int plugins_enabled = config->tiles.gui.enabled;
240 3 : if( FD_LIKELY( plugins_enabled ) ) {
241 3 : fd_topob_wksp( topo, "plugin_in" );
242 3 : fd_topob_wksp( topo, "plugin_out" );
243 3 : fd_topob_wksp( topo, "plugin" );
244 :
245 : /**/ fd_topob_link( topo, "plugin_out", "plugin_out", 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
246 3 : /**/ fd_topob_link( topo, "replay_plugi", "plugin_in", 128UL, 4098*8UL, 1UL );
247 3 : /**/ fd_topob_link( topo, "gossip_plugi", "plugin_in", 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
248 3 : /**/ fd_topob_link( topo, "poh_plugin", "plugin_in", 128UL, 16UL, 1UL );
249 3 : /**/ fd_topob_link( topo, "startp_plugi", "plugin_in", 128UL, 56UL, 1UL );
250 3 : /**/ fd_topob_link( topo, "votel_plugin", "plugin_in", 128UL, 8UL, 1UL );
251 3 : /**/ fd_topob_link( topo, "valcfg_plugi", "plugin_in", 128UL, 608UL, 1UL );
252 :
253 : /**/ fd_topob_tile( topo, "plugin", "plugin", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
254 :
255 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "replay_plugi", 0UL );
256 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "gossip_plugi", 0UL );
257 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_plugin", 0UL );
258 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "startp_plugi", 0UL );
259 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "votel_plugin", 0UL );
260 3 : /**/ fd_topob_tile_out( topo, "plugin", 0UL, "plugin_out", 0UL );
261 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "valcfg_plugi", 0UL );
262 :
263 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "replay_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
264 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "gossip_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
265 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
266 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "poh_plugin", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
267 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "startp_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
268 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "votel_plugin", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
269 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "valcfg_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
270 3 : }
271 :
272 3 : if( FD_LIKELY( config->tiles.gui.enabled ) ) {
273 3 : fd_topob_wksp( topo, "gui" );
274 3 : /**/ fd_topob_tile( topo, "gui", "gui", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
275 3 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "plugin_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
276 3 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "poh_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
277 3 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
278 3 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "pack_poh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
279 12 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "bank_poh", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
280 3 : }
281 :
282 3 : if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
283 0 : fd_topob_wksp( topo, "bundle_verif" );
284 0 : fd_topob_wksp( topo, "bundle_sign" );
285 0 : fd_topob_wksp( topo, "sign_bundle" );
286 0 : fd_topob_wksp( topo, "pack_sign" );
287 0 : fd_topob_wksp( topo, "sign_pack" );
288 0 : fd_topob_wksp( topo, "bundle" );
289 :
290 0 : /**/ fd_topob_link( topo, "bundle_verif", "bundle_verif", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU, 1UL );
291 0 : /**/ fd_topob_link( topo, "bundle_sign", "bundle_sign", 65536UL, 9UL, 1UL );
292 0 : /**/ fd_topob_link( topo, "sign_bundle", "sign_bundle", 128UL, 64UL, 1UL );
293 0 : /**/ fd_topob_link( topo, "pack_sign", "pack_sign", 65536UL, 1232UL, 1UL );
294 0 : /**/ fd_topob_link( topo, "sign_pack", "sign_pack", 128UL, 64UL, 1UL );
295 :
296 : /**/ fd_topob_tile( topo, "bundle", "bundle", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
297 :
298 : /**/ fd_topob_tile_out( topo, "bundle", 0UL, "bundle_verif", 0UL );
299 0 : FOR(verify_tile_cnt) fd_topob_tile_in( topo, "verify", i, "metric_in", "bundle_verif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
300 :
301 0 : /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "bundle_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
302 0 : /**/ fd_topob_tile_out( topo, "bundle", 0UL, "bundle_sign", 0UL );
303 0 : /**/ fd_topob_tile_in( topo, "bundle", 0UL, "metric_in", "sign_bundle", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
304 0 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_bundle", 0UL );
305 :
306 0 : /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "pack_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
307 0 : /**/ fd_topob_tile_out( topo, "pack", 0UL, "pack_sign", 0UL );
308 0 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "sign_pack", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
309 0 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_pack", 0UL );
310 :
311 0 : if( plugins_enabled ) {
312 0 : fd_topob_wksp( topo, "bundle_plugi" );
313 : /* bundle_plugi must be kind of deep, to prevent exhausting shared
314 : flow control credits when publishing many packets at once. */
315 0 : fd_topob_link( topo, "bundle_plugi", "bundle_plugi", 65536UL, sizeof(fd_plugin_msg_block_engine_update_t), 1UL );
316 0 : fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "bundle_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
317 0 : fd_topob_tile_out( topo, "bundle", 0UL, "bundle_plugi", 0UL );
318 0 : }
319 0 : }
320 :
321 3 : if( FD_LIKELY( !is_auto_affinity ) ) {
322 0 : if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
323 0 : FD_LOG_ERR(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] only provides for %lu cores. "
324 0 : "You should either increase the number of cores dedicated to Firedancer in the affinity string, or decrease the number of cores needed by reducing "
325 0 : "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
326 0 : topo->tile_cnt, affinity_tile_cnt ));
327 0 : if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
328 0 : FD_LOG_WARNING(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] provides for %lu cores. "
329 0 : "Not all cores in the affinity will be used by Firedancer. You may wish to increase the number of tiles in the system by increasing "
330 0 : "individual tile counts in the [layout] section of the configuration file.",
331 0 : topo->tile_cnt, affinity_tile_cnt ));
332 :
333 0 : if( FD_LIKELY( strcmp( "", config->frankendancer.layout.agave_affinity ) ) ) {
334 0 : ushort agave_cpu[ FD_TILE_MAX ];
335 0 : ulong agave_cpu_cnt = fd_tile_private_cpus_parse( config->frankendancer.layout.agave_affinity, agave_cpu );
336 :
337 0 : for( ulong i=0UL; i<agave_cpu_cnt; i++ ) {
338 0 : if( FD_UNLIKELY( agave_cpu[ i ]>=cpus->cpu_cnt ) )
339 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies a CPU index of %hu, but the system "
340 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
341 0 : "in the system.",
342 0 : agave_cpu[ i ], cpus->cpu_cnt ));
343 :
344 0 : for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
345 0 : fd_topo_tile_t * tile = &topo->tiles[ j ];
346 0 : if( tile->cpu_idx==agave_cpu[ i ] ) FD_LOG_WARNING(( "Tile `%s:%lu` is already assigned to CPU %hu, but the CPU is also assigned to Agave. "
347 0 : "This may cause contention between the two tiles.", tile->name, tile->kind_id, agave_cpu[ i ] ));
348 0 : }
349 :
350 0 : if( FD_UNLIKELY( topo->agave_affinity_cnt>FD_TILE_MAX ) ) {
351 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies more CPUs than Firedancer can use. "
352 0 : "You should either reduce the number of CPUs in the affinity string." ));
353 0 : }
354 0 : topo->agave_affinity_cpu_idx[ topo->agave_affinity_cnt++ ] = agave_cpu[ i ];
355 0 : }
356 0 : }
357 0 : }
358 :
359 : /* There is a special fseq that sits between the pack, bank, and poh
360 : tiles to indicate when the bank/poh tiles are done processing a
361 : microblock. Pack uses this to determine when to "unlock" accounts
362 : that it marked as locked because they were being used. */
363 :
364 15 : for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
365 12 : fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
366 :
367 12 : fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
368 12 : fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
369 12 : fd_topob_tile_uses( topo, poh_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
370 12 : fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
371 12 : FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
372 12 : }
373 :
374 : /* There's another special fseq that's used to communicate the shred
375 : version from the Agave boot path to the shred tile. */
376 3 : fd_topo_obj_t * poh_shred_obj = fd_topob_obj( topo, "fseq", "poh_shred" );
377 3 : fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
378 3 : fd_topob_tile_uses( topo, poh_tile, poh_shred_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
379 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
380 3 : fd_topo_tile_t * shred_tile = &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ];
381 3 : fd_topob_tile_uses( topo, shred_tile, poh_shred_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
382 3 : }
383 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, poh_shred_obj->id, "poh_shred" ) );
384 :
385 3 : FOR(net_tile_cnt) fd_topos_net_tile_finish( topo, i );
386 :
387 75 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
388 72 : fd_topo_tile_t * tile = &topo->tiles[ i ];
389 72 : fd_topo_configure_tile( tile, config );
390 72 : }
391 :
392 3 : if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo, 1 );
393 :
394 3 : fd_topob_finish( topo, CALLBACKS );
395 3 : config->topo = *topo;
396 3 : }
397 :
398 : void
399 : fd_topo_configure_tile( fd_topo_tile_t * tile,
400 72 : fd_config_t * config ) {
401 72 : int plugins_enabled = config->tiles.gui.enabled;
402 :
403 72 : if( FD_UNLIKELY( !strcmp( tile->name, "net" ) || !strcmp( tile->name, "sock" ) ) ) {
404 :
405 3 : tile->net.shred_listen_port = config->tiles.shred.shred_listen_port;
406 3 : tile->net.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
407 3 : tile->net.legacy_transaction_listen_port = config->tiles.quic.regular_transaction_listen_port;
408 :
409 69 : } else if( FD_UNLIKELY( !strcmp( tile->name, "netlnk" ) ) ) {
410 :
411 : /* already configured */
412 :
413 66 : } else if( FD_UNLIKELY( !strcmp( tile->name, "quic" ) ) ) {
414 :
415 3 : tile->quic.reasm_cnt = config->tiles.quic.txn_reassembly_count;
416 3 : tile->quic.out_depth = config->tiles.verify.receive_buffer_size;
417 3 : tile->quic.max_concurrent_connections = config->tiles.quic.max_concurrent_connections;
418 3 : tile->quic.max_concurrent_handshakes = config->tiles.quic.max_concurrent_handshakes;
419 3 : tile->quic.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
420 3 : tile->quic.idle_timeout_millis = config->tiles.quic.idle_timeout_millis;
421 3 : tile->quic.ack_delay_millis = config->tiles.quic.ack_delay_millis;
422 3 : tile->quic.retry = config->tiles.quic.retry;
423 3 : fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( tile->quic.key_log_path ), config->tiles.quic.ssl_key_log_file, sizeof(tile->quic.key_log_path) ) );
424 :
425 63 : } else if( FD_UNLIKELY( !strcmp( tile->name, "bundle" ) ) ) {
426 0 : strncpy( tile->bundle.url, config->tiles.bundle.url, sizeof(tile->bundle.url) );
427 0 : tile->bundle.url_len = strnlen( tile->bundle.url, 255 );
428 0 : strncpy( tile->bundle.sni, config->tiles.bundle.tls_domain_name, 256 );
429 0 : tile->bundle.sni_len = strnlen( tile->bundle.sni, 255 );
430 0 : strncpy( tile->bundle.identity_key_path, config->paths.identity_key, sizeof(tile->bundle.identity_key_path) );
431 0 : strncpy( tile->bundle.key_log_path, config->development.bundle.ssl_key_log_file, sizeof(tile->bundle.key_log_path) );
432 0 : tile->bundle.buf_sz = config->development.bundle.buffer_size_kib<<10;
433 0 : tile->bundle.ssl_heap_sz = config->development.bundle.ssl_heap_size_mib<<20;
434 0 : tile->bundle.keepalive_interval_nanos = config->tiles.bundle.keepalive_interval_millis * (ulong)1e6;
435 0 : tile->bundle.tls_cert_verify = !!config->tiles.bundle.tls_cert_verify;
436 63 : } else if( FD_UNLIKELY( !strcmp( tile->name, "verify" ) ) ) {
437 18 : tile->verify.tcache_depth = config->tiles.verify.signature_cache_size;
438 :
439 45 : } else if( FD_UNLIKELY( !strcmp( tile->name, "dedup" ) ) ) {
440 3 : tile->dedup.tcache_depth = config->tiles.dedup.signature_cache_size;
441 :
442 42 : } else if( FD_UNLIKELY( !strcmp( tile->name, "resolv" ) ) ) {
443 :
444 39 : } else if( FD_UNLIKELY( !strcmp( tile->name, "pack" ) ) ) {
445 3 : tile->pack.max_pending_transactions = config->tiles.pack.max_pending_transactions;
446 3 : tile->pack.bank_tile_count = config->layout.bank_tile_count;
447 3 : tile->pack.larger_max_cost_per_block = config->development.bench.larger_max_cost_per_block;
448 3 : tile->pack.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
449 3 : tile->pack.use_consumed_cus = config->tiles.pack.use_consumed_cus;
450 3 : tile->pack.schedule_strategy = config->tiles.pack.schedule_strategy_enum;
451 :
452 3 : if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
453 0 : #define PARSE_PUBKEY( _tile, f ) \
454 0 : if( FD_UNLIKELY( !fd_base58_decode_32( config->tiles.bundle.f, tile->_tile.bundle.f ) ) ) \
455 0 : FD_LOG_ERR(( "[tiles.bundle.enabled] set to true, but failed to parse [tiles.bundle."#f"] %s", config->tiles.bundle.f ));
456 0 : tile->pack.bundle.enabled = 1;
457 0 : PARSE_PUBKEY( pack, tip_distribution_program_addr );
458 0 : PARSE_PUBKEY( pack, tip_payment_program_addr );
459 0 : PARSE_PUBKEY( pack, tip_distribution_authority );
460 0 : tile->pack.bundle.commission_bps = config->tiles.bundle.commission_bps;
461 0 : strncpy( tile->pack.bundle.identity_key_path, config->paths.identity_key, sizeof(tile->pack.bundle.identity_key_path) );
462 0 : strncpy( tile->pack.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->pack.bundle.vote_account_path) );
463 3 : } else {
464 3 : fd_memset( &tile->pack.bundle, '\0', sizeof(tile->pack.bundle) );
465 3 : }
466 36 : } else if( FD_UNLIKELY( !strcmp( tile->name, "bank" ) ) ) {
467 :
468 24 : } else if( FD_UNLIKELY( !strcmp( tile->name, "poh" ) ) ) {
469 3 : strncpy( tile->poh.identity_key_path, config->paths.identity_key, sizeof(tile->poh.identity_key_path) );
470 :
471 3 : tile->poh.plugins_enabled = plugins_enabled;
472 3 : tile->poh.bank_cnt = config->layout.bank_tile_count;
473 3 : tile->poh.lagged_consecutive_leader_start = config->tiles.poh.lagged_consecutive_leader_start;
474 :
475 3 : if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
476 0 : tile->poh.bundle.enabled = 1;
477 0 : PARSE_PUBKEY( poh, tip_distribution_program_addr );
478 0 : PARSE_PUBKEY( poh, tip_payment_program_addr );
479 0 : strncpy( tile->poh.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->poh.bundle.vote_account_path) );
480 0 : #undef PARSE_PUBKEY
481 3 : } else {
482 3 : fd_memset( &tile->poh.bundle, '\0', sizeof(tile->poh.bundle) );
483 3 : }
484 :
485 21 : } else if( FD_UNLIKELY( !strcmp( tile->name, "shred" ) ) ) {
486 3 : strncpy( tile->shred.identity_key_path, config->paths.identity_key, sizeof(tile->shred.identity_key_path) );
487 :
488 3 : tile->shred.depth = config->topo.links[ tile->out_link_id[ 0 ] ].depth;
489 3 : tile->shred.fec_resolver_depth = config->tiles.shred.max_pending_shred_sets;
490 3 : tile->shred.expected_shred_version = config->consensus.expected_shred_version;
491 3 : tile->shred.shred_listen_port = config->tiles.shred.shred_listen_port;
492 3 : tile->shred.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
493 3 : for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_retransmit_cnt; i++ ) {
494 0 : parse_ip_port( "tiles.shred.additional_shred_destinations_retransmit",
495 0 : config->tiles.shred.additional_shred_destinations_retransmit[ i ],
496 0 : &tile->shred.adtl_dests_retransmit[ i ] );
497 0 : }
498 3 : tile->shred.adtl_dests_retransmit_cnt = config->tiles.shred.additional_shred_destinations_retransmit_cnt;
499 3 : for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_leader_cnt; i++ ) {
500 0 : parse_ip_port( "tiles.shred.additional_shred_destinations_leader",
501 0 : config->tiles.shred.additional_shred_destinations_leader[ i ],
502 0 : &tile->shred.adtl_dests_leader[ i ] );
503 0 : }
504 3 : tile->shred.adtl_dests_leader_cnt = config->tiles.shred.additional_shred_destinations_leader_cnt;
505 :
506 18 : } else if( FD_UNLIKELY( !strcmp( tile->name, "store" ) ) ) {
507 3 : tile->store.disable_blockstore_from_slot = config->development.bench.disable_blockstore_from_slot;
508 :
509 15 : } else if( FD_UNLIKELY( !strcmp( tile->name, "sign" ) ) ) {
510 3 : strncpy( tile->sign.identity_key_path, config->paths.identity_key, sizeof(tile->sign.identity_key_path) );
511 :
512 12 : } else if( FD_UNLIKELY( !strcmp( tile->name, "metric" ) ) ) {
513 3 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &tile->metric.prometheus_listen_addr ) ) )
514 0 : FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
515 3 : tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
516 :
517 9 : } else if( FD_UNLIKELY( !strcmp( tile->name, "cswtch" ) ) ) {
518 :
519 6 : } else if( FD_UNLIKELY( !strcmp( tile->name, "gui" ) ) ) {
520 3 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.gui.gui_listen_address, &tile->gui.listen_addr ) ) )
521 0 : FD_LOG_ERR(( "failed to parse gui listen address `%s`", config->tiles.gui.gui_listen_address ));
522 3 : tile->gui.listen_port = config->tiles.gui.gui_listen_port;
523 3 : tile->gui.is_voting = strcmp( config->paths.vote_account, "" );
524 3 : strncpy( tile->gui.cluster, config->cluster, sizeof(tile->gui.cluster) );
525 3 : strncpy( tile->gui.identity_key_path, config->paths.identity_key, sizeof(tile->gui.identity_key_path) );
526 3 : strncpy( tile->gui.vote_key_path, config->paths.vote_account, sizeof(tile->gui.vote_key_path) );
527 3 : tile->gui.max_http_connections = config->tiles.gui.max_http_connections;
528 3 : tile->gui.max_websocket_connections = config->tiles.gui.max_websocket_connections;
529 3 : tile->gui.max_http_request_length = config->tiles.gui.max_http_request_length;
530 3 : tile->gui.send_buffer_size_mb = config->tiles.gui.send_buffer_size_mb;
531 3 : tile->gui.schedule_strategy = config->tiles.pack.schedule_strategy_enum;
532 3 : tile->gui.websocket_compression = config->development.gui.websocket_compression;
533 3 : tile->gui.frontend_release_channel = config->development.gui.frontend_release_channel_enum;
534 :
535 3 : } else if( FD_UNLIKELY( !strcmp( tile->name, "plugin" ) ) ) {
536 :
537 3 : } else {
538 0 : FD_LOG_ERR(( "unknown tile name %lu `%s`", tile->id, tile->name ));
539 0 : }
540 72 : }
|