LCOV - code coverage report
Current view: top level - disco/net - fd_net_tile_topo.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 422 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /* Topology support routines for the net tile */
       2             : 
       3             : #define _GNU_SOURCE
       4             : #include "fd_net_tile.h"
       5             : #include "../topo/fd_topob.h"
       6             : #include "../netlink/fd_netlink_tile.h"
       7             : #include "../../app/shared/fd_config.h" /* FIXME layering violation */
       8             : #include "../../util/pod/fd_pod_format.h"
       9             : #include "fd_linux_bond.h"
      10             : #include "../../waltz/ip/fd_iproute.h"
      11             : 
      12             : #include <errno.h>
      13             : #include <limits.h>
      14             : #include <net/if.h>
      15             : #include <unistd.h>
      16             : 
      17             : static void
      18             : fd_net_read_device_driver( char *       driver,
      19             :                            ulong        driver_sz,
      20           0 :                            char const * if_name ) {
      21           0 :   FD_TEST( driver && driver_sz>=4UL );
      22           0 :   char path[ PATH_MAX ], target[ PATH_MAX ];
      23           0 :   fd_memcpy( driver, "n/a", 4UL );
      24           0 :   if( FD_UNLIKELY( !fd_cstr_printf_check( path, sizeof(path), NULL,
      25           0 :                                          "/sys/class/net/%s/device/driver", if_name ) ) ) {
      26           0 :     FD_LOG_WARNING(( "cannot read driver for interface `%s`: sysfs path too long", if_name ));
      27           0 :     return;
      28           0 :   }
      29             : 
      30           0 :   long n = readlink( path, target, sizeof(target)-1UL );
      31           0 :   if( FD_UNLIKELY( n<0L ) ) {
      32           0 :     if( errno!=ENOENT ) FD_LOG_WARNING(( "readlink(%s) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
      33           0 :     return;
      34           0 :   }
      35           0 :   if( FD_UNLIKELY( (ulong)n==sizeof(target)-1UL ) ) {
      36           0 :     FD_LOG_WARNING(( "device driver link `%s` is too long", path ));
      37           0 :     return;
      38           0 :   }
      39           0 :   target[ n ] = '\0';
      40             : 
      41           0 :   char const * base = strrchr( target, '/' );
      42           0 :   base = base ? base+1 : target;
      43           0 :   if( FD_UNLIKELY( !base[0] ) ) {
      44           0 :     FD_LOG_WARNING(( "device driver link `%s` has an empty driver name", path ));
      45           0 :     return;
      46           0 :   }
      47           0 :   ulong name_sz = strlen( base )+1UL;
      48           0 :   if( FD_UNLIKELY( name_sz>driver_sz ) ) {
      49           0 :     FD_LOG_WARNING(( "driver name in `%s` exceeds output buffer size %lu", path, driver_sz ));
      50           0 :     return;
      51           0 :   }
      52           0 :   fd_memcpy( driver, base, name_sz );
      53           0 : }
      54             : 
      55             : void
      56             : fd_net_get_driver( char *       driver,
      57             :                    ulong        driver_sz,
      58           0 :                    char const * if_name ) {
      59           0 :   FD_TEST( driver && driver_sz>=4UL );
      60           0 :   if( !fd_bonding_is_master( if_name ) ) {
      61           0 :     fd_net_read_device_driver( driver, driver_sz, if_name );
      62           0 :     return;
      63           0 :   }
      64             : 
      65           0 :   driver[0] = '\0';
      66           0 :   fd_bonding_slave_iter_t iter[1];
      67           0 :   for( fd_bonding_slave_iter_init( iter, if_name );
      68           0 :        !fd_bonding_slave_iter_done( iter );
      69           0 :        fd_bonding_slave_iter_next( iter ) ) {
      70           0 :     char member_driver[ NAME_MAX+1UL ];
      71           0 :     fd_net_read_device_driver( member_driver, fd_ulong_min( sizeof(member_driver), driver_sz ),
      72           0 :                                fd_bonding_slave_iter_ele( iter ) );
      73           0 :     if( FD_UNLIKELY( !strcmp( member_driver, "n/a" ) || ( driver[0] && strcmp( driver, member_driver ) ) ) ) {
      74           0 :       driver[0] = '\0';
      75           0 :       break;
      76           0 :     }
      77           0 :     fd_cstr_ncpy( driver, member_driver, driver_sz );
      78           0 :   }
      79           0 :   if( FD_UNLIKELY( !driver[0] ) ) fd_memcpy( driver, "n/a", 4UL );
      80           0 : }
      81             : 
      82             : char const *
      83           0 : fd_net_tile_name( char const * provider ) {
      84           0 :   if( 0==strcmp( provider, "xdp" ) ) {
      85           0 :     return "net";
      86           0 :   } else if( 0==strcmp( provider, "mlx5" ) ) {
      87           0 :     return "mlx5";
      88           0 :   } else if( 0==strcmp( provider, "socket" ) ) {
      89           0 :     return "sock";
      90           0 :   }
      91           0 :   FD_LOG_ERR(( "invalid net provider: %s", provider ));
      92           0 : }
      93             : 
      94             : static void
      95             : setup_mlx5_tile( fd_topo_t *             topo,
      96             :                  ulong                   tile_kind_id,
      97             :                  fd_topo_tile_t *        netlink_tile,
      98             :                  ulong const *           tile_to_cpu,
      99             :                  fd_config_net_t const * net_cfg,
     100             :                  ulong                   route_max,
     101           0 :                  ulong                   route_peer_max ) {
     102           0 :   fd_topo_tile_t * tile = fd_topob_tile( topo, "mlx5", "mlx5", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     103           0 :   tile->sleep_eventfd = topo->sleep_obj_id!=ULONG_MAX;
     104           0 :   fd_topob_link( topo, "net_netlnk", "net_netlnk", 128UL, 0UL, 0UL );
     105           0 :   fd_topob_tile_in(  topo, "netlnk", 0UL,         "metric_in", "net_netlnk", tile_kind_id, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     106           0 :   fd_topob_tile_out( topo, "mlx5", tile_kind_id,               "net_netlnk", tile_kind_id );
     107           0 :   fd_topob_tile_in(  topo, "mlx5", tile_kind_id, "metric_in", "iproute_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     108           0 :   fd_netlink_topo_join( topo, netlink_tile, tile );
     109             : 
     110           0 :   fd_topo_obj_t * umem_obj = fd_topob_obj( topo, "dcache", "net_umem" );
     111           0 :   fd_topob_tile_uses( topo, tile, umem_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     112           0 :   fd_pod_insertf_ulong( topo->props, umem_obj->id, "net.%lu.umem", tile_kind_id );
     113             : 
     114           0 :   FD_STATIC_ASSERT( sizeof(tile->mlx5.if_name)==IF_NAMESIZE, str_bounds );
     115           0 :   fd_cstr_ncpy( tile->mlx5.if_name, net_cfg->interface, IF_NAMESIZE );
     116             : 
     117           0 :   tile->mlx5.net.bind_address = net_cfg->bind_address_parsed;
     118           0 :   tile->mlx5.rx_queue_size    = net_cfg->mlx5.rx_queue_size;
     119           0 :   tile->mlx5.tx_queue_size    = net_cfg->mlx5.tx_queue_size;
     120           0 :   tile->mlx5.batch_size       = FD_MLX5_BATCH_SIZE;
     121             : 
     122           0 :   tile->net.umem_dcache_obj_id = umem_obj->id;
     123           0 :   tile->mlx5.netdev_tbl_obj_id = netlink_tile->netlink.netdev_tbl_obj_id;
     124           0 :   tile->mlx5.route_max         = route_max;
     125           0 :   tile->mlx5.route_peer_max    = route_peer_max;
     126           0 :   tile->mlx5.route_peer_seed   = 1UL + tile_kind_id;
     127           0 :   tile->mlx5.neigh4_obj_id     = netlink_tile->netlink.neigh4_obj_id;
     128           0 : }
     129             : 
     130             : static void
     131             : setup_xdp_tile( fd_topo_t *             topo,
     132             :                 ulong                   tile_kind_id,
     133             :                 fd_topo_tile_t *        netlink_tile,
     134             :                 ulong const *           tile_to_cpu,
     135             :                 fd_config_net_t const * net_cfg,
     136             :                 ulong                   route_max,
     137             :                 ulong                   route_peer_max,
     138             :                 char const *            if_phys,
     139             :                 ulong                   if_queue,
     140           0 :                 int                     xsk_core_dump ) {
     141           0 :   fd_topo_tile_t * tile = fd_topob_tile( topo, "net", "net", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, topo->sleep_obj_id!=ULONG_MAX );
     142           0 :   fd_topob_link( topo, "net_netlnk", "net_netlnk", 128UL, 0UL, 0UL );
     143           0 :   fd_topob_tile_in(  topo, "netlnk", 0UL, "metric_in", "net_netlnk", tile_kind_id, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     144           0 :   fd_topob_tile_out( topo, "net",    tile_kind_id,                "net_netlnk", tile_kind_id );
     145           0 :   fd_topob_tile_in(  topo, "net", tile_kind_id, "metric_in", "iproute_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     146           0 :   fd_netlink_topo_join( topo, netlink_tile, tile );
     147             : 
     148           0 :   fd_topo_obj_t * umem_obj = fd_topob_obj( topo, "dcache", "net_umem" );
     149           0 :   fd_topob_tile_uses( topo, tile, umem_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     150           0 :   fd_pod_insertf_ulong( topo->props, umem_obj->id, "net.%lu.umem", tile_kind_id );
     151             : 
     152           0 :   FD_STATIC_ASSERT( sizeof(tile->xdp.if_virt)==IF_NAMESIZE, str_bounds );
     153           0 :   fd_cstr_ncpy( tile->xdp.if_virt, net_cfg->interface, IF_NAMESIZE );
     154           0 :   tile->net.bind_address = net_cfg->bind_address_parsed;
     155             : 
     156           0 :   FD_STATIC_ASSERT( sizeof(tile->xdp.if_phys)==IF_NAMESIZE, str_bounds );
     157           0 :   fd_cstr_ncpy( tile->xdp.if_phys, if_phys, IF_NAMESIZE );
     158           0 :   tile->xdp.if_queue = (uint)if_queue;
     159             : 
     160           0 :   tile->xdp.tx_flush_timeout_ns = (long)net_cfg->xdp.flush_timeout_micros * 1000L;
     161           0 :   tile->xdp.xdp_rx_queue_size   = net_cfg->xdp.xdp_rx_queue_size;
     162           0 :   tile->xdp.xdp_tx_queue_size   = net_cfg->xdp.xdp_tx_queue_size;
     163           0 :   tile->xdp.zero_copy           = net_cfg->xdp.xdp_zero_copy;
     164           0 :   fd_cstr_ncpy( tile->xdp.xdp_mode, net_cfg->xdp.xdp_mode, sizeof(tile->xdp.xdp_mode) );
     165             : 
     166           0 :   fd_cstr_ncpy( tile->xdp.poll_mode, net_cfg->xdp.poll_mode, sizeof(tile->xdp.poll_mode) );
     167             : 
     168           0 :   tile->xdp.net.umem_dcache_obj_id = umem_obj->id;
     169           0 :   tile->xdp.netdev_tbl_obj_id      = netlink_tile->netlink.netdev_tbl_obj_id;
     170           0 :   tile->xdp.route_max              = route_max;
     171           0 :   tile->xdp.route_peer_max         = route_peer_max;
     172           0 :   tile->xdp.route_peer_seed        = 1UL + tile_kind_id;
     173           0 :   tile->xdp.neigh4_obj_id          = netlink_tile->netlink.neigh4_obj_id;
     174             : 
     175           0 :   tile->xdp.xsk_core_dump = xsk_core_dump;
     176             : 
     177             :   /* Allocate free ring */
     178             : 
     179           0 :   tile->xdp.free_ring_depth = tile->xdp.xdp_tx_queue_size;
     180           0 : }
     181             : 
     182             : static void
     183             : setup_sock_tile( fd_topo_t *             topo,
     184             :                  ulong const *           tile_to_cpu,
     185           0 :                  fd_config_net_t const * net_cfg ) {
     186           0 :   fd_topo_tile_t * tile = fd_topob_tile( topo, "sock", "sock", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     187           0 :   tile->sock.net.bind_address = net_cfg->bind_address_parsed;
     188             : 
     189           0 :   if( FD_UNLIKELY( net_cfg->socket.receive_buffer_size>INT_MAX ) ) FD_LOG_ERR(( "invalid [net.socket.receive_buffer_size]" ));
     190           0 :   if( FD_UNLIKELY( net_cfg->socket.send_buffer_size   >INT_MAX ) ) FD_LOG_ERR(( "invalid [net.socket.send_buffer_size]" ));
     191           0 :   tile->sock.so_rcvbuf = (int)net_cfg->socket.receive_buffer_size;
     192           0 :   tile->sock.so_sndbuf = (int)net_cfg->socket.send_buffer_size   ;
     193           0 : }
     194             : 
     195             : void
     196             : fd_topos_net_tiles( fd_topo_t *             topo,
     197             :                     ulong                   net_tile_cnt,
     198             :                     fd_config_net_t const * net_cfg,
     199             :                     ulong                   netlnk_max_routes,
     200             :                     ulong                   netlnk_max_peer_routes,
     201             :                     ulong                   netlnk_max_neighbors,
     202             :                     int                     xsk_core_dump,
     203           0 :                     ulong const             tile_to_cpu[ FD_TILE_MAX ] ) {
     204             :   /* net_umem: Packet buffers */
     205           0 :   fd_topob_wksp( topo, "net_umem" );
     206             : 
     207           0 :   fd_pod_insert_cstr( topo->props, "net.provider",  net_cfg->provider );
     208             : 
     209             :   /* Create workspaces */
     210             : 
     211           0 :   if( 0==strcmp( net_cfg->provider, "xdp" ) ) {
     212             : 
     213             :     /* net: private working memory of the net tiles */
     214           0 :     fd_topob_wksp( topo, "net" );
     215             :     /* netlnk: private working memory of the netlnk tile */
     216           0 :     fd_topob_wksp( topo, "netlnk" );
     217             :     /* netbase: shared network config (config plane) */
     218           0 :     fd_topob_wksp( topo, "netbase" );
     219             :     /* net_netlnk: net->netlnk ARP requests */
     220           0 :     fd_topob_wksp( topo, "net_netlnk" );
     221           0 :     fd_topob_wksp( topo, "iproute" );
     222             : 
     223           0 :     fd_topo_tile_t * netlink_tile = fd_topob_tile( topo, "netlnk", "netlnk", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 1 );
     224             :     /* A dump is emitted synchronously.  Keep room for one complete dump in
     225             :        addition to an already outstanding complete dump. */
     226           0 :     ulong iproute_depth = fd_ulong_pow2_up( 4UL*(netlnk_max_routes+netlnk_max_peer_routes)+8UL );
     227           0 :     fd_topob_link( topo, "iproute_out", "iproute", iproute_depth, sizeof(fd_iproute_msg_t), 1UL );
     228           0 :     fd_topob_tile_out( topo, "netlnk", 0UL, "iproute_out", 0UL );
     229           0 :     fd_netlink_topo_create( netlink_tile, topo, netlnk_max_routes, netlnk_max_peer_routes, netlnk_max_neighbors, net_cfg->interface );
     230             : 
     231             :     /* Enumerate network devices to attach to */
     232           0 :     uint devices[ FD_NET_BOND_SLAVE_MAX ] = {0};
     233           0 :     uint device_cnt = 1U;
     234           0 :     if( net_cfg->xdp.native_bond && fd_bonding_is_master( net_cfg->interface ) ) {
     235           0 :       fd_bonding_slave_iter_t iter_[1];
     236           0 :       fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, net_cfg->interface );
     237           0 :       uint slave_cnt;
     238           0 :       for( slave_cnt=0U;
     239           0 :            /*         */ !fd_bonding_slave_iter_done( iter );
     240           0 :            slave_cnt++,  fd_bonding_slave_iter_next( iter ) ) {
     241           0 :         if( FD_UNLIKELY( slave_cnt>=FD_NET_BOND_SLAVE_MAX ) ) {
     242           0 :           FD_LOG_ERR(( "bond interface %s has too many slave devices; max is %u (see [net.xdp.native_bond])",
     243           0 :                        net_cfg->interface, FD_NET_BOND_SLAVE_MAX ));
     244           0 :         }
     245           0 :         uint if_idx = if_nametoindex( fd_bonding_slave_iter_ele( iter ) );
     246           0 :         if( FD_UNLIKELY( !if_idx ) ) FD_LOG_ERR(( "if_nametoindex(%s) failed", fd_bonding_slave_iter_ele( iter ) ));
     247           0 :         devices[ slave_cnt ] = if_idx;
     248           0 :       }
     249           0 :       if( slave_cnt==0 ) {
     250           0 :         FD_LOG_ERR(( "no bond slave devices detected on interface %s (see [net.xdp.native_bond])", net_cfg->interface ));
     251           0 :       }
     252           0 :       device_cnt = (uint)slave_cnt;
     253           0 :     } else {
     254           0 :       devices[ 0 ] = if_nametoindex( net_cfg->interface );
     255           0 :       if( FD_UNLIKELY( !devices[ 0 ] ) ) FD_LOG_ERR(( "unsupported [net.interface]: `%s`", net_cfg->interface ));
     256           0 :       device_cnt = 1U;
     257           0 :     }
     258             : 
     259             :     /* Verify that net_tile_cnt is a multiple of device_cnt */
     260           0 :     if( FD_UNLIKELY( net_tile_cnt%device_cnt!=0 ) ) {
     261           0 :       FD_LOG_ERR(( "net tile count %lu must be a multiple of the number of slave devices %u (incompatible settings [layout.net_tile_count] and [net.xdp.native_bond])", net_tile_cnt, device_cnt ));
     262           0 :     }
     263           0 :     uint dev_queue_cnt = (uint)net_tile_cnt/device_cnt;
     264             : 
     265             :     /* Assign XDP tiles to device queues */
     266           0 :     ulong tile_kind_id = 0UL;
     267           0 :     for( uint i=0UL; i<device_cnt; i++ ) {
     268           0 :       char if_name[ IF_NAMESIZE ];
     269           0 :       if( FD_UNLIKELY( !if_indextoname( devices[ i ], if_name ) ) ) {
     270           0 :         FD_LOG_ERR(( "error initializing network stack: if_indextoname(%u) failed (try disabling [net.xdp.native_bond]?)", i ));
     271           0 :       }
     272           0 :       for( ulong j=0UL; j<dev_queue_cnt; j++ ) {
     273           0 :         setup_xdp_tile( topo, tile_kind_id++, netlink_tile, tile_to_cpu, net_cfg, netlnk_max_routes, netlnk_max_peer_routes, if_name, (uint)j, xsk_core_dump );
     274           0 :       }
     275           0 :     }
     276           0 :     FD_TEST( tile_kind_id==net_tile_cnt );
     277             : 
     278           0 :   } else if( 0==strcmp( net_cfg->provider, "socket" ) ) {
     279             : 
     280             :     /* sock: private working memory of the sock tiles */
     281           0 :     fd_topob_wksp( topo, "sock" );
     282             : 
     283           0 :     for( ulong i=0UL; i<net_tile_cnt; i++ ) {
     284           0 :       setup_sock_tile( topo, tile_to_cpu, net_cfg );
     285           0 :     }
     286           0 :   } else if( 0==strcmp( net_cfg->provider, "mlx5" ) ) {
     287             : 
     288             :     /* mlx5: private working memory of the mlx5 tiles */
     289           0 :     fd_topob_wksp( topo, "mlx5" );
     290             :     /* netlnk: private working memory of the netlnk tile */
     291           0 :     fd_topob_wksp( topo, "netlnk" );
     292             :     /* netbase: shared network config (config plane) */
     293           0 :     fd_topob_wksp( topo, "netbase" );
     294             :     /* net_netlnk: net->netlnk ARP requests */
     295           0 :     fd_topob_wksp( topo, "net_netlnk" );
     296           0 :     fd_topob_wksp( topo, "iproute" );
     297             : 
     298           0 :     fd_topo_tile_t * netlink_tile = fd_topob_tile( topo, "netlnk", "netlnk", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 1 );
     299           0 :     ulong iproute_depth = fd_ulong_pow2_up( 4UL*(netlnk_max_routes+netlnk_max_peer_routes)+8UL );
     300           0 :     fd_topob_link( topo, "iproute_out", "iproute", iproute_depth, sizeof(fd_iproute_msg_t), 1UL );
     301           0 :     fd_topob_tile_out( topo, "netlnk", 0UL, "iproute_out", 0UL );
     302           0 :     fd_netlink_topo_create( netlink_tile, topo, netlnk_max_routes, netlnk_max_peer_routes, netlnk_max_neighbors, net_cfg->interface );
     303             : 
     304           0 :     for( ulong i=0UL; i<net_tile_cnt; i++ ) {
     305           0 :       setup_mlx5_tile( topo, i, netlink_tile, tile_to_cpu, net_cfg, netlnk_max_routes, netlnk_max_peer_routes );
     306           0 :     }
     307             : 
     308           0 :   } else {
     309           0 :     FD_LOG_ERR(( "invalid `net.provider`" ));
     310           0 :   }
     311           0 : }
     312             : 
     313             : static void
     314             : add_umem_rx_link( fd_topo_t *  topo,
     315             :                   char const * link_name,
     316             :                   ulong        net_kind_id,
     317             :                   ulong        depth,
     318           0 :                   ulong        burst ) {
     319           0 :   if( FD_UNLIKELY( !topo || !link_name  ) ) FD_LOG_ERR(( "NULL args" ));
     320           0 :   if( FD_UNLIKELY( strlen( link_name )>=sizeof(topo->links[ topo->link_cnt ].name ) ) ) FD_LOG_ERR(( "link name too long: %s", link_name ));
     321           0 :   if( FD_UNLIKELY( topo->link_cnt>=FD_TOPO_MAX_LINKS ) ) FD_LOG_ERR(( "too many links" ));
     322             : 
     323           0 :   ulong kind_id = 0UL;
     324           0 :   for( ulong i=0UL; i<topo->link_cnt; i++ ) {
     325           0 :     if( !strcmp( topo->links[ i ].name, link_name ) ) kind_id++;
     326           0 :   }
     327             : 
     328           0 :   fd_topo_link_t * link = &topo->links[ topo->link_cnt ];
     329           0 :   strncpy( link->name, link_name, sizeof(link->name) );
     330           0 :   link->id       = topo->link_cnt;
     331           0 :   link->kind_id  = kind_id;
     332           0 :   link->depth    = depth;
     333           0 :   link->mtu      = FD_NET_MTU;
     334           0 :   link->burst    = burst;
     335             : 
     336           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "mcache", "net_umem" );
     337           0 :   link->mcache_obj_id = obj->id;
     338           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, depth, "obj.%lu.depth", obj->id ) );
     339             : 
     340           0 :   link->dcache_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "net.%lu.umem", net_kind_id );
     341           0 :   if( FD_UNLIKELY( link->dcache_obj_id==ULONG_MAX ) ) FD_LOG_ERR(( "umem dcache not found for net %lu", net_kind_id ));
     342             : 
     343           0 :   topo->link_cnt++;
     344           0 : }
     345             : 
     346             : void
     347             : fd_topos_net_rx_link( fd_topo_t *  topo,
     348             :                       char const * link_name,
     349             :                       ulong        net_kind_id,
     350           0 :                       ulong        depth ) {
     351           0 :   char const * provider = fd_pod_query_cstr( topo->props, "net.provider", "" );
     352           0 :   if( 0==strcmp( provider, "xdp" ) ) {
     353           0 :     add_umem_rx_link( topo, link_name, net_kind_id, depth, 0UL );
     354           0 :     fd_topob_tile_out( topo, "net", net_kind_id, link_name, net_kind_id );
     355           0 :   } else if( 0==strcmp( provider, "mlx5" ) ) {
     356           0 :     ulong tile_id = fd_topo_find_tile( topo, "mlx5", net_kind_id );
     357           0 :     if( FD_UNLIKELY( tile_id==ULONG_MAX ) ) FD_LOG_ERR(( "tile mlx5:%lu not found", net_kind_id ));
     358           0 :     add_umem_rx_link( topo, link_name, net_kind_id, depth, topo->tiles[ tile_id ].mlx5.batch_size );
     359           0 :     fd_topob_tile_out( topo, "mlx5", net_kind_id, link_name, net_kind_id );
     360           0 :   } else if( 0==strcmp( provider, "socket" ) ) {
     361           0 :     fd_topob_link( topo, link_name, "net_umem", depth, FD_NET_MTU, 64 );
     362           0 :     fd_topob_tile_out( topo, "sock", net_kind_id, link_name, net_kind_id );
     363           0 :   }
     364           0 : }
     365             : 
     366             : void
     367             : fd_topos_tile_in_net( fd_topo_t *  topo,
     368             :                       char const * fseq_wksp,
     369             :                       char const * link_name,
     370             :                       ulong        link_kind_id,
     371             :                       int          reliable,
     372           0 :                       int          polled ) {
     373           0 :   for( ulong j=0UL; j<(topo->tile_cnt); j++ ) {
     374           0 :     if( 0==strcmp( topo->tiles[ j ].name, "net"   ) ||
     375           0 :         0==strcmp( topo->tiles[ j ].name, "sock"  ) ||
     376           0 :         0==strcmp( topo->tiles[ j ].name, "mlx5" ) ) {
     377           0 :       fd_topob_tile_in( topo, topo->tiles[ j ].name, topo->tiles[ j ].kind_id, fseq_wksp, link_name, link_kind_id, reliable, polled );
     378           0 :     }
     379           0 :   }
     380           0 : }
     381             : 
     382             : static void
     383             : fd_topos_xdp_setup_mem( fd_topo_t *      topo,
     384           0 :                         fd_topo_tile_t * net_tile ) {
     385           0 :   ulong rx_depth = net_tile->xdp.xdp_rx_queue_size;
     386           0 :   ulong tx_depth = net_tile->xdp.xdp_tx_queue_size;
     387           0 :   rx_depth += (rx_depth/2UL);
     388           0 :   tx_depth += (tx_depth/2UL);
     389             : 
     390           0 :   if( net_tile->kind_id==0 ) {
     391             :     /* Double it for loopback XSK */
     392           0 :     rx_depth *= 2UL;
     393           0 :     tx_depth *= 2UL;
     394           0 :   }
     395             : 
     396           0 :   ulong cum_frame_cnt = rx_depth + tx_depth;
     397             : 
     398             :   /* Count up the depth of all RX mcaches */
     399             : 
     400           0 :   for( ulong j=0UL; j<(net_tile->out_cnt); j++ ) {
     401           0 :     ulong link_id       = net_tile->out_link_id[ j ];
     402           0 :     ulong mcache_obj_id = topo->links[ link_id ].mcache_obj_id;
     403           0 :     ulong depth = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "obj.%lu.depth", mcache_obj_id );
     404           0 :     if( FD_UNLIKELY( depth==ULONG_MAX ) ) FD_LOG_ERR(( "Didn't find depth for mcache %s", topo->links[ link_id ].name ));
     405           0 :     cum_frame_cnt += depth + 1UL;
     406           0 :   }
     407             : 
     408             :   /* Create a dcache object */
     409             : 
     410           0 :   ulong umem_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "net.%lu.umem", net_tile->kind_id );
     411           0 :   FD_TEST( umem_obj_id!=ULONG_MAX );
     412             : 
     413           0 :   FD_TEST( net_tile->net.umem_dcache_obj_id > 0 );
     414           0 :   fd_pod_insertf_ulong( topo->props, cum_frame_cnt, "obj.%lu.depth", umem_obj_id );
     415           0 :   fd_pod_insertf_ulong( topo->props, 2UL,           "obj.%lu.burst", umem_obj_id ); /* 4096 byte padding */
     416           0 :   fd_pod_insertf_ulong( topo->props, 2048UL,        "obj.%lu.mtu",   umem_obj_id );
     417           0 : }
     418             : 
     419             : void
     420             : fd_topo_install_xdp( fd_topo_t const * topo,
     421             :                      fd_xdp_fds_t *    fds,
     422             :                      uint *            fds_cnt,
     423             :                      uint              bind_addr,
     424           0 :                      int               dry_run ) {
     425           0 :   uint fds_max = *fds_cnt;
     426           0 :   memset( fds, 0, fds_max*sizeof(fd_xdp_fds_t) );
     427             : 
     428           0 :   uint if_cnt = 0U;
     429           0 : # define ADD_IF_IDX( idx_ ) do {                      \
     430           0 :     uint idx = (idx_);                                \
     431           0 :     int found = 0;                                    \
     432           0 :     for( uint i=0U; i<if_cnt; i++ ) {                 \
     433           0 :       if( fds[ i ].if_idx==idx ) {                    \
     434           0 :         found = 1;                                    \
     435           0 :         break;                                        \
     436           0 :       }                                               \
     437           0 :     }                                                 \
     438           0 :     if( !found ) {                                    \
     439           0 :       FD_TEST( if_cnt<FD_NET_BOND_SLAVE_MAX+1 );      \
     440           0 :       fds[ if_cnt++ ].if_idx = idx;                   \
     441           0 :     }                                                 \
     442           0 :   } while(0)
     443             : 
     444             :   /* Create a list of unique fds */
     445             : 
     446           0 :   ulong net_tile_cnt = fd_topo_tile_name_cnt( topo, "net" );
     447           0 :   for( ulong tile_kind_id=0UL; tile_kind_id<net_tile_cnt; tile_kind_id++ ) {
     448           0 :     ulong net_tile_id = fd_topo_find_tile( topo, "net", tile_kind_id );
     449           0 :     FD_TEST( net_tile_id!=ULONG_MAX );
     450           0 :     fd_topo_tile_t const * tile = &topo->tiles[ net_tile_id ];
     451           0 :     uint if_idx = if_nametoindex( tile->xdp.if_phys ); FD_TEST( if_idx );
     452           0 :     ADD_IF_IDX( if_idx );
     453           0 :   }
     454             : 
     455             :   /* Add loopback unless found */
     456             : 
     457           0 :   uint lo_idx = if_nametoindex( "lo" ); FD_TEST( lo_idx );
     458           0 :   ADD_IF_IDX( lo_idx );
     459             : 
     460             :   /* Done with config discovery */
     461             : 
     462           0 :   *fds_cnt = if_cnt;
     463           0 :   int next_fd = 123462;
     464           0 :   for( uint i=0U; i<if_cnt; i++ ) {
     465           0 :     fds[ i ].xsk_map_fd   = next_fd++;
     466           0 :     fds[ i ].prog_link_fd = next_fd++;
     467           0 :   }
     468           0 :   if( dry_run ) return;
     469             : 
     470             :   /* Install */
     471             : 
     472           0 :   ulong net0_tile_idx = fd_topo_find_tile( topo, "net", 0UL );
     473           0 :   FD_TEST( net0_tile_idx!=ULONG_MAX );
     474           0 :   fd_topo_tile_t const * net0_tile = &topo->tiles[ net0_tile_idx ];
     475             : 
     476           0 :   ushort udp_port_candidates[] = {
     477           0 :     (ushort)net0_tile->xdp.net.legacy_transaction_listen_port,
     478           0 :     (ushort)net0_tile->xdp.net.quic_transaction_listen_port,
     479           0 :     (ushort)net0_tile->xdp.net.shred_listen_port,
     480           0 :     (ushort)net0_tile->xdp.net.gossip_listen_port,
     481           0 :     (ushort)net0_tile->xdp.net.repair_client_listen_port,
     482           0 :     (ushort)net0_tile->xdp.net.repair_serve_listen_port,
     483           0 :     (ushort)net0_tile->xdp.net.votor_quic_client_listen_port,
     484           0 :     (ushort)net0_tile->xdp.net.votor_quic_server_listen_port,
     485           0 :   };
     486             : 
     487           0 :   for( uint i=0U; i<if_cnt; i++ ) {
     488             :     /* Override XDP mode for loopback */
     489           0 :     char const * xdp_mode = net0_tile->xdp.xdp_mode;
     490           0 :     if( fds[ i ].if_idx==1U ) xdp_mode = "skb";
     491             : 
     492           0 :     fd_xdp_fds_t xdp_fds = fd_xdp_install(
     493           0 :         fds[ i ].if_idx,
     494           0 :         bind_addr,
     495           0 :         sizeof(udp_port_candidates)/sizeof(udp_port_candidates[0]),
     496           0 :         udp_port_candidates,
     497           0 :         xdp_mode );
     498           0 :     if( FD_UNLIKELY( -1==dup2( xdp_fds.xsk_map_fd, fds[ i ].xsk_map_fd ) ) ) {
     499           0 :       FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     500           0 :     }
     501           0 :     if( FD_UNLIKELY( -1==close( xdp_fds.xsk_map_fd ) ) ) {
     502           0 :       FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     503           0 :     }
     504           0 :     if( FD_UNLIKELY( -1==dup2( xdp_fds.prog_link_fd, fds[ i ].prog_link_fd ) ) ) {
     505           0 :       FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     506           0 :     }
     507           0 :     if( FD_UNLIKELY( -1==close( xdp_fds.prog_link_fd ) ) ) {
     508           0 :       FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     509           0 :     }
     510           0 :   }
     511           0 : }
     512             : 
     513             : # undef ADD_IF_IDX
     514             : 
     515             : void
     516             : fd_topos_sock_lo( fd_topo_t *            topo,
     517           0 :                   fd_topo_tile_t const * net_tile ) {
     518           0 :   fd_topob_wksp( topo, "sock" );
     519           0 :   fd_topo_tile_t * sock = fd_topob_tile( topo, "sock", "sock", "metric_in", ULONG_MAX, 0, 0, 0 );
     520           0 :   sock->net = net_tile->net;
     521           0 :   sock->sock.only_recv_lo = 1;
     522           0 :   sock->sock.so_rcvbuf    = 32*1024*1024;
     523           0 :   sock->sock.net_tile_id  = net_tile->id;
     524             : 
     525           0 :   for( ulong i=0UL; i<net_tile->out_cnt; i++ ) {
     526           0 :     fd_topo_link_t const * net_out_link = &topo->links[ net_tile->out_link_id[ i ] ];
     527             : 
     528             :     /* Which links of net to duplicate */
     529           0 :     if( 0!=strncmp( net_out_link->name, "net_", 4UL ) || 0==strcmp( net_out_link->name, "net_netlnk" ) ) continue;
     530             : 
     531             :     /* Duplicate link */
     532           0 :     fd_topo_link_t * sock_out_link = fd_topob_link( topo, net_out_link->name, "sock", 4096UL, FD_NET_MTU, 64UL );
     533           0 :     fd_topob_tile_out( topo, "sock", sock->kind_id, sock_out_link->name, sock_out_link->kind_id );
     534             : 
     535             :     /* Loop through all tiles, check their in links for net */
     536           0 :     for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
     537           0 :       fd_topo_tile_t * consumer = &topo->tiles[ j ];
     538           0 :       ulong const in_cnt = consumer->in_cnt;
     539           0 :       for( ulong k=0UL; k<in_cnt; k++ ) {
     540           0 :         if( consumer->in_link_id[ k ]!=net_out_link->id ) continue;
     541             : 
     542             :         /* Add as sock link consumer */
     543           0 :         char const * fseq_wksp = topo->workspaces[ topo->objs[ consumer->in_link_fseq_obj_id[ k ] ].wksp_id ].name;
     544           0 :         fd_topob_tile_in( topo, consumer->name, consumer->kind_id, fseq_wksp, sock_out_link->name, sock_out_link->kind_id,
     545           0 :                           consumer->in_link_reliable[ k ], consumer->in_link_poll[ k ] );
     546           0 :       }
     547           0 :     }
     548           0 :   }
     549           0 : }
     550             : 
     551             : ulong
     552           0 : sock_lo_net_tile_id( fd_topo_tile_t const * tile ) {
     553           0 :   if( 0==strcmp( tile->name, "sock" ) && tile->sock.only_recv_lo ) return tile->sock.net_tile_id;
     554           0 :   return ULONG_MAX;
     555           0 : }
     556             : 
     557             : void
     558           0 : sock_lo_set_affinity( fd_topo_t * topo ) {
     559           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     560           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     561           0 :     ulong net_tile_id = sock_lo_net_tile_id( tile );
     562           0 :     if( net_tile_id==ULONG_MAX ) continue;
     563           0 :     FD_TEST( net_tile_id<topo->tile_cnt );
     564           0 :     fd_topo_tile_t const * net_tile = &topo->tiles[ net_tile_id ];
     565           0 :     tile->cpu_idx = net_tile->cpu_idx;
     566           0 :     tile->floats  = net_tile->floats;
     567           0 :   }
     568           0 : }
     569             : 
     570             : static void
     571             : fd_topos_mlx5_setup_mem( fd_topo_t *      topo,
     572           0 :                          fd_topo_tile_t * mlx5_tile ) {
     573           0 :   ulong cum_frame_cnt = 0UL;
     574             : 
     575           0 :   ulong const rx_depth = mlx5_tile->mlx5.rx_queue_size;
     576           0 :   ulong const tx_depth = mlx5_tile->mlx5.tx_queue_size;
     577           0 :   cum_frame_cnt += rx_depth + tx_depth;
     578             : 
     579             :   /* Count up the depth of all RX mcaches */
     580             : 
     581           0 :   for( ulong j=0UL; j<(mlx5_tile->out_cnt); j++ ) {
     582           0 :     ulong link_id       = mlx5_tile->out_link_id[ j ];
     583           0 :     ulong mcache_obj_id = topo->links[ link_id ].mcache_obj_id;
     584           0 :     ulong depth = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "obj.%lu.depth", mcache_obj_id );
     585           0 :     if( FD_UNLIKELY( depth==ULONG_MAX ) ) FD_LOG_ERR(( "Didn't find depth for mcache %s", topo->links[ link_id ].name ));
     586           0 :     cum_frame_cnt += depth + 1UL;
     587           0 :   }
     588             : 
     589             :   /* Create a dcache object */
     590             : 
     591           0 :   ulong umem_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "net.%lu.umem", mlx5_tile->kind_id );
     592           0 :   FD_TEST( umem_obj_id!=ULONG_MAX );
     593             : 
     594           0 :   FD_TEST( mlx5_tile->net.umem_dcache_obj_id > 0 );
     595           0 :   fd_pod_insertf_ulong( topo->props, cum_frame_cnt, "obj.%lu.depth", umem_obj_id );
     596           0 :   fd_pod_insertf_ulong( topo->props, 2UL,           "obj.%lu.burst", umem_obj_id ); /* 4096 byte padding */
     597           0 :   fd_pod_insertf_ulong( topo->props, FD_NET_MTU,    "obj.%lu.mtu",   umem_obj_id );
     598           0 : }
     599             : 
     600             : void
     601             : fd_topos_net_tile_finish( fd_topo_t * topo,
     602           0 :                           ulong       net_kind_id ) {
     603           0 :   char const * provider = fd_pod_query_cstr( topo->props, "net.provider", "" );
     604           0 :   if( 0==strcmp( provider, "xdp" ) ) {
     605           0 :     ulong tile_id = fd_topo_find_tile( topo, "net", net_kind_id );
     606           0 :     if( FD_UNLIKELY( tile_id==ULONG_MAX ) ) {
     607           0 :       FD_LOG_ERR(( "tile net:%lu not found", net_kind_id ));
     608           0 :     }
     609           0 :     fd_topos_xdp_setup_mem( topo, &topo->tiles[ tile_id ] );
     610           0 :   } else if( 0==strcmp( provider, "mlx5" ) ) {
     611           0 :     ulong tile_id = fd_topo_find_tile( topo, "mlx5", net_kind_id );
     612           0 :     if( FD_UNLIKELY( tile_id==ULONG_MAX ) ) {
     613           0 :       FD_LOG_ERR(( "tile mlx5:%lu not found", net_kind_id ));
     614           0 :     }
     615           0 :     fd_topos_mlx5_setup_mem( topo, &topo->tiles[ tile_id ] );
     616           0 :   } else {
     617           0 :     return;
     618           0 :   }
     619           0 : }

Generated by: LCOV version 1.14