LCOV - code coverage report
Current view: top level - app/shared/commands/configure - ethtool-channels.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 316 0.0 %
Date: 2025-11-19 04:34:25 Functions: 0 11 0.0 %

          Line data    Source code
       1             : #include "configure.h"
       2             : 
       3             : #include <errno.h>
       4             : #include <unistd.h>
       5             : 
       6             : #include "fd_ethtool_ioctl.h"
       7             : #include "../../../../disco/net/fd_linux_bond.h"
       8             : 
       9           0 : #define NAME "ethtool-channels"
      10             : 
      11             : static int fini_device( char const * device );
      12             : 
      13             : static int
      14           0 : enabled( fd_config_t const * config ) {
      15             : 
      16             :   /* if we're running in a network namespace, we configure ethtool on
      17             :      the virtual device as part of netns setup, not here */
      18           0 :   if( config->development.netns.enabled ) return 0;
      19             : 
      20             :   /* only enable if network stack is XDP */
      21           0 :   if( 0!=strcmp( config->net.provider, "xdp" ) ) return 0;
      22             : 
      23           0 :   return 1;
      24           0 : }
      25             : 
      26             : static void
      27             : init_perm( fd_cap_chk_t *      chk,
      28           0 :            fd_config_t const * config FD_PARAM_UNUSED ) {
      29           0 :   fd_cap_chk_root( chk, NAME, "modify network device configuration with ethtool" );
      30           0 : }
      31             : 
      32             : static void
      33             : fini_perm( fd_cap_chk_t *      chk,
      34           0 :            fd_config_t const * config FD_PARAM_UNUSED ) {
      35           0 :   fd_cap_chk_root( chk, NAME, "modify network device configuration with ethtool" );
      36           0 : }
      37             : 
      38             : /* FIXME: Centrally define listen port list to avoid this configure
      39             :    stage from going out of sync with port mappings. */
      40             : static uint
      41             : get_ports( fd_config_t const * config,
      42           0 :            ushort *            ports ) {
      43           0 :   uint port_cnt = 0U;
      44             : 
      45           0 : #define ADD_PORT( p ) do { \
      46           0 :   ushort __port = ( p ); \
      47           0 :   if( FD_UNLIKELY( __port==0U ) ) break; \
      48           0 :   int __dupe = 0; \
      49           0 :   for( uint __p=0U; !__dupe && __p<port_cnt; ++__p ) __dupe = (ports[ __p ]==__port); \
      50           0 :   if( FD_UNLIKELY( __dupe ) ) break; \
      51           0 :   ports[ port_cnt ] = __port; \
      52           0 :   port_cnt++; \
      53           0 : } while(0)
      54             : 
      55           0 :   ADD_PORT( config->tiles.shred.shred_listen_port              );
      56           0 :   ADD_PORT( config->tiles.quic.quic_transaction_listen_port    );
      57           0 :   ADD_PORT( config->tiles.quic.regular_transaction_listen_port );
      58           0 :   if( config->is_firedancer ) {
      59           0 :     ADD_PORT( config->gossip.port                              );
      60           0 :     ADD_PORT( config->tiles.repair.repair_intake_listen_port   );
      61           0 :     ADD_PORT( config->tiles.repair.repair_serve_listen_port    );
      62           0 :     ADD_PORT( config->tiles.send.send_src_port                 );
      63           0 :   }
      64           0 : #undef ADD_PORT
      65             : 
      66           0 :   return port_cnt;
      67           0 : }
      68             : 
      69             : /* Attempts to initialize the device in simple or dedicated mode.  If
      70             :    strict is true, FD_LOG_ERR's on failure.  Otherwise, returns 1 on
      71             :    failure. Returns 0 on success. */
      72             : static int
      73             : init_device( char const *        device,
      74             :              fd_config_t const * config,
      75             :              int                 dedicated_mode,
      76             :              int                 strict,
      77           0 :              uint                device_cnt ) {
      78           0 :   FD_TEST( dedicated_mode || strict );
      79             : 
      80           0 :   uint const net_tile_cnt = config->layout.net_tile_count;
      81           0 :   if( FD_UNLIKELY( net_tile_cnt%device_cnt!=0 ) ) {
      82           0 :     FD_LOG_ERR(( "net tile count %u 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 ));
      83           0 :   }
      84           0 :   uint const queue_cnt = net_tile_cnt / device_cnt;
      85             : 
      86           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
      87           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
      88           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
      89             : 
      90             :   /* This should happen first, otherwise changing the number of channels may fail */
      91           0 :   FD_TEST( 0==fd_ethtool_ioctl_rxfh_set_default( &ioc ) );
      92             : 
      93           0 :   uint const num_channels = !dedicated_mode ? queue_cnt : 0 /* maximum allowed */;
      94           0 :   int ret = fd_ethtool_ioctl_channels_set_num( &ioc, num_channels );
      95           0 :   if( FD_UNLIKELY( 0!=ret ) ) {
      96           0 :     if( strict ) {
      97           0 :       if( FD_LIKELY( ret == EBUSY ) )
      98           0 :         FD_LOG_ERR(( "error configuring network device (%s), failed to set number of channels. "
      99           0 :                      "This is most commonly caused by an issue with the Intel ice driver on certain versions "
     100           0 :                      "of Ubuntu.  If you are using the ice driver, `sudo dmesg | grep %s` contains "
     101           0 :                      "messages about RDMA, and you do not need RDMA, try running `rmmod irdma` and/or "
     102           0 :                      "blacklisting the irdma kernel module.", device, device ));
     103           0 :       else
     104           0 :         FD_LOG_ERR(( "error configuring network device (%s), failed to set number of channels", device ));
     105           0 :     }
     106           0 :     return 1;
     107           0 :   }
     108             : 
     109             :   /* Some drivers (e.g. igb) put the RXFH table into an incorrect state
     110             :      after changing the channel count.  So in simple mode we reset it
     111             :      to the default again. */
     112           0 :   if( !dedicated_mode ) {
     113           0 :     FD_TEST( 0==fd_ethtool_ioctl_rxfh_set_default( &ioc ) );
     114           0 :   }
     115             : 
     116           0 :   FD_TEST( 0==fd_ethtool_ioctl_ntuple_clear( &ioc ) );
     117             : 
     118           0 :   if( dedicated_mode ) {
     119             :     /* Some drivers (e.g. ixgbe) reset the RXFH table upon activation
     120             :        of the ntuple feature, so we do this first. */
     121           0 :     if( FD_UNLIKELY( 0!=fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_NTUPLE, 1 ) ) ) {
     122           0 :       if( strict ) FD_LOG_ERR(( "error configuring network device (%s), failed to enable ntuple feature. Try `net.xdp.rss_queue_mode=\"simple\"`", device ));
     123           0 :       else         return 1;
     124           0 :     }
     125             : 
     126             :     /* Remove a queue from the rxfh table for each net tile. */
     127           0 :     uint rxfh_queue_cnt;
     128           0 :     FD_TEST( 0==fd_ethtool_ioctl_rxfh_get_queue_cnt( &ioc, &rxfh_queue_cnt ) );
     129           0 :     if( FD_UNLIKELY( queue_cnt>=rxfh_queue_cnt ) ) {
     130           0 :       if( strict ) FD_LOG_ERR(( "error configuring network device (%s), too many net tiles %u for queue count %u.  "
     131           0 :                                 "Try `net.xdp.rss_queue_mode=\"simple\"` or reduce net tile count",
     132           0 :                                 device, net_tile_cnt, rxfh_queue_cnt ));
     133           0 :       else         return 1;
     134           0 :     }
     135           0 :     if( FD_UNLIKELY( 0!=fd_ethtool_ioctl_rxfh_set_suffix( &ioc, queue_cnt ) ) ) {
     136           0 :       if( strict ) FD_LOG_ERR(( "error configuring network device (%s), failed to isolate queues. Try `net.xdp.rss_queue_mode=\"simple\"`", device ));
     137           0 :       else         return 1;
     138           0 :     }
     139             : 
     140             :     /* Add a ntuple rule for each listening destination port.  If there
     141             :        are multiple net tiles, create a group of rules for each tile. */
     142           0 :     int ntuple_error = 0;
     143           0 :     ushort ports[ 32 ];
     144           0 :     uint port_cnt = get_ports( config, ports );
     145           0 :     uint rule_idx = 0;
     146           0 :     uint const rule_group_cnt = fd_uint_pow2_up( queue_cnt );
     147           0 :     for( uint r=0U; !ntuple_error && r<rule_group_cnt; r++ ) {
     148           0 :       for( uint p=0U; !ntuple_error && p<port_cnt; p++ ) {
     149           0 :         ntuple_error = 0!=fd_ethtool_ioctl_ntuple_set_udp_dport( &ioc, rule_idx++, ports[ p ], r, rule_group_cnt, r%queue_cnt );
     150           0 :       }
     151           0 :     }
     152           0 :     if( FD_UNLIKELY( ntuple_error ) ) {
     153           0 :       if( strict ) FD_LOG_ERR(( "error configuring network device (%s), failed to install ntuple rules.  "
     154           0 :                                 "Try `net.xdp.rss_queue_mode=\"simple\"` or `layout.net_tile_count=1`", device ));
     155           0 :       else         return 1;
     156           0 :     }
     157           0 :   }
     158             : 
     159           0 :   return 0;
     160           0 : }
     161             : 
     162             : static void
     163           0 : init( fd_config_t const * config ) {
     164           0 :   int only_dedicated =
     165           0 :     (0==strcmp( config->net.xdp.rss_queue_mode, "dedicated" ));
     166           0 :   int try_dedicated = only_dedicated ||
     167           0 :     (0==strcmp( config->net.xdp.rss_queue_mode, "auto" ) );
     168             : 
     169             :   /* if using a bonded device, we need to set channels on the
     170             :      underlying devices. */
     171           0 :   int  is_bonded  = fd_bonding_is_master( config->net.interface );
     172           0 :   uint device_cnt = 1U;
     173           0 :   if( is_bonded && config->net.xdp.native_bond ) {
     174           0 :     device_cnt = fd_bonding_slave_cnt( config->net.interface );
     175           0 :   }
     176             : 
     177             :   /* If the mode was auto, we will try to init in dedicated mode but will
     178             :      not fail the stage if this is not successful.  If the mode was
     179             :      dedicated, we will require success. */
     180           0 :   if( try_dedicated ) {
     181           0 :     int failed = 0;
     182           0 :     if( is_bonded ) {
     183           0 :       fd_bonding_slave_iter_t iter_[1];
     184           0 :       fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     185           0 :       for( ; !failed && !fd_bonding_slave_iter_done( iter );
     186           0 :           fd_bonding_slave_iter_next( iter ) ) {
     187           0 :         failed = init_device( fd_bonding_slave_iter_ele( iter ), config, 1, only_dedicated, device_cnt );
     188           0 :       }
     189           0 :     } else {
     190           0 :       failed = init_device( config->net.interface, config, 1, only_dedicated, device_cnt );
     191           0 :     }
     192           0 :     if( !failed ) return;
     193           0 :     FD_TEST( !only_dedicated );
     194           0 :     FD_LOG_WARNING(( "error configuring network device (%s), rss_queue_mode \"auto\" attempted"
     195           0 :                      " \"dedicated\" configuration but falling back to \"simple\".", config->net.interface ));
     196             :     /* Wipe partial dedicated configuration before simple init */
     197           0 :     if( is_bonded ) {
     198           0 :       fd_bonding_slave_iter_t iter_[1];
     199           0 :       fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     200           0 :       for( ; !fd_bonding_slave_iter_done( iter );
     201           0 :           fd_bonding_slave_iter_next( iter ) ) {
     202           0 :         fini_device( fd_bonding_slave_iter_ele( iter ) );
     203           0 :       }
     204           0 :     }
     205           0 :     else {
     206           0 :       fini_device( config->net.interface );
     207           0 :     }
     208           0 :   }
     209             : 
     210             :   /* Require success for simple mode, either configured or as fallback */
     211           0 :   if( is_bonded ) {
     212           0 :     fd_bonding_slave_iter_t iter_[1];
     213           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     214           0 :     for( ; !fd_bonding_slave_iter_done( iter );
     215           0 :         fd_bonding_slave_iter_next( iter ) ) {
     216           0 :       init_device( fd_bonding_slave_iter_ele( iter ), config, 0, 1, device_cnt );
     217           0 :     }
     218           0 :   } else {
     219           0 :     init_device( config->net.interface, config, 0, 1, device_cnt );
     220           0 :   }
     221           0 : }
     222             : 
     223             : /* Returns whether anything is changed from the default (fini'd) state */
     224             : static int
     225           0 : check_device_is_modified( char const * device ) {
     226           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
     227           0 :   if( FD_UNLIKELY( &ioc!=fd_ethtool_ioctl_init( &ioc, device ) ) )
     228           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
     229             : 
     230           0 :   fd_ethtool_ioctl_channels_t channels;
     231           0 :   FD_TEST( 0==fd_ethtool_ioctl_channels_get_num( &ioc, &channels ) );
     232           0 :   if( channels.current!=channels.max ) return 1;
     233             : 
     234           0 :   uint rxfh_queue_cnt;
     235           0 :   FD_TEST( 0==fd_ethtool_ioctl_rxfh_get_queue_cnt( &ioc, &rxfh_queue_cnt ) );
     236             : 
     237           0 :   uint rxfh_table[ FD_ETHTOOL_MAX_RXFH_TABLE_CNT ] = { 0 };
     238           0 :   uint rxfh_table_ele_cnt;
     239           0 :   FD_TEST( 0==fd_ethtool_ioctl_rxfh_get_table( &ioc, rxfh_table, &rxfh_table_ele_cnt ) );
     240           0 :   for( uint j=0U, q=0U; j<rxfh_table_ele_cnt; j++) {
     241           0 :     if( rxfh_table[ j ]!=q++ ) return 1;
     242           0 :     if( q>=rxfh_queue_cnt ) q = 0;
     243           0 :   }
     244             : 
     245           0 :   int ntuple_rules_empty;
     246           0 :   FD_TEST( 0==fd_ethtool_ioctl_ntuple_validate_udp_dport( &ioc, NULL, 0, 0, &ntuple_rules_empty ) );
     247           0 :   if( !ntuple_rules_empty ) return 1;
     248             : 
     249           0 :   return 0;
     250           0 : }
     251             : 
     252             : static int
     253             : check_device_is_configured( char const *        device,
     254             :                             fd_config_t const * config,
     255             :                             int                 dedicated_mode,
     256           0 :                             uint                device_cnt ) {
     257           0 :   uint const net_tile_cnt = config->layout.net_tile_count;
     258           0 :   if( FD_UNLIKELY( net_tile_cnt%device_cnt!=0 ) ) {
     259           0 :     FD_LOG_ERR(( "net tile count %u 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 ));
     260           0 :   }
     261           0 :   uint const queue_cnt = net_tile_cnt / device_cnt;
     262             : 
     263           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
     264           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
     265           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
     266             : 
     267           0 :   fd_ethtool_ioctl_channels_t channels;
     268           0 :   FD_TEST( 0==fd_ethtool_ioctl_channels_get_num( &ioc, &channels ) );
     269           0 :   if( channels.current!=(dedicated_mode ? channels.max : queue_cnt) ) return 0;
     270             : 
     271           0 :   uint rxfh_queue_cnt;
     272           0 :   FD_TEST( 0==fd_ethtool_ioctl_rxfh_get_queue_cnt( &ioc, &rxfh_queue_cnt ) );
     273           0 :   rxfh_queue_cnt = fd_uint_min( rxfh_queue_cnt, channels.current );
     274             : 
     275           0 :   uint rxfh_table[ FD_ETHTOOL_MAX_RXFH_TABLE_CNT ] = { 0 };
     276           0 :   uint rxfh_table_ele_cnt;
     277           0 :   FD_TEST( 0==fd_ethtool_ioctl_rxfh_get_table( &ioc, rxfh_table, &rxfh_table_ele_cnt ) );
     278           0 :   int rxfh_error = (dedicated_mode && 0U==rxfh_table_ele_cnt);
     279           0 :   uint const start_queue = dedicated_mode ? queue_cnt : 0U;
     280           0 :   for( uint j=0U, q=start_queue; !rxfh_error && j<rxfh_table_ele_cnt; j++) {
     281           0 :     rxfh_error = (rxfh_table[ j ]!=q++);
     282           0 :     if( FD_UNLIKELY( q>=rxfh_queue_cnt ) ) q = start_queue;
     283           0 :   }
     284           0 :   if( rxfh_error ) return 0;
     285             : 
     286           0 :   if( dedicated_mode ) {
     287           0 :     int ntuple_feature_active;
     288           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_NTUPLE, &ntuple_feature_active ) );
     289           0 :     if( !ntuple_feature_active ) return 0;
     290           0 :   }
     291             : 
     292           0 :   if( !dedicated_mode ) {
     293           0 :     int ntuple_rules_empty;
     294           0 :     FD_TEST( 0==fd_ethtool_ioctl_ntuple_validate_udp_dport( &ioc, NULL, 0, 0, &ntuple_rules_empty ) );
     295           0 :     if( !ntuple_rules_empty ) return 0;
     296           0 :   } else {
     297           0 :     int ports_valid;
     298           0 :     ushort ports[ 32 ];
     299           0 :     uint port_cnt = get_ports( config, ports );
     300           0 :     FD_TEST( 0==fd_ethtool_ioctl_ntuple_validate_udp_dport( &ioc, ports, port_cnt, queue_cnt, &ports_valid ));
     301           0 :     if( !ports_valid ) return 0;
     302           0 :   }
     303             : 
     304           0 :   return 1;
     305           0 : }
     306             : 
     307             : static configure_result_t
     308             : check( fd_config_t const * config,
     309           0 :        int                 check_type FD_PARAM_UNUSED ) {
     310           0 :   int only_dedicated =
     311           0 :     (0==strcmp( config->net.xdp.rss_queue_mode, "dedicated" ));
     312           0 :   int check_dedicated = only_dedicated ||
     313           0 :     (0==strcmp( config->net.xdp.rss_queue_mode, "auto" ));
     314             : 
     315           0 :   int  is_bonded  = fd_bonding_is_master( config->net.interface );
     316           0 :   uint device_cnt = 1U;
     317           0 :   if( is_bonded && config->net.xdp.native_bond ) {
     318           0 :     device_cnt = fd_bonding_slave_cnt( config->net.interface );
     319           0 :   }
     320             : 
     321           0 :   if( check_dedicated ) {
     322           0 :     int is_configured = 1;
     323           0 :     if( is_bonded ) {
     324           0 :       fd_bonding_slave_iter_t iter_[1];
     325           0 :       fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     326           0 :       for( ; is_configured && !fd_bonding_slave_iter_done( iter );
     327           0 :           fd_bonding_slave_iter_next( iter ) ) {
     328           0 :         is_configured = check_device_is_configured( fd_bonding_slave_iter_ele( iter ), config, 1, device_cnt );
     329           0 :       }
     330           0 :     } else {
     331           0 :       is_configured = check_device_is_configured( config->net.interface, config, 1, device_cnt );
     332           0 :     }
     333           0 :     if( is_configured ) CONFIGURE_OK();
     334           0 :   }
     335             : 
     336           0 :   if( !only_dedicated ) {
     337           0 :     int is_configured = 1;
     338           0 :     if( is_bonded ) {
     339           0 :       fd_bonding_slave_iter_t iter_[1];
     340           0 :       fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     341           0 :       for( ; is_configured && !fd_bonding_slave_iter_done( iter );
     342           0 :           fd_bonding_slave_iter_next( iter ) ) {
     343           0 :         is_configured = check_device_is_configured( fd_bonding_slave_iter_ele( iter ), config, 0, device_cnt );
     344           0 :       }
     345           0 :     } else {
     346           0 :       is_configured = check_device_is_configured( config->net.interface, config, 0, device_cnt );
     347           0 :     }
     348           0 :     if( is_configured ) CONFIGURE_OK();
     349           0 :   }
     350             : 
     351           0 :   int is_modified = 0;
     352           0 :   if( is_bonded ) {
     353           0 :     fd_bonding_slave_iter_t iter_[1];
     354           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     355           0 :     for( ; !is_modified && !fd_bonding_slave_iter_done( iter );
     356           0 :         fd_bonding_slave_iter_next( iter ) ) {
     357           0 :       is_modified = check_device_is_modified( fd_bonding_slave_iter_ele( iter ) );
     358           0 :     }
     359           0 :   } else {
     360           0 :     is_modified = check_device_is_modified( config->net.interface );
     361           0 :   }
     362           0 :   if( is_modified )
     363           0 :     PARTIALLY_CONFIGURED( "device `%s` has partial ethtool-channels network configuration", config->net.interface );
     364             : 
     365           0 :   NOT_CONFIGURED( "device `%s` missing ethtool-channels network configuration", config->net.interface );
     366           0 : }
     367             : 
     368             : static int
     369           0 : fini_device( char const * device ) {
     370           0 :   int error = 0;
     371             : 
     372           0 :   fd_ethtool_ioctl_t ioc;
     373           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
     374           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
     375             : 
     376             :   /* It may be the case for certain devices that the default state is
     377             :      the same as the init'd state (in simple mode).  In this case the
     378             :      following fini commands will all be noops, which is fine.  But we
     379             :      need to return 0 so that the configure stage logic does not
     380             :      consider this to be an error.  We compare the state before and
     381             :      after to see if anything was changed by fini. */
     382           0 :   fd_ethtool_ioctl_channels_t channels_orig;
     383           0 :   error |= (0!=fd_ethtool_ioctl_channels_get_num( &ioc, &channels_orig ));
     384           0 :   uint rxfh_table_orig[ FD_ETHTOOL_MAX_RXFH_TABLE_CNT ] = { 0 };
     385           0 :   uint rxfh_table_orig_ele_cnt;
     386           0 :   error |= (0!=fd_ethtool_ioctl_rxfh_get_table( &ioc, rxfh_table_orig, &rxfh_table_orig_ele_cnt ));
     387           0 :   int ntuple_rules_empty_orig;
     388           0 :   error |= (0!=fd_ethtool_ioctl_ntuple_validate_udp_dport( &ioc, NULL, 0, 0, &ntuple_rules_empty_orig ));
     389           0 :   if( FD_UNLIKELY( error ) )
     390           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to determine initial state", device ));
     391             : 
     392             :   /* We leave the ntuple feature flag as-is in fini */
     393           0 :   error |= (0!=fd_ethtool_ioctl_ntuple_clear( &ioc ));
     394             : 
     395             :   /* This should happen first, otherwise changing the number of channels may fail */
     396           0 :   error |= (0!=fd_ethtool_ioctl_rxfh_set_default( &ioc ));
     397             : 
     398           0 :   error |= (0!=fd_ethtool_ioctl_channels_set_num( &ioc, 0 /* max */ ));
     399             : 
     400             :   /* Some drivers (i40e) do not always evenly redistribute the RXFH table
     401             :      when increasing the channel count, so we run this again just in case. */
     402           0 :   error |= (0!=fd_ethtool_ioctl_rxfh_set_default( &ioc ));
     403             : 
     404           0 :   if( FD_UNLIKELY( error ) )
     405           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to set to default state", device ));
     406             : 
     407           0 :   fd_ethtool_ioctl_channels_t channels_new;
     408           0 :   error |= (0!=fd_ethtool_ioctl_channels_get_num( &ioc, &channels_new ));
     409           0 :   uint rxfh_table_new[ FD_ETHTOOL_MAX_RXFH_TABLE_CNT ] = { 0 };
     410           0 :   uint rxfh_table_new_ele_cnt;
     411           0 :   error |= (0!=fd_ethtool_ioctl_rxfh_get_table( &ioc, rxfh_table_new, &rxfh_table_new_ele_cnt ));
     412           0 :   int ntuple_rules_empty_new;
     413           0 :   error |= (0!=fd_ethtool_ioctl_ntuple_validate_udp_dport( &ioc, NULL, 0, 0, &ntuple_rules_empty_new ));
     414           0 :   if( FD_UNLIKELY( error ) )
     415           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to determine final state", device ));
     416             : 
     417           0 :   fd_ethtool_ioctl_fini( &ioc );
     418             : 
     419           0 :   int modified = (0!=memcmp( &channels_orig, &channels_new, sizeof(fd_ethtool_ioctl_channels_t) )) ||
     420           0 :                  (rxfh_table_orig_ele_cnt != rxfh_table_new_ele_cnt) ||
     421           0 :                  (0!=memcmp( rxfh_table_orig, rxfh_table_new, rxfh_table_orig_ele_cnt * sizeof(uint) )) ||
     422           0 :                  (ntuple_rules_empty_orig!=ntuple_rules_empty_new);
     423           0 :   return modified;
     424           0 : }
     425             : 
     426             : static int
     427             : fini( fd_config_t const * config,
     428           0 :       int                 pre_init FD_PARAM_UNUSED ) {
     429           0 :   int done = 0;
     430           0 :   if( FD_UNLIKELY( fd_bonding_is_master( config->net.interface ) ) ) {
     431           0 :     fd_bonding_slave_iter_t iter_[1];
     432           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     433           0 :     for( ; !fd_bonding_slave_iter_done( iter );
     434           0 :          fd_bonding_slave_iter_next( iter ) ) {
     435           0 :       done |= fini_device( fd_bonding_slave_iter_ele( iter ) );
     436           0 :     }
     437           0 :   } else {
     438           0 :     done = fini_device( config->net.interface );
     439           0 :   }
     440           0 :   return done;
     441           0 : }
     442             : 
     443             : configure_stage_t fd_cfg_stage_ethtool_channels = {
     444             :   .name            = NAME,
     445             :   .always_recreate = 0,
     446             :   .enabled         = enabled,
     447             :   .init_perm       = init_perm,
     448             :   .fini_perm       = fini_perm,
     449             :   .init            = init,
     450             :   .fini            = fini,
     451             :   .check           = check,
     452             : };
     453             : 
     454             : #undef NAME

Generated by: LCOV version 1.14