Line data Source code
1 : #include "fd_fib4.h"
2 : #include "fd_fib4_private.h"
3 : #include "../../util/tmpl/fd_map.h"
4 : #include "../../util/net/fd_ip4.h" /* for printing ip4 addrs */
5 : #define SORT_NAME sort_fib4_key
6 : #define SORT_KEY_T fd_fib4_key_t
7 243 : #define SORT_BEFORE(a,b) ( ((a).mask_bits<(b).mask_bits) || \
8 243 : ( ((a).mask_bits==(b).mask_bits) && ((a).prio<(b).prio) ) || \
9 243 : ( ((a).mask_bits==(b).mask_bits) && ((a).prio==(b).prio) && ((a).addr<(b).addr) ) )
10 : #include "../../util/tmpl/fd_sort.c"
11 :
12 : FD_FN_CONST ulong
13 531 : fd_fib4_align( void ) {
14 531 : return alignof(fd_fib4_priv_t);
15 531 : }
16 :
17 : FD_FN_CONST ulong
18 : fd_fib4_footprint( ulong route_max,
19 117 : ulong route_peer_max ) {
20 117 : if( route_max==0 || route_max>UINT_MAX ||
21 117 : route_peer_max==0 || route_peer_max>UINT_MAX ) return 0UL;
22 108 : ulong elem_max = fd_fib4_hmap_get_ele_max( route_peer_max );
23 108 : ulong hmap_footprint = fd_fib4_hmap_footprint( elem_max );
24 108 : if( !hmap_footprint ) return 0UL;
25 :
26 108 : return FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT,
27 108 : alignof(fd_fib4_priv_t), sizeof(fd_fib4_priv_t) ),
28 108 : alignof(fd_fib4_key_t), route_max*sizeof(fd_fib4_key_t) ),
29 108 : alignof(fd_fib4_hop_t), route_max*sizeof(fd_fib4_hop_t) ),
30 108 : fd_fib4_hmap_align(), hmap_footprint ),
31 108 : fd_fib4_align() );
32 108 : }
33 :
34 : void *
35 : fd_fib4_new( void * mem,
36 : ulong route_max,
37 : ulong route_peer_max,
38 42 : ulong route_peer_seed ) {
39 :
40 42 : if( FD_UNLIKELY( !mem ) ) {
41 0 : FD_LOG_WARNING(( "NULL mem" ));
42 0 : return NULL;
43 0 : }
44 42 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_fib4_align() ) ) ) {
45 0 : FD_LOG_WARNING(( "unaligned mem" ));
46 0 : return NULL;
47 0 : }
48 42 : if( FD_UNLIKELY( route_max==0 || route_max>UINT_MAX ) ) {
49 0 : FD_LOG_WARNING(( "invalid route_max" ));
50 0 : return NULL;
51 0 : }
52 42 : if( FD_UNLIKELY( route_peer_max==0 || route_peer_max>UINT_MAX ) ) {
53 0 : FD_LOG_WARNING(( "invalid route_peer_max" ));
54 0 : return NULL;
55 0 : }
56 :
57 42 : FD_SCRATCH_ALLOC_INIT( l, mem );
58 42 : fd_fib4_priv_t * fib4 = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_fib4_priv_t), sizeof(fd_fib4_priv_t) );
59 42 : fd_fib4_key_t * keys = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_fib4_key_t), route_max*sizeof(fd_fib4_key_t) );
60 42 : fd_fib4_hop_t * vals = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_fib4_hop_t), route_max*sizeof(fd_fib4_hop_t) );
61 42 : ulong hmap_elem_max = fd_fib4_hmap_get_ele_max( route_peer_max );
62 42 : ulong hmap_footprint = fd_fib4_hmap_footprint( hmap_elem_max ); FD_TEST( hmap_footprint );
63 42 : void * fib4_hmap_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_fib4_hmap_align(), hmap_footprint ); FD_TEST( fib4_hmap_mem );
64 42 : FD_SCRATCH_ALLOC_FINI( l, alignof(fd_fib4_priv_t) );
65 :
66 42 : fd_memset( fib4, 0, sizeof(fd_fib4_priv_t) );
67 42 : fd_memset( keys, 0, route_max*sizeof(fd_fib4_key_t) );
68 42 : fd_memset( vals, 0, route_max*sizeof(fd_fib4_hop_t) );
69 :
70 42 : FD_TEST( fd_fib4_hmap_new( fib4_hmap_mem, hmap_elem_max, 1 ) );
71 :
72 42 : fib4->cnt = 1UL; // first route entry is 0.0.0.0/0
73 42 : fib4->max = route_max;
74 42 : fib4->hop_off = (ulong)vals - (ulong)fib4;
75 42 : fib4->hmap_offset = (ulong)fib4_hmap_mem - (ulong)fib4;
76 42 : fib4->hmap_max = route_peer_max;
77 42 : fib4->hmap_cnt = 0;
78 42 : fib4->seed = route_peer_seed;
79 42 : keys[0].prio = UINT_MAX;
80 42 : vals[0].rtype = FD_FIB4_RTYPE_THROW;
81 42 : keys[0].mask_bits = 32;
82 :
83 42 : return fib4;
84 42 : }
85 :
86 : fd_fib4_t *
87 : fd_fib4_join( fd_fib4_t * join,
88 42 : void * shmem ) {
89 42 : if( FD_UNLIKELY( !join ) ) {
90 0 : FD_LOG_WARNING(( "NULL join" ));
91 0 : return NULL;
92 0 : }
93 42 : if( FD_UNLIKELY( !shmem ) ) {
94 0 : FD_LOG_WARNING(( "NULL shmem" ));
95 0 : return NULL;
96 0 : }
97 :
98 42 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_fib4_align() ) ) ) {
99 0 : FD_LOG_WARNING(( "unaligned shmem" ));
100 0 : return NULL;
101 0 : }
102 :
103 42 : fd_fib4_priv_t * priv = fd_type_pun( shmem );
104 42 : fd_fib4_hmap_t * hmap_join = fd_type_pun( join->hmap_join );
105 42 : void * hmap_mem = fd_fib4_hmap_mem( priv );
106 42 : ulong ele_max = fd_fib4_hmap_get_ele_max( priv->hmap_max );
107 42 : ulong probe_max = fd_fib4_hmap_get_probe_max( ele_max );
108 42 : ulong seed = priv->seed;
109 :
110 42 : FD_TEST( fd_fib4_hmap_join( hmap_join, hmap_mem, ele_max, probe_max, seed ) );
111 :
112 42 : join->priv = priv;
113 42 : return join;
114 42 : }
115 :
116 : void *
117 12 : fd_fib4_leave( fd_fib4_t * fib4 ) {
118 12 : *fib4 = (fd_fib4_t){0};
119 12 : return fib4;
120 12 : }
121 :
122 : void *
123 12 : fd_fib4_delete( void * mem ) {
124 12 : return mem;
125 12 : }
126 :
127 : void
128 84 : fd_fib4_clear( fd_fib4_t * fib4_join ) {
129 84 : fd_fib4_priv_t * fib4 = fib4_join->priv;
130 84 : fib4->cnt = 1UL;
131 :
132 84 : if( fib4->hmap_cnt==0 ) return;
133 :
134 :
135 51 : fib4->hmap_cnt = 0;
136 51 : fd_fib4_hmap_t * hmap_join = fd_type_pun( fib4_join->hmap_join );
137 51 : void * hmap_mem = fd_fib4_hmap_mem( fib4 );
138 51 : ulong elem_max = fd_fib4_hmap_get_ele_max( fib4->hmap_max );
139 51 : FD_TEST( fd_fib4_hmap_leave( hmap_join ) );
140 51 : FD_TEST( fd_fib4_hmap_new( hmap_mem, elem_max, 1 ) );
141 :
142 51 : ulong probe_max = fd_fib4_hmap_get_probe_max( elem_max );
143 51 : ulong seed = fib4->seed;
144 51 : FD_TEST( fd_fib4_hmap_join( hmap_join, hmap_mem, elem_max, probe_max, seed ) );
145 51 : }
146 :
147 : FD_FN_PURE ulong
148 6 : fd_fib4_max( fd_fib4_t const * fib4_join ) {
149 6 : return fib4_join->priv->max;
150 6 : }
151 :
152 : FD_FN_PURE ulong
153 6 : fd_fib4_peer_max( fd_fib4_t const * fib4_join ) {
154 6 : return fib4_join->priv->hmap_max;
155 6 : }
156 :
157 : FD_FN_PURE ulong
158 66 : fd_fib4_cnt( fd_fib4_t const * fib4_join ) {
159 66 : fd_fib4_priv_t * priv = fib4_join->priv;
160 66 : return priv->cnt+priv->hmap_cnt;
161 66 : }
162 :
163 : /* Upsert a /32 route. Returns FD_MAP_SUCCESS on success or
164 : FD_MAP_ERR_FULL if the hmap is full. */
165 :
166 : static int
167 : fd_fib4_hmap_upsert_entry( fd_fib4_t * fib4_join,
168 : uint ip4_dst,
169 : uint prio,
170 393 : fd_fib4_hop_t const * hop ) {
171 :
172 393 : FD_TEST( hop );
173 393 : fd_fib4_priv_t * fib = fib4_join->priv;
174 393 : fd_fib4_hmap_t * hmap_join = fd_type_pun( fib4_join->hmap_join );
175 :
176 393 : fd_fib4_hmap_key_t key = { .dst_addr=ip4_dst, .prio=prio };
177 393 : fd_fib4_hmap_entry_t * ele = fd_fib4_hmap_upsert( hmap_join, &key );
178 393 : if( FD_UNLIKELY( !ele ) ) return FD_MAP_ERR_FULL;
179 :
180 393 : int is_new = fd_fib4_hmap_ele_is_free( ele );
181 393 : if( FD_UNLIKELY( is_new && fib->hmap_cnt>=fib->hmap_max ) ) return FD_MAP_ERR_FULL;
182 :
183 381 : fd_fib4_hmap_entry_t to_enter = {
184 381 : .key = key,
185 381 : .next_hop = *hop
186 381 : };
187 381 : *ele = to_enter;
188 :
189 381 : fib->hmap_cnt += (ulong)is_new;
190 :
191 381 : return FD_MAP_SUCCESS;
192 393 : }
193 :
194 : int
195 : fd_fib4_insert( fd_fib4_t * fib_join,
196 : uint ip4_dst,
197 : int prefix,
198 : uint prio,
199 576 : fd_fib4_hop_t const * hop ) {
200 :
201 576 : FD_TEST( hop );
202 576 : if( ip4_dst!=0 && prefix==32 ) {
203 393 : if( fd_fib4_hmap_upsert_entry( fib_join, ip4_dst, prio, hop )==FD_MAP_SUCCESS ) return 1;
204 12 : FD_LOG_WARNING(( "Failed to insert /32 route " FD_IP4_ADDR_FMT " into fib4 hashmap", FD_IP4_ADDR_FMT_ARGS(ip4_dst) ));
205 12 : return 0;
206 393 : }
207 :
208 183 : fd_fib4_priv_t * fib = fib_join->priv;
209 :
210 183 : uint mask = prefix>0 ? fd_uint_mask( 32-prefix, 31 ) : 0U;
211 :
212 183 : fd_fib4_key_t new_key = (fd_fib4_key_t){
213 183 : .addr = fd_uint_bswap( ip4_dst ) & mask,
214 183 : .mask = mask,
215 183 : .prio = prio,
216 183 : .mask_bits = fd_uint_find_lsb_w_default( mask, 32 )
217 183 : };
218 :
219 183 : fd_fib4_key_t * key_tbl = fd_fib4_key_tbl( fib );
220 183 : fd_fib4_hop_t * hop_tbl = fd_fib4_hop_tbl( fib );
221 :
222 942 : for( ulong i=1UL; i<fib->cnt; i++ ) {
223 759 : if( key_tbl[i].addr==new_key.addr && key_tbl[i].mask==new_key.mask && key_tbl[i].prio==new_key.prio ) {
224 0 : hop_tbl[i] = *hop;
225 0 : return 1;
226 0 : }
227 759 : }
228 :
229 183 : if( FD_UNLIKELY( fib->cnt>=fib->max ) ) {
230 6 : FD_LOG_WARNING(( "Failed to insert route " FD_IP4_ADDR_FMT ", route table is full (%lu max)", FD_IP4_ADDR_FMT_ARGS(ip4_dst), fib->max ));
231 6 : return 0;
232 6 : }
233 :
234 177 : ulong old_cnt = fib->cnt;
235 177 : fib->cnt = old_cnt+1UL;
236 :
237 : /* Maintain sorted order for indices [1,cnt) by (mask_bits, prio) ascending.
238 : Find the intended location and shift the rest down */
239 177 : ulong n_sorted = fd_ulong_sat_sub( old_cnt, 1 ); /* number of existing sorted elems in [1,idx) */
240 177 : ulong idx; /* loc to insert new entry */
241 177 : if( FD_LIKELY( n_sorted>0UL ) ) {
242 117 : ulong rnk = sort_fib4_key_split( key_tbl + 1UL, n_sorted, new_key );
243 117 : ulong pos = 1UL + rnk;
244 147 : for( ulong dst=old_cnt; dst>pos; dst-- ) { /* n_sorted>0 <> idx>0 */
245 30 : key_tbl[ dst ] = key_tbl[ dst-1 ];
246 30 : hop_tbl[ dst ] = hop_tbl[ dst-1 ];
247 30 : }
248 117 : idx = pos;
249 117 : } else {
250 60 : idx = old_cnt;
251 60 : }
252 :
253 177 : key_tbl[ idx ] = new_key;
254 177 : hop_tbl[ idx ] = *hop;
255 :
256 177 : return 1;
257 183 : }
258 :
259 : int
260 : fd_fib4_remove( fd_fib4_t * fib_join,
261 : uint ip4_dst,
262 : int prefix,
263 39 : uint prio ) {
264 39 : fd_fib4_priv_t * fib = fib_join->priv;
265 39 : if( ip4_dst!=0U && prefix==32 ) {
266 33 : fd_fib4_hmap_t * hmap = fd_type_pun( fib_join->hmap_join );
267 33 : ulong memo = fd_fib4_hmap_entry_hash( ip4_dst, fib->seed );
268 33 : fd_fib4_hmap_entry_t * ele = NULL;
269 33 : for( fd_fib4_hmap_iter_t iter = fd_fib4_hmap_iter_init( hmap, memo );
270 45 : !fd_fib4_hmap_iter_done( hmap, memo, iter );
271 33 : iter = fd_fib4_hmap_iter_next( hmap, memo, iter ) ) {
272 33 : fd_fib4_hmap_entry_t * candidate = fd_fib4_hmap_iter_ele( hmap, memo, iter );
273 33 : if( candidate->key.dst_addr==ip4_dst && candidate->key.prio==prio ) {
274 21 : ele = candidate;
275 21 : break;
276 21 : }
277 33 : }
278 33 : if( FD_UNLIKELY( !ele ) ) return 0;
279 21 : fd_fib4_hmap_remove( hmap, ele );
280 21 : fib->hmap_cnt--;
281 21 : return 1;
282 33 : }
283 :
284 6 : uint mask = prefix>0 ? fd_uint_mask( 32-prefix, 31 ) : 0U;
285 6 : uint addr = fd_uint_bswap( ip4_dst ) & mask;
286 6 : fd_fib4_key_t * keys = fd_fib4_key_tbl( fib );
287 6 : fd_fib4_hop_t * hops = fd_fib4_hop_tbl( fib );
288 6 : for( ulong i=1UL; i<fib->cnt; i++ ) {
289 3 : if( keys[i].addr!=addr || keys[i].mask!=mask || keys[i].prio!=prio ) continue;
290 3 : for( ulong j=i+1UL; j<fib->cnt; j++ ) {
291 0 : keys[j-1UL] = keys[j];
292 0 : hops[j-1UL] = hops[j];
293 0 : }
294 3 : fib->cnt--;
295 3 : return 1;
296 3 : }
297 3 : return 0;
298 6 : }
299 :
300 : fd_fib4_hop_t
301 : fd_fib4_lookup( fd_fib4_t const * fib_join,
302 : uint ip4_dst,
303 759 : ulong flags ) {
304 759 : fd_fib4_priv_t * fib = fib_join->priv;
305 :
306 759 : if( FD_UNLIKELY( flags ) ) {
307 0 : return fd_fib4_hop_tbl_const( fib )[0]; /* dead route */
308 0 : }
309 :
310 759 : if( fib->hmap_cnt>0 ) {
311 699 : fd_fib4_hmap_t const * hmap_join = fd_type_pun_const( fib_join->hmap_join );
312 699 : ulong memo = fd_fib4_hmap_entry_hash( ip4_dst, fib->seed );
313 699 : fd_fib4_hmap_entry_t const * best = NULL;
314 699 : for( fd_fib4_hmap_iter_t iter = fd_fib4_hmap_iter_init( hmap_join, memo );
315 1026 : !fd_fib4_hmap_iter_done( hmap_join, memo, iter );
316 699 : iter = fd_fib4_hmap_iter_next( hmap_join, memo, iter ) ) {
317 327 : fd_fib4_hmap_entry_t const * candidate = fd_fib4_hmap_iter_ele_const( hmap_join, memo, iter );
318 327 : if( candidate->key.dst_addr==ip4_dst && (!best || candidate->key.prio<best->key.prio) ) best = candidate;
319 327 : }
320 699 : if( best && best->next_hop.rtype!=FD_FIB4_RTYPE_UNSPEC ) {
321 303 : return best->next_hop;
322 303 : }
323 : // Can't find a match in the fib4 hashmap. Look up in the routing table.
324 699 : }
325 :
326 456 : ip4_dst = fd_uint_bswap( ip4_dst );
327 456 : fd_fib4_key_t const * keys = fd_fib4_key_tbl_const( fib );
328 :
329 : /* The table [1,cnt) is sorted by increasing mask_bits then prio.
330 : Return the first match, which is guaranteed to be optimal. */
331 456 : ulong cnt = fib->cnt;
332 456 : ulong j = 1UL;
333 1347 : while( j<cnt ) {
334 1119 : if( (ip4_dst & keys[j].mask)==keys[j].addr ) {
335 228 : break;
336 228 : }
337 891 : j++;
338 891 : }
339 :
340 456 : ulong idx = j==cnt ? 0UL : j;
341 456 : fd_fib4_hop_t out = fd_fib4_hop_tbl_const( fib )[ idx ];
342 :
343 456 : return out;
344 759 : }
345 :
346 : #if FD_HAS_HOSTED
347 :
348 : #include <errno.h>
349 : #include <stdio.h>
350 : #include "../../util/net/fd_ip4.h"
351 :
352 165 : #define WRAP_PRINT(file,str) if( FD_UNLIKELY( fputs( (str), (file) )<0 ) ) return errno
353 243 : #define WRAP_PRINTF(file,...) if( FD_UNLIKELY( fprintf( (file), __VA_ARGS__ )<0 ) ) return errno
354 :
355 : static int
356 : fd_fib4_fprintf_route( fd_fib4_key_t const * key,
357 : fd_fib4_hop_t const * hop,
358 69 : FILE * file ) {
359 :
360 69 : switch( hop->rtype ) {
361 0 : case FD_FIB4_RTYPE_UNSPEC:
362 0 : WRAP_PRINT( file, "unspecified " );
363 0 : break;
364 15 : case FD_FIB4_RTYPE_UNICAST:
365 15 : break;
366 21 : case FD_FIB4_RTYPE_LOCAL:
367 21 : WRAP_PRINT( file, "local " );
368 21 : break;
369 21 : case FD_FIB4_RTYPE_BROADCAST:
370 21 : WRAP_PRINT( file, "broadcast " );
371 21 : break;
372 21 : case FD_FIB4_RTYPE_MULTICAST:
373 0 : WRAP_PRINT( file, "multicast " );
374 0 : break;
375 0 : case FD_FIB4_RTYPE_BLACKHOLE:
376 0 : WRAP_PRINT( file, "blackhole " );
377 0 : break;
378 12 : case FD_FIB4_RTYPE_THROW:
379 12 : WRAP_PRINT( file, "throw " );
380 12 : break;
381 12 : default:
382 0 : WRAP_PRINTF( file, "invalid (%u) ", hop->rtype );
383 0 : break;
384 69 : }
385 :
386 69 : if( key->mask==0 ) {
387 18 : WRAP_PRINT( file, "default" );
388 51 : } else {
389 51 : WRAP_PRINTF( file, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( fd_uint_bswap( key->addr ) ) );
390 51 : if( key->mask!=UINT_MAX ) {
391 51 : WRAP_PRINTF( file, "/%u", 32U-(uint)fd_uint_find_lsb_w_default( key->mask, 32 ) );
392 51 : }
393 51 : }
394 :
395 69 : if( hop->ip4_gw ) {
396 6 : WRAP_PRINTF( file, " via " FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( hop->ip4_gw ) );
397 6 : }
398 :
399 69 : if( hop->if_idx ) {
400 57 : WRAP_PRINTF( file, " dev %u", hop->if_idx );
401 57 : }
402 :
403 69 : switch( hop->scope ) {
404 45 : case 0:
405 45 : break;
406 0 : case 200:
407 0 : WRAP_PRINT( file, " scope site" );
408 0 : break;
409 15 : case 253:
410 15 : WRAP_PRINT( file, " scope link" );
411 15 : break;
412 15 : case 254:
413 9 : WRAP_PRINT( file, " scope host" );
414 9 : break;
415 9 : default:
416 0 : WRAP_PRINTF( file, " scope %u", hop->scope );
417 0 : break;
418 69 : }
419 :
420 69 : if( hop->ip4_src ) {
421 54 : WRAP_PRINTF( file, " src " FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( hop->ip4_src ) );
422 54 : }
423 :
424 69 : if( key->prio ) {
425 24 : WRAP_PRINTF( file, " metric %u", key->prio );
426 24 : }
427 :
428 69 : WRAP_PRINT( file, "\n" );
429 :
430 69 : return 0;
431 69 : }
432 :
433 : int
434 : fd_fib4_fprintf( fd_fib4_t const * fib_join,
435 12 : void * file_ ) {
436 12 : FILE * file = file_;
437 12 : fd_fib4_priv_t * fib = fib_join->priv;
438 :
439 12 : fd_fib4_key_t const * key_tbl = fd_fib4_key_tbl_const( fib );
440 12 : fd_fib4_hop_t const * hop_tbl = fd_fib4_hop_tbl_const( fib );
441 :
442 12 : ulong cnt = fib->cnt;
443 :
444 51 : for( ulong j=0UL; j<cnt; j++ ) {
445 39 : fd_fib4_key_t key = key_tbl[j];
446 39 : fd_fib4_hop_t hop = hop_tbl[j];
447 39 : fd_fib4_fprintf_route( &key, &hop, file );
448 39 : }
449 :
450 : /* Attempt to print the hashmap. */
451 12 : fd_fib4_hmap_t const * hmap_join = fd_type_pun_const( fib_join->hmap_join );
452 12 : fd_fib4_hmap_entry_t const * elems = fd_fib4_hmap_ele0_const( hmap_join );
453 12 : ulong ele_max = fd_fib4_hmap_get_ele_max( fib->hmap_max );
454 3276 : for( ulong i=0; i<ele_max; i++ ) {
455 3264 : fd_fib4_hmap_entry_t const * e = elems + i;
456 3264 : if( FD_LIKELY( fd_fib4_hmap_ele_is_free( e ) ) ) {
457 3234 : continue;
458 3234 : }
459 :
460 30 : fd_fib4_hmap_entry_t tmp_entry = *e;
461 :
462 30 : fd_fib4_key_t key;
463 30 : key.addr = fd_uint_bswap( tmp_entry.key.dst_addr );
464 30 : key.mask = 31U; /* force fd_fib4_fprintf_route to print the /32 suffix */
465 30 : key.prio = tmp_entry.key.prio;
466 30 : fd_fib4_fprintf_route( &key, &tmp_entry.next_hop, file );
467 30 : }
468 :
469 12 : return 0;
470 12 : }
471 :
472 : #undef WRAP_PRINT
473 : #undef WRAP_PRINTF
474 :
475 : #endif /* FD_HAS_HOSTED */
|