Line data Source code
1 : #ifndef HEADER_fd_src_disco_fd_disco_base_h
2 : #define HEADER_fd_src_disco_fd_disco_base_h
3 :
4 : #include "../tango/fd_tango.h"
5 : #include "../ballet/shred/fd_shred.h"
6 : #include "../ballet/txn/fd_txn.h"
7 : #include "../flamenco/types/fd_types_custom.h"
8 : #include "../util/wksp/fd_wksp_private.h"
9 :
10 402 : #define DST_PROTO_OUTGOING (0UL)
11 0 : #define DST_PROTO_TPU_UDP (1UL)
12 384 : #define DST_PROTO_TPU_QUIC (2UL)
13 18 : #define DST_PROTO_SHRED (3UL)
14 0 : #define DST_PROTO_REPAIR (4UL)
15 0 : #define DST_PROTO_GOSSIP (5UL)
16 0 : #define DST_PROTO_SEND (6UL)
17 :
18 1320 : #define POH_PKT_TYPE_MICROBLOCK (0UL)
19 126 : #define POH_PKT_TYPE_BECAME_LEADER (1UL)
20 0 : #define POH_PKT_TYPE_FEAT_ACT_SLOT (2UL)
21 :
22 : /* FD_NET_MTU is the max full packet size, with ethernet, IP, and UDP
23 : headers that can go in or out of the net tile. 2048 is the maximum
24 : XSK entry size, so this value follows naturally. */
25 :
26 465 : #define FD_NET_MTU (2048UL)
27 :
28 : /* FD_TPU_MTU is the max serialized byte size of a txn sent over TPU.
29 :
30 : This is minimum MTU of IPv6 packet - IPv6 header - UDP header
31 : 1280 - 40 - 8 */
32 :
33 0 : #define FD_TPU_MTU (1232UL)
34 :
35 : /* FD_GOSSIP_MTU is the max sz of a gossip packet which is the same as
36 : above. */
37 :
38 0 : #define FD_GOSSIP_MTU (FD_TPU_MTU)
39 :
40 : /* FD_SHRED_STORE_MTU is the size of an fd_shred34_t (statically
41 : asserted in fd_shred_tile.c). */
42 :
43 3 : #define FD_SHRED_STORE_MTU (41792UL)
44 :
45 : /* FD_SHRED_OUT_MTU is the maximum size of a frag on the shred_out
46 : link. This is the size of a data shred header + merkle root
47 : + chained merkle root. */
48 :
49 3 : #define FD_SHRED_OUT_MTU (FD_SHRED_DATA_HEADER_SZ + 2*FD_SHRED_MERKLE_ROOT_SZ + sizeof(int))
50 : FD_STATIC_ASSERT( FD_SHRED_OUT_MTU == 156UL , update FD_SHRED_OUT_MTU );
51 :
52 0 : #define FD_NETMUX_SIG_MIN_HDR_SZ ( 42UL) /* The default header size, which means no vlan tags and no IP options. */
53 : #define FD_NETMUX_SIG_IGNORE_HDR_SZ (102UL) /* Outside the allowable range, but still fits in 4 bits when compressed */
54 :
55 : /* These limits are defined here to prevent circular dependencies, and
56 : statically asserted they are calculated correctly in the relevant
57 : places. We get one bound using transactions that consume the minimum
58 : number of CUs and another bound using the minimum size transactions.
59 : The overall bound is the lower of the two. */
60 : #define FD_MAX_TXN_PER_SLOT_CU 98039UL
61 : #define FD_MAX_TXN_PER_SLOT_SHRED 272635UL
62 9 : #define FD_MAX_TXN_PER_SLOT 98039UL
63 : FD_STATIC_ASSERT( FD_MAX_TXN_PER_SLOT<=FD_MAX_TXN_PER_SLOT_CU&&FD_MAX_TXN_PER_SLOT<=FD_MAX_TXN_PER_SLOT_SHRED, max_txn_per_slot );
64 : FD_STATIC_ASSERT( FD_MAX_TXN_PER_SLOT>=FD_MAX_TXN_PER_SLOT_CU||FD_MAX_TXN_PER_SLOT>=FD_MAX_TXN_PER_SLOT_SHRED, max_txn_per_slot );
65 :
66 :
67 : FD_PROTOTYPES_BEGIN
68 :
69 : /* hdr_sz is the total size of network headers, including eth, ip, udp.
70 : Ignored for outgoing packets.
71 : For incoming packets, hash_{ip_addr,port} are the source IP and port,
72 : for outgoing packets, they are the destination IP and port. */
73 : FD_FN_CONST static inline ulong
74 : fd_disco_netmux_sig( uint hash_ip_addr,
75 : ushort hash_port,
76 : uint ip_addr,
77 : ulong proto,
78 804 : ulong hdr_sz ) {
79 : /* The size of an Ethernet header is 14+4k bytes, where 0<=k<=3 (?) is
80 : the number of vlan tags. The size of an IP header is 4j, where
81 : 5<=j<=15 is the size given in the header. The size of a UDP header
82 : is 8B. Thus, the total sum of these is 42+4i, where i=k+j-5,
83 : 0<=i<=13. Since bits are at a premium here, we compress the header
84 : size by just storing i. */
85 804 : ulong hdr_sz_i = ((hdr_sz - 42UL)>>2)&0xFUL;
86 804 : ulong hash = 0xfffffUL & fd_ulong_hash( (ulong)hash_ip_addr | ((ulong)hash_port<<32) );
87 804 : return (hash<<44) | ((hdr_sz_i&0xFUL)<<40UL) | ((proto&0xFFUL)<<32UL) | ((ulong)ip_addr);
88 804 : }
89 :
90 402 : FD_FN_CONST static inline ulong fd_disco_netmux_sig_hash ( ulong sig ) { return (sig>>44UL); }
91 402 : FD_FN_CONST static inline ulong fd_disco_netmux_sig_proto( ulong sig ) { return (sig>>32UL) & 0xFFUL; }
92 402 : FD_FN_CONST static inline uint fd_disco_netmux_sig_ip ( ulong sig ) { return (uint)(sig & 0xFFFFFFFFUL); }
93 :
94 : /* fd_disco_netmux_sig_hdr_sz extracts the total size of the Ethernet,
95 : IP, and UDP headers from the netmux signature field. The UDP payload
96 : of the packet stored in the corresponding frag begins at the returned
97 : offset. */
98 0 : FD_FN_CONST static inline ulong fd_disco_netmux_sig_hdr_sz( ulong sig ) { return 4UL*((sig>>40UL) & 0xFUL) + 42UL; }
99 :
100 : FD_FN_CONST static inline ulong
101 : fd_disco_poh_sig( ulong slot,
102 : ulong pkt_type,
103 1368 : ulong bank_tile ) {
104 : /* The high 6 bits of the low byte of the signature field is the bank
105 : idx. Banks will filter to only handle frags with their own idx.
106 : The higher 7 bytes are the slot number. Technically, the slot
107 : number is a ulong, but it won't hit 256^7 for about 10^9 years at
108 : the current rate. The lowest bits of the low byte is the packet
109 : type. */
110 1368 : return (slot << 8) | ((bank_tile & 0x3FUL) << 2) | (pkt_type & 0x3UL);
111 1368 : }
112 :
113 78 : FD_FN_CONST static inline ulong fd_disco_poh_sig_pkt_type( ulong sig ) { return (sig & 0x3UL); }
114 48 : FD_FN_CONST static inline ulong fd_disco_poh_sig_slot( ulong sig ) { return (sig >> 8); }
115 0 : FD_FN_CONST static inline ulong fd_disco_poh_sig_bank_tile( ulong sig ) { return (sig >> 2) & 0x3FUL; }
116 :
117 : FD_FN_CONST static inline ulong
118 : fd_disco_bank_sig( ulong slot,
119 12 : ulong pack_idx ) {
120 12 : return (slot << 32) | pack_idx;
121 12 : }
122 :
123 0 : FD_FN_CONST static inline ulong fd_disco_bank_sig_slot( ulong sig ) { return (sig >> 32); }
124 0 : FD_FN_CONST static inline ulong fd_disco_bank_sig_pack_idx( ulong sig ) { return sig & 0xFFFFFFFFUL; }
125 :
126 : /* TODO remove */
127 :
128 : FD_FN_CONST static inline ulong
129 : fd_disco_replay_old_sig( ulong slot,
130 0 : ulong flags ) {
131 0 : /* The low byte of the signature field is the flags for replay message.
132 0 : The higher 7 bytes are the slot number. These flags indicate the status
133 0 : of a microblock as it transits through the replay system. Technically,
134 0 : the slot number is a ulong, but it won't hit 256^7 for about 10^9 years
135 0 : at the current rate. The lowest bit of the low byte is the packet
136 0 : type. */
137 0 : return (slot << 8) | (flags & 0xFFUL);
138 0 : }
139 :
140 0 : FD_FN_CONST static inline ulong fd_disco_replay_old_sig_flags( ulong sig ) { return (sig & 0xFFUL); }
141 0 : FD_FN_CONST static inline ulong fd_disco_replay_old_sig_slot( ulong sig ) { return (sig >> 8); }
142 :
143 : /* fd_disco_shred_out_shred_sig constructs a sig for the shred_out link.
144 : The encoded fields vary depending on the type of the sig. The
145 : diagram below describes the encoding.
146 :
147 : is_turbine (1) | slot (32) | fec_set_idx (15) | is_code (1) | shred_idx or data_cnt (15)
148 : [63] | [31, 62] | [16, 30] | [15] | [0, 14]
149 :
150 : There are two types of messages on the shred_out link. The first
151 : type is a generic shred message. The second is a FEC set completion
152 : message. Since we have run out of bits, the receiver must look at the
153 : sz of the dcache entry to determine which type of message it is.
154 :
155 : For the first message type (SHRED):
156 :
157 : The first bit [63] describes whether this shred source was turbine
158 : or repair.
159 :
160 : The next 32 bits [31, 62] describe the slot number. Note: if the slot
161 : number is >= UINT_MAX, the sender will store the value UINT_MAX in
162 : this field. If the receiver sees a value of UINT_MAX in the field, it
163 : must read the actual slot number from the dcache entry.
164 :
165 : The following 15 bits [16, 30] describe the fec_set_idx. This is a
166 : 15-bit value because shreds are bounded to 2^15 per slot, so in the
167 : worst case there is an independent FEC set for every shred, which
168 : results in at most 2^15 FEC sets per slot.
169 :
170 : The next bit [15] describes whether it is a coding shred (is_code).
171 : If is_code = 0, the sig describes a data shred, and the last 15 bits
172 : [0, 14] encode the shred_idx. If is_code = 1, the sig describes a
173 : coding shred, and the last 15 bits encode the data_cnt.
174 :
175 : For the second message type (FEC):
176 :
177 : Only the slot and fec_set_idx bits are populated. The data in the
178 : frag is the full shred header of the last data shred in the FEC set,
179 : the merkle root of the FEC set, and the chained merkle root of the
180 : FEC. Each field immediately follows the other field. */
181 :
182 : /* TODO this shred_out_sig can be greatly simplified when FEC sets
183 : are uniformly coding shreds and fixed size. */
184 :
185 : FD_FN_CONST static inline ulong
186 : fd_disco_shred_out_shred_sig( int is_turbine,
187 : ulong slot,
188 : uint fec_set_idx,
189 : int is_code,
190 0 : uint shred_idx_or_data_cnt ) {
191 0 : ulong slot_ul = fd_ulong_min( slot, (ulong)UINT_MAX );
192 0 : ulong shred_idx_or_data_cnt_ul = fd_ulong_min( (ulong)shred_idx_or_data_cnt, (ulong)FD_SHRED_BLK_MAX );
193 0 : ulong fec_set_idx_ul = fd_ulong_min( (ulong)fec_set_idx, (ulong)FD_SHRED_BLK_MAX );
194 0 : ulong is_turbine_ul = !!is_turbine;
195 0 : ulong is_code_ul = !!is_code;
196 :
197 0 : return is_turbine_ul << 63 | slot_ul << 31 | fec_set_idx_ul << 16 | is_code_ul << 15 | shred_idx_or_data_cnt_ul;
198 0 : }
199 :
200 : /* fd_disco_shred_out_shred_sig_{...} are accessors for the fields encoded
201 : in the sig described above. */
202 :
203 0 : FD_FN_CONST static inline int fd_disco_shred_out_shred_sig_is_turbine ( ulong sig ) { return fd_ulong_extract_bit( sig, 63 ); }
204 0 : FD_FN_CONST static inline ulong fd_disco_shred_out_shred_sig_slot ( ulong sig ) { return fd_ulong_extract ( sig, 31, 62 ); }
205 0 : FD_FN_CONST static inline uint fd_disco_shred_out_shred_sig_fec_set_idx( ulong sig ) { return (uint)fd_ulong_extract ( sig, 16, 30 ); }
206 0 : FD_FN_CONST static inline int fd_disco_shred_out_shred_sig_is_code ( ulong sig ) { return fd_ulong_extract_bit( sig, 15 ); }
207 0 : FD_FN_CONST static inline uint fd_disco_shred_out_shred_sig_shred_idx ( ulong sig ) { return (uint)fd_ulong_extract_lsb( sig, 15 ); } /* only when is_code = 0 */
208 0 : FD_FN_CONST static inline uint fd_disco_shred_out_shred_sig_data_cnt ( ulong sig ) { return (uint)fd_ulong_extract_lsb( sig, 15 ); } /* only when is_code = 1 */
209 :
210 : /*
211 : | slot (32) | fec_set_idx (15) | data_cnt (15) | is_data_complete (1) | is_batch_complete (1) |
212 : | [32, 63] | [17, 31] | [2, 16] | [1] | [0] |
213 :
214 : */
215 : FD_FN_CONST static inline ulong
216 0 : fd_disco_shred_out_fec_sig( ulong slot, uint fec_set_idx, uint data_cnt, int is_slot_complete, int is_batch_complete ) {
217 0 : ulong slot_ul = fd_ulong_min( slot, (ulong)UINT_MAX );
218 0 : ulong fec_set_idx_ul = fd_ulong_min( (ulong)fec_set_idx, (ulong)FD_SHRED_BLK_MAX );
219 0 : ulong data_cnt_ul = fd_ulong_min( (ulong)data_cnt, (ulong)FD_SHRED_BLK_MAX );
220 0 : ulong is_slot_complete_ul = !!is_slot_complete;
221 0 : ulong is_batch_complete_ul = !!is_batch_complete;
222 0 : return slot_ul << 32 | fec_set_idx_ul << 17 | data_cnt_ul << 2 | is_slot_complete_ul << 1 | is_batch_complete_ul;
223 0 : }
224 :
225 0 : FD_FN_CONST static inline ulong fd_disco_shred_out_fec_sig_slot ( ulong sig ) { return fd_ulong_extract ( sig, 32, 63 ); }
226 0 : FD_FN_CONST static inline uint fd_disco_shred_out_fec_sig_fec_set_idx ( ulong sig ) { return (uint) fd_ulong_extract ( sig, 17, 31 ); }
227 0 : FD_FN_CONST static inline uint fd_disco_shred_out_fec_sig_data_cnt ( ulong sig ) { return (uint) fd_ulong_extract ( sig, 2, 16 ); }
228 0 : FD_FN_CONST static inline int fd_disco_shred_out_fec_sig_is_slot_complete ( ulong sig ) { return fd_ulong_extract_bit( sig, 1 ); }
229 0 : FD_FN_CONST static inline int fd_disco_shred_out_fec_sig_is_batch_complete( ulong sig ) { return fd_ulong_extract_bit( sig, 0 ); }
230 :
231 : /* Exclusively used for force completion messages */
232 :
233 : FD_FN_CONST static inline ulong
234 0 : fd_disco_repair_shred_sig( uint last_shred_idx ){
235 0 : return (ulong) last_shred_idx;
236 0 : }
237 :
238 0 : FD_FN_CONST static inline uint fd_disco_repair_shred_sig_last_shred_idx( ulong sig ) { return (uint) sig; }
239 :
240 :
241 : FD_FN_CONST static inline ulong
242 3 : fd_disco_repair_replay_sig( ulong slot, ushort parent_off, uint data_cnt, int slot_complete ) {
243 : /*
244 : | slot (32) | parent_off (16) | data_cnt (15) | slot_complete(1)
245 : | [32, 63] | [16, 31] | [1, 15] | [0]
246 : */
247 3 : ulong slot_ul = fd_ulong_min( slot, (ulong)UINT_MAX );
248 3 : ulong parent_off_ul = (ulong)parent_off;
249 3 : ulong data_cnt_ul = fd_ulong_min( (ulong)data_cnt, (ulong)FD_SHRED_BLK_MAX );
250 3 : ulong slot_complete_ul = !!slot_complete;
251 3 : return slot_ul << 32 | parent_off_ul << 16 | data_cnt_ul << 1 | slot_complete_ul;
252 3 : }
253 :
254 3 : FD_FN_CONST static inline ulong fd_disco_repair_replay_sig_slot ( ulong sig ) { return fd_ulong_extract ( sig, 32, 63 ); }
255 3 : FD_FN_CONST static inline ushort fd_disco_repair_replay_sig_parent_off ( ulong sig ) { return (ushort)fd_ulong_extract ( sig, 16, 31 ); }
256 3 : FD_FN_CONST static inline uint fd_disco_repair_replay_sig_data_cnt ( ulong sig ) { return (uint) fd_ulong_extract ( sig, 1, 15 ); }
257 3 : FD_FN_CONST static inline int fd_disco_repair_replay_sig_slot_complete( ulong sig ) { return fd_ulong_extract_bit( sig, 0 ); }
258 :
259 : FD_FN_PURE static inline ulong
260 0 : fd_disco_compact_chunk0( void * wksp ) {
261 0 : return (((struct fd_wksp_private *)wksp)->gaddr_lo) >> FD_CHUNK_LG_SZ;
262 0 : }
263 :
264 : FD_FN_PURE static inline ulong
265 0 : fd_disco_compact_wmark( void * wksp, ulong mtu ) {
266 0 : ulong chunk_mtu = ((mtu + 2UL*FD_CHUNK_SZ-1UL) >> (1+FD_CHUNK_LG_SZ)) << 1;
267 0 : ulong wksp_hi = ((struct fd_wksp_private *)wksp)->gaddr_hi;
268 0 : return (wksp_hi >> FD_CHUNK_LG_SZ) - chunk_mtu;
269 0 : }
270 :
271 : FD_PROTOTYPES_END
272 :
273 : #endif /* HEADER_fd_src_disco_fd_disco_base_h */
|