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

Generated by: LCOV version 1.14