LCOV - code coverage report
Current view: top level - waltz/ip - fd_fib4.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 296 340 87.1 %
Date: 2026-08-31 04:29:48 Functions: 16 16 100.0 %

          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 */

Generated by: LCOV version 1.14