LCOV - code coverage report
Current view: top level - app/shared - fd_auto_net.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 253 309 81.9 %
Date: 2026-11-09 04:27:00 Functions: 42 63 66.7 %

          Line data    Source code
       1             : #include "fd_auto_net.h"
       2             : #include "../platform/fd_sys_util.h"
       3             : #include "commands/configure/fd_ethtool_ioctl.h"
       4             : #include "../../disco/net/fd_linux_bond.h"
       5             : #include "../../disco/net/fd_net_tile.h"
       6             : #include "../../disco/net/iavf/fd_iavf.h"
       7             : #include "../../disco/net/mlx5/fd_mlx5.h"
       8             : #include "../../disco/netlink/fd_netlink_tile.h"
       9             : #include "../../waltz/mib/fd_netdev_netlink.h"
      10             : 
      11             : #include <stdlib.h> /* strtoul */
      12             : #include <limits.h>
      13             : #include <errno.h>
      14             : #include <string.h>
      15             : #include <unistd.h>
      16             : #include <sys/utsname.h>
      17             : #include <linux/if_arp.h>
      18             : 
      19         384 : #define PROVIDER_CNT       ( 3UL)
      20         864 : #define FEAT_CNT_MAX       (16UL)
      21         561 : #define NET_DRIVER_CNT_MAX (16UL)
      22             : 
      23             : struct fd_auto_info {
      24             :   /* System */
      25             :   ulong linux_major;
      26             :   ulong linux_minor;
      27             : 
      28             :   /* Networking */
      29             :   char driver[ NAME_SZ ];
      30             :   uint is_virtual_if:1;
      31             :   uint is_bonded_if:1;
      32             :   uint is_lacp_if:1;
      33             :   uint bonded_if_slave_count;
      34             :   int  is_using_gre;
      35             :   int  has_mlx5_rdma_port;
      36             :   int  has_uverbs;
      37             :   int  has_uverbs_module;
      38             :   int  iavf_pf_checks_passed;
      39             :   int  has_vfio;
      40             :   int  has_vfio_module;
      41             : };
      42             : typedef struct fd_auto_info fd_auto_info_t;
      43             : 
      44             : struct fd_auto_driver_rq {
      45             :   char const * name;
      46             :   ulong        min_linux_major;
      47             :   ulong        min_linux_minor;
      48             : 
      49             :   /* 0 = no max linux version */
      50             :   ulong        max_linux_major;
      51             :   ulong        max_linux_minor;
      52             : };
      53             : typedef struct fd_auto_driver_rq fd_auto_driver_rq_t;
      54             : 
      55             : struct fd_auto_feat {
      56             :   char const *         name;
      57             :   /* supported_drivers is for unconditional driver requirements.
      58             :      For conditional driver requirements leave this empty and call
      59             :      fd_auto_check_driver() inside the check() callback
      60             :      (like xdp_rss_queue_mode_check() does). */
      61             :   fd_auto_driver_rq_t  supported_drivers[ NET_DRIVER_CNT_MAX ];
      62             : 
      63             :   /* is_feat_auto() checks if feature is auto and sets the default */
      64             :   int  (*is_feat_auto)( fd_config_t          * config );
      65             :   int  (*check       )( fd_config_t    const * config,
      66             :                         fd_auto_info_t const * info   );
      67             :   void (*apply       )( fd_config_t          * config );
      68             : };
      69             : typedef struct fd_auto_feat fd_auto_feat_t;
      70             : 
      71             : struct fd_auto_provider {
      72             :   char const *         name;
      73             :   /* Later features observe earlier features updates to config,
      74             :      so the order is important.  e.g. ZC checks xdp_mode is DRV
      75             :      so DRV needs to come before ZC in the feats ordering. */
      76             :   fd_auto_feat_t       feats            [ FEAT_CNT_MAX ];
      77             :   fd_auto_driver_rq_t  supported_drivers[ NET_DRIVER_CNT_MAX ];
      78             : 
      79             :   int  (*check)( fd_config_t    const * config,
      80             :                  fd_auto_info_t const * info   );
      81             :   void (*apply)( fd_config_t          * config );
      82             : };
      83             : typedef struct fd_auto_provider fd_auto_provider_t;
      84             : 
      85             : static int
      86             : fd_auto_check_driver( fd_auto_info_t      const * info,
      87         405 :                       fd_auto_driver_rq_t const * supported_drivers ) {
      88             :   /* Check for driver requirements. */
      89         405 :   if( !supported_drivers[0].name ) return 1;
      90             : 
      91         561 :   for( ulong i=0UL; i<NET_DRIVER_CNT_MAX; i++ ) {
      92         561 :     fd_auto_driver_rq_t const * req = &supported_drivers[ i ];
      93         561 :     if( !req->name ) return 0;
      94             : 
      95         438 :     if( 0==strcmp( info->driver, req->name ) ) {
      96             :       /* Check system linux version is within bounds of min and max
      97             :          of what this driver req requires. */
      98         225 :       if( req->max_linux_major > 0UL ) {
      99          30 :         if( info->linux_major>req->max_linux_major ||
     100          30 :           ( info->linux_major==req->max_linux_major &&
     101          24 :             info->linux_minor>req->max_linux_minor ) ) continue;
     102          30 :       }
     103             : 
     104         201 :       if( info->linux_major>req->min_linux_major ||
     105         201 :         ( info->linux_major==req->min_linux_major &&
     106         153 :           info->linux_minor>=req->min_linux_minor ) ) return 1;
     107         201 :     }
     108         438 :   }
     109             : 
     110           0 :   return 0;
     111         276 : }
     112             : 
     113             : /* XDP checks/apply */
     114             : 
     115             : static int
     116             : xdp_check( fd_config_t    const * config,
     117          27 :            fd_auto_info_t const * info FD_PARAM_UNUSED ) {
     118          27 :   if( strcmp( config->net.provider, "auto" ) ) return 0;
     119          27 :   return 1;
     120          27 : }
     121             : 
     122             : static void
     123          27 : xdp_apply( fd_config_t * config ) {
     124          27 :   fd_memcpy( config->net.provider, "xdp", 4 );
     125          27 : }
     126             : 
     127             : static int
     128          96 : is_xdp_listen_gre_auto( fd_config_t * config ) {
     129          96 :   if( 2!=config->net.xdp.listen_gre ) return 0;
     130             :   /* Set to default */
     131          93 :   config->net.xdp.listen_gre = 0;
     132          93 :   return 1;
     133          96 : }
     134             : 
     135             : static int
     136             : xdp_listen_gre_check( fd_config_t    const * config FD_PARAM_UNUSED,
     137          51 :                       fd_auto_info_t const * info ) {
     138          51 :   return info->is_using_gre;
     139          51 : }
     140             : 
     141             : static void
     142           6 : xdp_listen_gre_apply( fd_config_t * config ) {
     143           6 :   config->net.xdp.listen_gre = 1;
     144           6 : }
     145             : 
     146             : static int
     147          96 : is_xdp_rss_queue_mode_auto( fd_config_t * config ) {
     148          96 :   if( strcmp( config->net.xdp.rss_queue_mode, "auto" ) ) return 0;
     149             :   /* Set to default */
     150          93 :   fd_memcpy( config->net.xdp.rss_queue_mode, "simple", 7 );
     151          93 :   return 1;
     152          96 : }
     153             : 
     154             : static int
     155             : xdp_rss_queue_mode_check( fd_config_t    const * config,
     156          51 :                           fd_auto_info_t const * info ) {
     157          51 :   if( 1==config->net.xdp.listen_gre ) {
     158           6 :     static fd_auto_driver_rq_t const gre_rss_drivers[ NET_DRIVER_CNT_MAX ] = {
     159           6 :       { "mlx5_core", 0, 0, 0, 0 }
     160           6 :     };
     161             : 
     162           6 :     if( 0==fd_auto_check_driver( info, gre_rss_drivers ) ) return 0;
     163           6 :   }
     164          48 :   return 1;
     165          51 : }
     166             : 
     167             : static void
     168          48 : xdp_rss_queue_mode_apply( fd_config_t * config ) {
     169          48 :   fd_memcpy( config->net.xdp.rss_queue_mode, "auto", 5 );
     170          48 : }
     171             : 
     172             : static int
     173          96 : is_xdp_native_bond_auto( fd_config_t * config ) {
     174          96 :   if( 2!=config->net.xdp.native_bond ) return 0;
     175             :   /* Set to default */
     176          96 :   config->net.xdp.native_bond = 0;
     177          96 :   return 1;
     178          96 : }
     179             : 
     180             : static int
     181             : xdp_native_bond_check( fd_config_t    const * config,
     182          27 :                        fd_auto_info_t const * info ) {
     183          27 :   if( !info->is_bonded_if ) return 0;
     184           6 :   if( !info->is_lacp_if ) return 0;
     185             : 
     186           3 :   if( 0==info->bonded_if_slave_count || info->bonded_if_slave_count>FD_NET_BOND_SLAVE_MAX ) return 0;
     187             : 
     188             :   /* net_tile_count must be a multiple of the bonded interface's slave count */
     189           3 :   if( 0!=config->layout.net_tile_count%info->bonded_if_slave_count ) return 0;
     190             : 
     191           3 :   return 1;
     192           3 : }
     193             : 
     194             : static void
     195           3 : xdp_native_bond_apply( fd_config_t * config ) {
     196           3 :   config->net.xdp.native_bond = 1;
     197           3 : }
     198             : 
     199             : static int
     200          96 : is_xdp_mode_auto( fd_config_t * config ) {
     201          96 :   if( strcmp( config->net.xdp.xdp_mode, "auto" ) ) return 0;
     202             :   /* Set to default */
     203          96 :   fd_memcpy( config->net.xdp.xdp_mode, "skb", 4 );
     204          96 :   return 1;
     205          96 : }
     206             : 
     207             : static int
     208             : xdp_drv_check( fd_config_t    const * config,
     209          27 :                fd_auto_info_t const * info ) {
     210          27 :   if( info->is_virtual_if &&
     211          27 :       !config->net.xdp.native_bond ) return 0;
     212          24 :   return 1;
     213          27 : }
     214             : 
     215             : static void
     216          24 : xdp_drv_apply( fd_config_t * config ) {
     217          24 :   fd_memcpy( config->net.xdp.xdp_mode, "drv", 4 );
     218          24 : }
     219             : 
     220             : static int
     221          96 : is_xdp_prefbusy_auto( fd_config_t * config ) {
     222          96 :   if( strcmp( config->net.xdp.poll_mode, "auto" ) ) return 0;
     223             :   /* Set to default */
     224          96 :   fd_memcpy( config->net.xdp.poll_mode, "softirq", 8 );
     225          96 :   return 1;
     226          96 : }
     227             : 
     228             : static int
     229             : xdp_prefbusy_check( fd_config_t    const * config,
     230          27 :                     fd_auto_info_t const * info FD_PARAM_UNUSED ) {
     231          27 :   if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
     232          24 :   return 1;
     233          27 : }
     234             : 
     235             : static void
     236          24 : xdp_prefbusy_apply( fd_config_t * config ) {
     237          24 :   fd_memcpy( config->net.xdp.poll_mode, "prefbusy", 9 );
     238          24 : }
     239             : 
     240             : static int
     241          96 : is_xdp_zc_auto( fd_config_t * config ) {
     242          96 :   if( 2!=config->net.xdp.xdp_zero_copy ) return 0;
     243             :   /* Set to default */
     244          96 :   config->net.xdp.xdp_zero_copy = 0;
     245          96 :   return 1;
     246          96 : }
     247             : 
     248             : static int
     249             : xdp_zc_check( fd_config_t    const * config,
     250          24 :               fd_auto_info_t const * info FD_PARAM_UNUSED ) {
     251          24 :   if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
     252          21 :   return 1;
     253          24 : }
     254             : 
     255             : static void
     256          21 : xdp_zc_apply( fd_config_t * config ) {
     257          21 :   config->net.xdp.xdp_zero_copy = 1;
     258          21 : }
     259             : 
     260             : /* mlx5 tile checks/apply */
     261             : static int
     262             : mlx5_check( fd_config_t    const * config,
     263          63 :             fd_auto_info_t const * info ) {
     264          63 :   if( strcmp( config->net.provider, "auto" ) ) return 0;
     265          63 :   if( !info->has_mlx5_rdma_port ) return 0;
     266          21 :   if( !info->has_uverbs && !info->has_uverbs_module ) return 0;
     267          18 :   return 1;
     268          21 : }
     269             : 
     270             : static void
     271          18 : mlx5_apply( fd_config_t * config ) {
     272          18 :   fd_memcpy( config->net.provider, "mlx5", 5 );
     273          18 : }
     274             : 
     275             : /* iavf tile checks/apply */
     276             : static int
     277             : iavf_check( fd_config_t    const * config,
     278          45 :             fd_auto_info_t const * info ) {
     279          45 :   if( 0!=strcmp( config->net.provider, "auto" ) ) return 0;
     280             : 
     281          45 :   if( !info->iavf_pf_checks_passed ) return 0;
     282          30 :   if( !info->has_vfio && !info->has_vfio_module ) return 0;
     283             : 
     284          27 :   if( info->is_bonded_if ) {
     285             :     /* Linux ice driver started allowing LACP bonds in combination with
     286             :        SR-IOV from Linux v6.5.
     287             :        https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1c769b1a303f7a3b447fc7244340b77823bdbfdc */
     288          15 :     static fd_auto_driver_rq_t const iavf_lacp_drivers[ NET_DRIVER_CNT_MAX ] = {
     289          15 :       { "ice",  6,  5, 0, 0 },
     290          15 :       { "i40e", 5, 14, 0, 0 }
     291          15 :     };
     292          15 :     if( 0==fd_auto_check_driver( info, iavf_lacp_drivers ) ) return 0;
     293          15 :   }
     294             : 
     295          21 :   return 1;
     296          27 : }
     297             : 
     298             : static void
     299          18 : iavf_apply( fd_config_t * config ) {
     300          18 :   fd_memcpy( config->net.provider, "iavf", 5 );
     301          18 : }
     302             : 
     303             : /* Each feature's supported Linux version matrix per driver decided
     304             :    based on fd-linux-version-testbed test results. */
     305             : static const fd_auto_provider_t NET_PROVIDERS[] = {
     306             :   {
     307             :     .name = "mlx5",
     308             :     .supported_drivers = { { "mlx5_core", 5, 14, 0, 0 } },
     309             :     .check = mlx5_check,
     310             :     .apply = mlx5_apply
     311             :   },
     312             :   {
     313             :     .name = "iavf",
     314             :     .supported_drivers = {
     315             :       { "ice",  5, 14, 0, 0 },
     316             :       { "i40e", 5, 14, 0, 0 }
     317             :     },
     318             :     .check = iavf_check,
     319             :     .apply = iavf_apply
     320             :   },
     321             :   {
     322             :     .name  = "xdp",
     323             :     .check = xdp_check,
     324             :     .apply = xdp_apply,
     325             :     .feats = {
     326             :       {
     327             :         .name              = "Listen GRE",
     328             :         .is_feat_auto      = is_xdp_listen_gre_auto,
     329             :         .check             = xdp_listen_gre_check,
     330             :         .apply             = xdp_listen_gre_apply
     331             :       },
     332             :       {
     333             :         .name              = "RSS Queue Mode",
     334             :         .is_feat_auto      = is_xdp_rss_queue_mode_auto,
     335             :         .check             = xdp_rss_queue_mode_check,
     336             :         .apply             = xdp_rss_queue_mode_apply
     337             :       },
     338             :       {
     339             :         .name              = "Native Bond",
     340             :         .supported_drivers = {
     341             :           { "mlx5_core", 5, 15, 0, 0 },
     342             :           { "i40e",      5, 15, 0, 0 },
     343             :         },
     344             :         .is_feat_auto      = is_xdp_native_bond_auto,
     345             :         .check             = xdp_native_bond_check,
     346             :         .apply             = xdp_native_bond_apply
     347             :       },
     348             :       {
     349             :         .name              = "DRV",
     350             :         .supported_drivers = {
     351             :           { "mlx5_core", 5, 15, 6, 3 },
     352             :           { "mlx5_core", 6,  5, 0, 0 },
     353             :           { "i40e",      5, 19, 0, 0 }
     354             :         },
     355             :         .is_feat_auto      = is_xdp_mode_auto,
     356             :         .check             = xdp_drv_check,
     357             :         .apply             = xdp_drv_apply,
     358             :       },
     359             :       {
     360             :         .name              = "Prefbusy",
     361             :         .supported_drivers = {
     362             :           { "mlx5_core", 5, 15, 0, 0 },
     363             :           { "i40e",      5, 15, 0, 0 }
     364             :         },
     365             :         .is_feat_auto      = is_xdp_prefbusy_auto,
     366             :         .check             = xdp_prefbusy_check,
     367             :         .apply             = xdp_prefbusy_apply
     368             :       },
     369             :       {
     370             :         .name              = "Zero Copy",
     371             :         .supported_drivers = {
     372             :           { "mlx5_core", 6, 1, 0, 0 }
     373             :         },
     374             :         .is_feat_auto      = is_xdp_zc_auto,
     375             :         .check             = xdp_zc_check,
     376             :         .apply             = xdp_zc_apply
     377             :       }
     378             :     }
     379             :   }
     380             : };
     381             : 
     382             : static void
     383           9 : scrape_system( fd_auto_info_t * info ) {
     384           9 :   struct utsname utsname;
     385           9 :   if( FD_UNLIKELY( -1==uname( &utsname ) ) ) {
     386           0 :     FD_LOG_WARNING(( "uname() failed (%i-%s), auto config skipping kernel version detection",
     387           0 :                      errno, fd_io_strerror( errno ) ));
     388           0 :     return;
     389           0 :   }
     390             : 
     391             :   /* utsname.release is typically "major.minor.patch-distrojunk",
     392             :      e.g. "6.8.0-45-generic" or "5.14.0-362.8.1.el9_3.x86_64".  We
     393             :      only care about major.minor.  A missing ".minor" is treated as
     394             :      minor 0.  An unparseable release leaves {0,0}, which fails all
     395             :      version requirements (fail-soft). */
     396             : 
     397           9 :   char const * cur = utsname.release;
     398           9 :   char *       end = NULL;
     399             : 
     400           9 :   ulong major = strtoul( cur, &end, 10 );
     401           9 :   if( FD_UNLIKELY( end==cur ) ) {
     402           0 :     FD_LOG_WARNING(( "unrecognized kernel release `%s`, auto config skipping kernel version detection",
     403           0 :                      utsname.release ));
     404           0 :     return;
     405           0 :   }
     406             : 
     407           9 :   ulong minor = 0UL;
     408           9 :   if( FD_LIKELY( end[0]=='.' ) ) {
     409           9 :     cur   = end+1;
     410           9 :     minor = strtoul( cur, &end, 10 );
     411           9 :     if( FD_UNLIKELY( end==cur ) ) minor = 0UL; /* tolerate "6." */
     412           9 :   }
     413             : 
     414           9 :   info->linux_major = major;
     415           9 :   info->linux_minor = minor;
     416           9 : }
     417             : 
     418             : static int
     419           9 : scrape_is_using_gre( void ) {
     420           9 :   fd_netlink_t netlink[1];
     421           9 :   if( FD_UNLIKELY( !fd_netlink_init( netlink, 42U ) ) ) return 1;
     422             : 
     423           9 :   ulong  netdev_tbl_footprint = fd_netdev_tbl_footprint( NETDEV_MAX, BOND_MASTER_MAX );
     424           9 :   void * netdev_tbl_mem       = aligned_alloc( FD_NETDEV_TBL_ALIGN, netdev_tbl_footprint );
     425           9 :   if( FD_UNLIKELY( !netdev_tbl_mem ) ) {
     426           0 :     fd_netlink_fini( netlink );
     427           0 :     FD_LOG_WARNING(( "failed to allocate network interface table for GRE auto detection" ));
     428           0 :     return 1;
     429           0 :   }
     430             : 
     431           9 :   fd_netdev_tbl_join_t netdev_tbl[1];
     432           9 :   FD_TEST( fd_netdev_tbl_new( netdev_tbl_mem, NETDEV_MAX, BOND_MASTER_MAX ) );
     433           9 :   FD_TEST( fd_netdev_tbl_join( netdev_tbl, netdev_tbl_mem ) );
     434             : 
     435           9 :   int err = fd_netdev_netlink_load_table( netdev_tbl, netlink );
     436           9 :   fd_netlink_fini( netlink );
     437           9 :   if( FD_UNLIKELY( err ) ) {
     438           0 :     FD_LOG_WARNING(( "failed to load network interfaces for GRE auto detection (%i-%s)",
     439           0 :                      err, fd_io_strerror( err ) ));
     440           0 :     free( netdev_tbl_mem );
     441           0 :     return 1;
     442           0 :   }
     443             : 
     444           9 :   int is_using_gre = 0;
     445          72 :   for( ushort i=0U; i<netdev_tbl->hdr->dev_cnt; i++ ) {
     446          63 :     if( netdev_tbl->dev_tbl[ i ].dev_type==ARPHRD_IPGRE ) {
     447           0 :       is_using_gre = 1;
     448           0 :       break;
     449           0 :     }
     450          63 :   }
     451           9 :   free( netdev_tbl_mem );
     452           9 :   return is_using_gre;
     453           9 : }
     454             : 
     455             : static void
     456             : scrape_networking( fd_auto_info_t * info,
     457           9 :                    char const     * if_name ) {
     458           9 :   info->is_using_gre = scrape_is_using_gre();
     459             : 
     460             :   /* Check for virtual interface */
     461           9 :   char path[ PATH_MAX ];
     462           9 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/class/net/%s/device", if_name ) );
     463           9 :   info->is_virtual_if = ( -1==access( path, F_OK ) );
     464             : 
     465             :   /* Check for bond */
     466           9 :   info->is_bonded_if = !!fd_bonding_is_master( if_name );
     467           9 :   if( info->is_bonded_if ) {
     468           9 :     info->bonded_if_slave_count = (uint)fd_bonding_slave_cnt( if_name );
     469           9 :     info->is_lacp_if            = !!fd_bonding_is_lacp( if_name );
     470           9 :   }
     471             : 
     472           9 :   fd_net_get_driver( info->driver, sizeof(info->driver), if_name );
     473             : 
     474           9 :   if( !strcmp( info->driver, "mlx5_core" ) ) {
     475           9 :     char rdma_name[ FD_MLX5_RDMA_NAME_MAX ];
     476           9 :     uint rdma_port;
     477           9 :     info->has_mlx5_rdma_port = fd_mlx5_rdma_dev_find( rdma_name, &rdma_port, if_name );
     478           9 :     info->has_uverbs         = fd_mlx5_uverbs_avail();
     479           9 :   }
     480           9 : }
     481             : 
     482             : static int
     483           9 : scrape_iavf_pfs( char const * if_name ) {
     484           9 :   char members[ FD_IAVF_MEMBER_MAX ][ IF_NAMESIZE ];
     485           9 :   ulong member_cnt;
     486           9 :   if( FD_UNLIKELY( -1==fd_iavf_member_interfaces( if_name, members, &member_cnt ) ) ) return 0;
     487             : 
     488             :   /* Each PF needs ARI, an IOMMU, PCIe resources for VFs and ntuple filtering */
     489           0 :   for( ulong i=0UL; i<member_cnt; i++ ) {
     490           0 :     uint numvfs;
     491           0 :     if( FD_UNLIKELY( -1==fd_iavf_iommu_check( members[i], NULL ) ) ) return 0;
     492           0 :     if( FD_UNLIKELY( -1==fd_iavf_ari_check( members[i] ) ) ) return 0;
     493           0 :     if( FD_UNLIKELY( -1==fd_iavf_numvfs_get( members[i], &numvfs ) ) ) return 0;
     494           0 :     if( FD_UNLIKELY( 0==numvfs && -1==fd_iavf_sriov_resources_check( members[i] ) ) ) return 0;
     495           0 :     if( 0!=numvfs ) {
     496           0 :       char vf_pci[ FD_IAVF_PCI_ADDR_SZ ];
     497           0 :       fd_iavf_pci_info_t pci;
     498           0 :       if( FD_UNLIKELY( -1==fd_iavf_get_last_vf( members[i], NULL, vf_pci, 1 ) ) ) return 0;
     499           0 :       if( FD_UNLIKELY( -1==fd_iavf_pci_probe( &pci, vf_pci ) ) ) return 0;
     500           0 :       if( 0!=strcmp( pci.driver, "vfio-pci" ) ) return 0;
     501           0 :     }
     502             : 
     503           0 :     fd_ethtool_ioctl_t ioc;
     504           0 :     if( FD_UNLIKELY( NULL==fd_ethtool_ioctl_init( &ioc, members[i] ) ) ) return 0;
     505             : 
     506             :     /* Only select IAVF automatically if ntuple filtering is enabled */
     507           0 :     int ntuple_enabled;
     508           0 :     int err = fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_NTUPLE, &ntuple_enabled );
     509           0 :     fd_ethtool_ioctl_fini( &ioc );
     510             : 
     511           0 :     if( FD_UNLIKELY( 0!=err ) ) return 0;
     512           0 :     if( FD_UNLIKELY( !ntuple_enabled ) ) return 0;
     513           0 :   }
     514           0 :   return 1;
     515           0 : }
     516             : 
     517             : static fd_auto_info_t
     518           9 : fd_auto_scrape_info( fd_config_t const * config ) {
     519           9 :   fd_auto_info_t info = {0};
     520             : 
     521           9 :   scrape_system    ( &info                        );
     522           9 :   scrape_networking( &info, config->net.interface );
     523             : 
     524           9 :   if( !strcmp( config->net.provider, "auto" ) &&
     525           9 :       info.has_mlx5_rdma_port                 &&
     526           9 :       !info.has_uverbs ) {
     527           0 :     info.has_uverbs_module = 0==fd_sys_util_modprobe( "ib_uverbs", 1 );
     528           0 :   }
     529             : 
     530           9 :   if( 0==strcmp( config->net.provider, "auto" ) ) {
     531           9 :     info.iavf_pf_checks_passed = scrape_iavf_pfs( config->net.interface );
     532           9 :     if( info.iavf_pf_checks_passed ) {
     533           0 :       if( fd_iavf_vfio_avail() ) {
     534           0 :         info.has_vfio = 0==fd_iavf_vfio_api_check( NULL );
     535           0 :       } else {
     536           0 :         info.has_vfio_module = 0==fd_sys_util_modprobe( "vfio-pci", 1 );
     537           0 :       }
     538           0 :     }
     539           9 :   }
     540             : 
     541           9 :   return info;
     542           9 : }
     543             : 
     544             : /* fd_auto_net_apply resolves any "auto" fields in the networking
     545             : configuration. The resulting configuration is optimized for the system
     546             : but won't always maximally optimize, this is to reduce risk of failures. */
     547             : static void
     548             : fd_auto_net_apply( fd_config_t          * config,
     549          96 :                    fd_auto_info_t const * info ) {
     550             :   /* Providers are in order of priority with first being the highest */
     551          96 :   int const is_provider_auto = !strcmp( config->net.provider, "auto" );
     552          96 :   int is_provider_set = 0;
     553         384 :   for( ulong p=0UL; p<PROVIDER_CNT; p++ ) {
     554         288 :     fd_auto_provider_t const * provider = &NET_PROVIDERS[p];
     555             : 
     556             :     /* Check provider requirements */
     557         288 :     int const is_explicit_provider = !is_provider_auto && !strcmp( config->net.provider, provider->name );
     558         288 :     int is_chosen_provider = !is_provider_set &&
     559         288 :                              ( is_explicit_provider ||
     560         228 :                                ( is_provider_auto &&
     561         198 :                                  ( !provider->check || provider->check( config, info ) ) &&
     562         198 :                                  fd_auto_check_driver( info, provider->supported_drivers ) ) );
     563         288 :     if( is_chosen_provider ) {
     564          93 :       is_provider_set = 1;
     565          93 :       if( is_provider_auto ) {
     566          63 :         if( FD_UNLIKELY( !provider->apply ) ) {
     567           0 :           FD_LOG_ERR(( "Applying auto configure net provider %s failed since no apply function was found.", provider->name ));
     568           0 :         }
     569          63 :         provider->apply( config );
     570          63 :       }
     571          93 :     }
     572             : 
     573         864 :     for( ulong f=0UL; f<FEAT_CNT_MAX; f++ ) {
     574         864 :       fd_auto_feat_t const * feat = &provider->feats[f];
     575         864 :       if( !feat->name ) break;
     576             : 
     577             :       /* Checks feature is set to "auto", if so replaces "auto" with
     578             :          default and goes onto the next checks */
     579         576 :       if( !feat->is_feat_auto( config ) ) continue;
     580             : 
     581         570 :       if( !is_chosen_provider ) continue;
     582             : 
     583             :       /* Feature's driver/Linux version requirements */
     584         318 :       if( !fd_auto_check_driver( info, feat->supported_drivers ) ) continue;
     585             : 
     586             :       /* Feature's other requirements */
     587         207 :       if( feat->check && !feat->check( config, info ) ) continue;
     588             : 
     589         126 :       if( FD_UNLIKELY( !feat->apply ) ) {
     590           0 :         FD_LOG_ERR(( "Applying auto configure net feature %s failed since no apply function was found.", feat->name ));
     591           0 :       }
     592         126 :       feat->apply( config );
     593         126 :     }
     594         288 :   }
     595          96 : }
     596             : 
     597             : void
     598           9 : fd_auto_net( fd_config_t * config ) {
     599           9 :   fd_auto_info_t info = fd_auto_scrape_info( config );
     600           9 :   fd_auto_net_apply( config, &info );
     601             : 
     602           9 :   fd_cstr_printf( config->auto_config_log, sizeof(config->auto_config_log), NULL,
     603           9 :       "network auto configure system info: provider=%s xdp_mode=%s poll_mode=%s zero_copy=%d native_bond=%d listen_gre=%d rss_queue_mode=%s (driver=%s kernel=%lu.%lu gre=%d virtual_if=%d bonded_if=%d lacp_if=%d slaves=%u, net_tile_cnt=%u)",
     604           9 :       config->net.provider,
     605           9 :       config->net.xdp.xdp_mode,
     606           9 :       config->net.xdp.poll_mode,
     607           9 :       config->net.xdp.xdp_zero_copy,
     608           9 :       config->net.xdp.native_bond,
     609           9 :       config->net.xdp.listen_gre,
     610           9 :       config->net.xdp.rss_queue_mode,
     611           9 :       info.driver[0] ? info.driver : "unknown",
     612           9 :       info.linux_major, info.linux_minor,
     613           9 :       info.is_using_gre,
     614           9 :       info.is_virtual_if,
     615           9 :       info.is_bonded_if,
     616           9 :       info.is_lacp_if,
     617           9 :       info.bonded_if_slave_count,
     618           9 :       config->layout.net_tile_count );
     619           9 : }

Generated by: LCOV version 1.14