LCOV - code coverage report
Current view: top level - app/shared - fd_config_auto.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 90 178 50.6 %
Date: 2026-08-04 05:20:02 Functions: 14 39 35.9 %

          Line data    Source code
       1             : #include "fd_config_auto.h"
       2             : #include "../../disco/net/fd_linux_bond.h"
       3             : #include "../../disco/net/fd_net_tile.h"
       4             : 
       5             : #include <stdlib.h> /* strtoul */
       6             : #include <limits.h>
       7             : #include <errno.h>
       8             : #include <string.h>
       9             : #include <unistd.h>
      10             : #include <sys/utsname.h>
      11             : 
      12          30 : #define PROVIDER_CNT       ( 1UL)
      13          75 : #define FEAT_CNT_MAX       ( 8UL)
      14          84 : #define NET_DRIVER_CNT_MAX (16UL)
      15             : 
      16             : struct fd_auto_info {
      17             :   /* System */
      18             :   ulong linux_major;
      19             :   ulong linux_minor;
      20             : 
      21             :   /* Networking */
      22             :   char driver[ NAME_SZ ];
      23             :   int  is_virtual_if;
      24             :   int  is_bonded_if;
      25             :   uint bonded_if_slave_count;
      26             : };
      27             : typedef struct fd_auto_info fd_auto_info_t;
      28             : 
      29             : struct fd_auto_driver_rq {
      30             :   char const * name;
      31             :   ulong        min_linux_major;
      32             :   ulong        min_linux_minor;
      33             : 
      34             :   /* 0 = no max linux version */
      35             :   ulong        max_linux_major;
      36             :   ulong        max_linux_minor;
      37             : };
      38             : typedef struct fd_auto_driver_rq fd_auto_driver_rq_t;
      39             : 
      40             : struct fd_auto_feat {
      41             :   char const *         name;
      42             :   fd_auto_driver_rq_t  supported_drivers[ NET_DRIVER_CNT_MAX ];
      43             : 
      44             :   /* Checks if networking feature is auto and sets the default */
      45             :   int  (*is_feat_auto)( fd_config_t          * config );
      46             :   int  (*check       )( fd_config_t    const * config,
      47             :                         fd_auto_info_t const * info   );
      48             :   void (*apply       )( fd_config_t          * config );
      49             : };
      50             : typedef struct fd_auto_feat fd_auto_feat_t;
      51             : 
      52             : struct fd_auto_provider {
      53             :   char const *   name;
      54             :   /* Later features observe earlier features updates to config,
      55             :      so the order is important.  e.g. ZC checks xdp_mode is DRV
      56             :      so DRV needs to come before ZC in the feats ordering. */
      57             :   fd_auto_feat_t feats[ FEAT_CNT_MAX ];
      58             : 
      59             :   int (*check)( fd_config_t    const * config,
      60             :                 fd_auto_info_t const * info );
      61             : };
      62             : typedef struct fd_auto_provider fd_auto_provider_t;
      63             : 
      64             : /* XDP checks/apply */
      65             : 
      66             : static int
      67             : check_xdp_auto( fd_config_t    const * config,
      68          15 :                 fd_auto_info_t const * info FD_PARAM_UNUSED ) {
      69          15 :   if( strcmp( config->net.provider, "xdp" ) ) return 0;
      70          12 :   return 1;
      71          15 : }
      72             : 
      73             : static int
      74          15 : is_xdp_native_bond_auto( fd_config_t * config ) {
      75          15 :   if( 2!=config->net.xdp.native_bond ) return 0;
      76             :   /* Set to default */
      77          15 :   config->net.xdp.native_bond = 0;
      78          15 :   return 1;
      79          15 : }
      80             : 
      81             : static int
      82             : xdp_native_bond_check( fd_config_t    const * config,
      83           6 :                        fd_auto_info_t const * info ) {
      84           6 :   if( !info->is_bonded_if ) return 0;
      85             : 
      86           3 :   if( 0==info->bonded_if_slave_count || info->bonded_if_slave_count>FD_NET_BOND_SLAVE_MAX ) return 0;
      87             : 
      88             :   /* net_tile_count must be a multiple of the bonded interface's slave count */
      89           3 :   if( 0!=config->layout.net_tile_count%info->bonded_if_slave_count ) return 0;
      90             : 
      91           3 :   return 1;
      92           3 : }
      93             : 
      94             : static void
      95           3 : xdp_native_bond_apply( fd_config_t * config ) {
      96           3 :   config->net.xdp.native_bond = 1;
      97           3 : }
      98             : 
      99             : static int
     100          15 : is_xdp_mode_auto( fd_config_t * config ) {
     101          15 :   if( strcmp( config->net.xdp.xdp_mode, "auto" ) ) return 0;
     102             :   /* Set to default */
     103          15 :   fd_memcpy( config->net.xdp.xdp_mode, "skb", 4 );
     104          15 :   return 1;
     105          15 : }
     106             : 
     107             : static int
     108             : xdp_drv_check( fd_config_t    const * config,
     109           6 :                fd_auto_info_t const * info ) {
     110           6 :   if( info->is_virtual_if &&
     111           6 :       !config->net.xdp.native_bond ) return 0;
     112           6 :   return 1;
     113           6 : }
     114             : 
     115             : static void
     116           6 : xdp_drv_apply( fd_config_t * config ) {
     117           6 :   fd_memcpy( config->net.xdp.xdp_mode, "drv", 4 );
     118           6 : }
     119             : 
     120             : static int
     121          15 : is_xdp_prefbusy_auto( fd_config_t * config ) {
     122          15 :   if( strcmp( config->net.xdp.poll_mode, "auto" ) ) return 0;
     123             :   /* Set to default */
     124          15 :   fd_memcpy( config->net.xdp.poll_mode, "softirq", 8 );
     125          15 :   return 1;
     126          15 : }
     127             : 
     128             : static int
     129             : xdp_prefbusy_check( fd_config_t    const * config,
     130           6 :                     fd_auto_info_t const * info FD_PARAM_UNUSED ) {
     131           6 :   if( strcmp( config->net.xdp.xdp_mode, "drv") ) return 0;
     132           6 :   return 1;
     133           6 : }
     134             : 
     135             : static void
     136           6 : xdp_prefbusy_apply( fd_config_t * config ) {
     137           6 :   fd_memcpy( config->net.xdp.poll_mode, "prefbusy", 9 );
     138           6 : }
     139             : 
     140             : static int
     141          15 : is_xdp_zc_auto( fd_config_t * config ) {
     142          15 :   if( 2!=config->net.xdp.xdp_zero_copy ) return 0;
     143             :   /* Set to default */
     144          15 :   config->net.xdp.xdp_zero_copy = 0;
     145          15 :   return 1;
     146          15 : }
     147             : 
     148             : static int
     149             : xdp_zc_check( fd_config_t    const * config FD_PARAM_UNUSED,
     150           6 :               fd_auto_info_t const * info   FD_PARAM_UNUSED ) {
     151             :   /* zc turned off for initial config auto rollout just to
     152             :      be safe. */
     153           6 :   return 0;
     154           6 : }
     155             : 
     156             : static void
     157           0 : xdp_zc_apply( fd_config_t * config ) {
     158           0 :   config->net.xdp.xdp_zero_copy = 1;
     159           0 : }
     160             : 
     161             : /* Each feature's supported Linux version matrix per driver decided
     162             :    based on fd-linux-version-testbed test results. */
     163             : static const fd_auto_provider_t NET_PROVIDERS[] = {
     164             :   {
     165             :     .name  = "XDP",
     166             :     .check = check_xdp_auto,
     167             :     .feats = {
     168             :       {
     169             :         .name              = "Native Bond",
     170             :         .supported_drivers = { { "mlx5_core", 5, 15, 0, 0} },
     171             :         .is_feat_auto      = is_xdp_native_bond_auto,
     172             :         .check             = xdp_native_bond_check,
     173             :         .apply             = xdp_native_bond_apply
     174             :       },
     175             :       {
     176             :         .name              = "DRV",
     177             :         .supported_drivers = {
     178             :           { "mlx5_core", 5, 15, 6, 3 },
     179             :           { "mlx5_core", 6,  5, 0, 0 },
     180             :         },
     181             :         .is_feat_auto      = is_xdp_mode_auto,
     182             :         .check             = xdp_drv_check,
     183             :         .apply             = xdp_drv_apply,
     184             :       },
     185             :       {
     186             :         .name              = "Prefbusy",
     187             :         .supported_drivers = { { "mlx5_core", 5, 15, 0, 0 } },
     188             :         .is_feat_auto      = is_xdp_prefbusy_auto,
     189             :         .check             = xdp_prefbusy_check,
     190             :         .apply             = xdp_prefbusy_apply
     191             :       },
     192             :       {
     193             :         .name              = "Zero Copy",
     194             :         .supported_drivers = { { "mlx5_core", 6, 1, 0, 0  } },
     195             :         .is_feat_auto      = is_xdp_zc_auto,
     196             :         .check             = xdp_zc_check,
     197             :         .apply             = xdp_zc_apply
     198             :       }
     199             :     }
     200             :   }
     201             : };
     202             : 
     203             : static void
     204           0 : scrape_system( fd_auto_info_t * info ) {
     205           0 :   struct utsname utsname;
     206           0 :   if( FD_UNLIKELY( -1==uname( &utsname ) ) ) {
     207           0 :     FD_LOG_WARNING(( "uname() failed (%i-%s), auto config skipping kernel version detection",
     208           0 :                      errno, fd_io_strerror( errno ) ));
     209           0 :     return;
     210           0 :   }
     211             : 
     212             :   /* utsname.release is typically "major.minor.patch-distrojunk",
     213             :      e.g. "6.8.0-45-generic" or "5.14.0-362.8.1.el9_3.x86_64".  We
     214             :      only care about major.minor.  A missing ".minor" is treated as
     215             :      minor 0.  An unparseable release leaves {0,0}, which fails all
     216             :      version requirements (fail-soft). */
     217             : 
     218           0 :   char const * cur = utsname.release;
     219           0 :   char *       end = NULL;
     220             : 
     221           0 :   ulong major = strtoul( cur, &end, 10 );
     222           0 :   if( FD_UNLIKELY( end==cur ) ) {
     223           0 :     FD_LOG_WARNING(( "unrecognized kernel release `%s`, auto config skipping kernel version detection",
     224           0 :                      utsname.release ));
     225           0 :     return;
     226           0 :   }
     227             : 
     228           0 :   ulong minor = 0UL;
     229           0 :   if( FD_LIKELY( end[0]=='.' ) ) {
     230           0 :     cur   = end+1;
     231           0 :     minor = strtoul( cur, &end, 10 );
     232           0 :     if( FD_UNLIKELY( end==cur ) ) minor = 0UL; /* tolerate "6." */
     233           0 :   }
     234             : 
     235           0 :   info->linux_major = major;
     236           0 :   info->linux_minor = minor;
     237           0 : }
     238             : 
     239             : static void
     240             : scrape_driver( char       * driver,
     241           0 :                char const * if_name ) {
     242           0 :   char path[ PATH_MAX ], target[ PATH_MAX ];
     243           0 :   driver[0] = '\0';
     244           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/class/net/%s/device/driver", if_name ) );
     245             : 
     246           0 :   long n = readlink( path, target, PATH_MAX-1 );
     247           0 :   if( FD_UNLIKELY( n<0L ) ) return;
     248           0 :   target[ n ] = '\0';  /* readlink does not NUL-terminate */
     249             : 
     250           0 :   char const * base = strrchr( target, '/' );
     251           0 :   fd_cstr_ncpy( driver, base ? base+1 : target, NAME_SZ );
     252           0 : }
     253             : 
     254             : static void
     255             : scrape_networking( fd_auto_info_t * info,
     256           0 :                    char const     * if_name ) {
     257             :   /* Check for virtual interface */
     258           0 :   char path[ PATH_MAX ];
     259           0 :   FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/sys/class/net/%s/device", if_name ) );
     260           0 :   info->is_virtual_if = ( -1==access( path, F_OK ) );
     261             : 
     262             :   /* Check for bond */
     263           0 :   info->is_bonded_if = fd_bonding_is_master( if_name );
     264           0 :   if( info->is_bonded_if ) info->bonded_if_slave_count = (uint)fd_bonding_slave_cnt( if_name );
     265             : 
     266             :   /* Get driver name.  A bond master reports "n/a" so no driver specific
     267             :      config is applied. If all slaves share a driver name then reports
     268             :      that instead. */
     269           0 :   if( info->is_bonded_if ) {
     270           0 :     fd_bonding_slave_iter_t iter_[1];
     271           0 :     for( fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, if_name );
     272           0 :          !fd_bonding_slave_iter_done( iter );
     273           0 :          fd_bonding_slave_iter_next ( iter ) ) {
     274             : 
     275           0 :       char slave_driver[ NAME_SZ ];
     276           0 :       scrape_driver( slave_driver, fd_bonding_slave_iter_ele( iter ) );
     277           0 :       if( FD_UNLIKELY( !slave_driver[0] ||
     278           0 :                      ( info->driver[0]  && strcmp( info->driver, slave_driver ) ) ) ) {
     279           0 :         fd_memcpy( info->driver, "n/a", 4 );
     280           0 :         break;
     281           0 :       }
     282           0 :       fd_cstr_ncpy( info->driver, slave_driver, NAME_SZ );
     283           0 :     }
     284           0 :   } else {
     285           0 :     scrape_driver( info->driver, if_name );
     286           0 :   }
     287           0 : }
     288             : 
     289             : static fd_auto_info_t
     290           0 : fd_auto_scrape_info( fd_config_t const * config ) {
     291           0 :   fd_auto_info_t info = {0};
     292             : 
     293           0 :   scrape_system    ( &info                        );
     294           0 :   scrape_networking( &info, config->net.interface );
     295             : 
     296           0 :   return info;
     297           0 : }
     298             : 
     299             : static int
     300             : fd_auto_check_driver( fd_auto_info_t      const * info,
     301          48 :                       fd_auto_driver_rq_t const * supported_drivers ) {
     302             :   /* Check for driver requirements. */
     303          48 :   if( !supported_drivers[0].name ) return 1;
     304             : 
     305          84 :   for( ulong i=0UL; i<NET_DRIVER_CNT_MAX; i++ ) {
     306          84 :     fd_auto_driver_rq_t const * req = &supported_drivers[ i ];
     307          84 :     if( !req->name ) return 0;
     308             : 
     309          60 :     if( 0==strcmp( info->driver, req->name ) ) {
     310             :       /* Check system linux version is within bounds of min and max
     311             :          of what this driver req requires. */
     312          45 :       if( req->max_linux_major > 0UL ) {
     313           9 :         if( info->linux_major>req->max_linux_major ||
     314           9 :           ( info->linux_major==req->max_linux_major &&
     315           6 :             info->linux_minor>req->max_linux_minor ) ) continue;
     316           9 :       }
     317             : 
     318             : 
     319          39 :       if( info->linux_major>req->min_linux_major ||
     320          39 :         ( info->linux_major==req->min_linux_major &&
     321          24 :           info->linux_minor>=req->min_linux_minor ) ) return 1;
     322          39 :     }
     323          60 :   }
     324             : 
     325           0 :   return 0;
     326          48 : }
     327             : 
     328             : /* fd_auto_net resolves any "auto" fields in the networking
     329             : configuration. The resulting configuration is optimized for the system
     330             : but won't always maximally optimize, this is to reduce risk of failures. */
     331             : static void
     332             : fd_auto_net( fd_config_t          * config,
     333          15 :              fd_auto_info_t const * info ) {
     334             :   /* Providers are in order of priority with first being the highest */
     335          15 :   int is_provider_set = 0;
     336          30 :   for( ulong p=0UL; p<PROVIDER_CNT; p++ ) {
     337          15 :     fd_auto_provider_t const * provider = &NET_PROVIDERS[p];
     338             : 
     339             :     /* Check provider requirements */
     340          15 :     int is_chosen_provider = !is_provider_set && ( !provider->check || provider->check( config, info ) );
     341          15 :     if( is_chosen_provider ) is_provider_set = 1;
     342             : 
     343          75 :     for( ulong f=0UL; f<FEAT_CNT_MAX; f++ ) {
     344          75 :       fd_auto_feat_t const * feat = &provider->feats[f];
     345          75 :       if( !feat->name ) break;
     346             : 
     347             :       /* Checks feature is set to "auto", if so replaces "auto" with
     348             :          default and goes onto the next checks */
     349          60 :       if( !feat->is_feat_auto( config ) ) continue;
     350             : 
     351          60 :       if( !is_chosen_provider ||
     352          60 :           !strcmp( config->net.auto_level, "minimal" ) ) continue;
     353             : 
     354             :       /* Feature's driver/Linux version requirements */
     355          48 :       if( !fd_auto_check_driver( info, feat->supported_drivers ) ) continue;
     356             : 
     357             :       /* Feature's other requirements */
     358          24 :       if( feat->check && !feat->check( config, info ) ) continue;
     359             : 
     360          15 :       if( FD_UNLIKELY( !feat->apply ) ) {
     361           0 :         FD_LOG_ERR(( "Applying auto configure net feature %s failed since no apply function was found.", feat->name ));
     362           0 :       }
     363          15 :       feat->apply( config );
     364          15 :     }
     365          15 :   }
     366          15 : }
     367             : 
     368             : void
     369           0 : fd_config_auto( fd_config_t * config ) {
     370           0 :   fd_auto_info_t info = fd_auto_scrape_info( config );
     371           0 :   fd_auto_net( config, &info );
     372             : 
     373           0 :   fd_cstr_printf( config->auto_config_log, sizeof(config->auto_config_log), NULL,
     374           0 :       "network auto configure level=%s, provider=%s xdp_mode=%s poll_mode=%s zero_copy=%d native_bond=%d (driver=%s kernel=%lu.%lu virtual_if=%d bonded_if=%d slaves=%u, net_tile_cnt=%u)",
     375           0 :       config->net.auto_level,
     376           0 :       config->net.provider,
     377           0 :       config->net.xdp.xdp_mode,
     378           0 :       config->net.xdp.poll_mode,
     379           0 :       config->net.xdp.xdp_zero_copy,
     380           0 :       config->net.xdp.native_bond,
     381           0 :       info.driver[0] ? info.driver : "unknown",
     382           0 :       info.linux_major, info.linux_minor,
     383           0 :       info.is_virtual_if,
     384           0 :       info.is_bonded_if,
     385           0 :       info.bonded_if_slave_count,
     386           0 :       config->layout.net_tile_count );
     387           0 : }

Generated by: LCOV version 1.14