LCOV - code coverage report
Current view: top level - app/shared/commands/configure - ethtool-offloads.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 75 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /* This stage checks and modifies various ethtool features on the main
       2             :    and loopback interfaces.
       3             : 
       4             :      - "Generic Receive Offload": If enabled, may greatly increase
       5             :      throughput for sockets-based TCP flows, such as HTTP snapshot
       6             :      downloads.  This stage will log a warning if GRO is disabled, but
       7             :      does not modify the flag.
       8             : 
       9             :      - "RX UDP GRO Forwarding": If left enabled, may aggregate multiple
      10             :      UDP packets into a single large superpacket.  This would normally
      11             :      be split later for socket recv() calls, but AF_XDP delivers the
      12             :      full superpacket which confuses the application layer.  Disabled
      13             :      by this stage.
      14             : 
      15             :      - "GRE Segmentation Offload": This feature has been known to cause
      16             :      corruption of packets sent via normal sockets while XDP is in use
      17             :      on the same system.  Disabled by this stage. */
      18             : 
      19             : #include "configure.h"
      20             : 
      21             : #include "fd_ethtool_ioctl.h"
      22             : #include "../../../../disco/net/fd_linux_bond.h"
      23             : 
      24           0 : #define NAME "ethtool-offloads"
      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, "disable network device features with `ethtool --offload INTF FEATURE off`" );
      30           0 : }
      31             : 
      32             : 
      33             : static void
      34             : init_device( char const * device,
      35           0 :              int          xdp ) {
      36           0 :   if( !xdp ) return;
      37             : 
      38           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
      39           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
      40           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
      41             : 
      42             :   /* turn off rx-udp-gro-forwarding, which is entirely incompatible with
      43             :    * AF_XDP and QUIC
      44             :    * It results in multiple UDP payloads being merged into a single UDP packet,
      45             :    * with IP and UDP headers rewritten, combining the lengths and updating the
      46             :    * checksums. QUIC short packets cannot be processed reliably in this case. */
      47           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_RXUDPGROFWD,  0 ) );
      48             : 
      49             :   /* turn off tx-gre-segmentation and tx-gre-csum-segmentation.  When
      50             :      enabled, some packets sent via normal sockets can be corrupted
      51             :      while XDP is in use on the same system. */
      52           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_TXGRESEG,     0 ) );
      53           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_TXGRECSUMSEG, 0 ) );
      54           0 : }
      55             : 
      56             : static void
      57           0 : init( fd_config_t const * config ) {
      58           0 :   int const xdp = 0==strcmp( config->net.provider, "xdp" );
      59           0 :   if( FD_UNLIKELY( fd_bonding_is_master( config->net.interface ) ) ) {
      60           0 :     fd_bonding_slave_iter_t iter_[1];
      61           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
      62           0 :     for( ; !fd_bonding_slave_iter_done( iter );
      63           0 :          fd_bonding_slave_iter_next( iter ) ) {
      64           0 :       init_device( fd_bonding_slave_iter_ele( iter ), xdp );
      65           0 :     }
      66           0 :   } else {
      67           0 :     init_device( config->net.interface, xdp );
      68           0 :   }
      69           0 :   init_device( "lo", xdp );
      70           0 : }
      71             : 
      72             : static configure_result_t
      73             : check_device( char const * device,
      74             :               int          xdp,
      75           0 :               int          warn_gro ) {
      76           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
      77           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
      78           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
      79             : 
      80           0 :   if( warn_gro ) {
      81           0 :     int gro_active, gro_supported;
      82           0 :     if( FD_LIKELY( 0==fd_ethtool_ioctl_feature_gro_test( &ioc, &gro_active, &gro_supported ) ) ) {
      83           0 :       if( FD_UNLIKELY( !gro_active && gro_supported ) ) {
      84           0 :         FD_LOG_WARNING(( "network device `%s` has generic-receive-offload disabled.  "
      85           0 :                          "Consider enabling with `ethtool --offload %s generic-receive-offload on`.  "
      86           0 :                          "Proceeding but performance may be reduced.", device, device ));
      87           0 :       }
      88           0 :     }
      89           0 :   }
      90             : 
      91           0 :   if( xdp ) {
      92           0 :     int udpgrofwd_active;
      93           0 :     int greseg_active;
      94           0 :     int grecsumseg_active;
      95           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_RXUDPGROFWD,  &udpgrofwd_active  ) );
      96           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_TXGRESEG,     &greseg_active     ) );
      97           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_TXGRECSUMSEG, &grecsumseg_active ) );
      98             : 
      99           0 :     if( FD_UNLIKELY( udpgrofwd_active ) )
     100           0 :       NOT_CONFIGURED( "device `%s` has rx-udp-gro-forwarding enabled. Should be disabled", device );
     101           0 :     if( FD_UNLIKELY( greseg_active ) )
     102           0 :       NOT_CONFIGURED( "device `%s` has tx-gre-segmentation enabled. Should be disabled", device );
     103           0 :     if( FD_UNLIKELY( grecsumseg_active ) )
     104           0 :       NOT_CONFIGURED( "device `%s` has tx-gre-csum-segmentation enabled. Should be disabled", device );
     105           0 :   }
     106             : 
     107           0 :   CONFIGURE_OK();
     108           0 : }
     109             : 
     110             : static configure_result_t
     111             : check( fd_config_t const * config,
     112           0 :        int                 check_type ) {
     113           0 :   int warn_gro = check_type==FD_CONFIGURE_CHECK_TYPE_PRE_INIT ||
     114           0 :                  check_type==FD_CONFIGURE_CHECK_TYPE_CHECK ||
     115           0 :                  check_type==FD_CONFIGURE_CHECK_TYPE_RUN;
     116           0 :   int const xdp = 0==strcmp( config->net.provider, "xdp" );
     117           0 :   if( FD_UNLIKELY( fd_bonding_is_master( config->net.interface ) ) ) {
     118           0 :     fd_bonding_slave_iter_t iter_[1];
     119           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     120           0 :     for( ; !fd_bonding_slave_iter_done( iter );
     121           0 :          fd_bonding_slave_iter_next( iter ) ) {
     122           0 :       CHECK( check_device( fd_bonding_slave_iter_ele( iter ), xdp, warn_gro ) );
     123           0 :     }
     124           0 :   } else {
     125           0 :     CHECK( check_device( config->net.interface, xdp, warn_gro ) );
     126           0 :   }
     127           0 :   CHECK( check_device( "lo", xdp, 0 ) );
     128             : 
     129           0 :   CONFIGURE_OK();
     130           0 : }
     131             : 
     132             : configure_stage_t fd_cfg_stage_ethtool_offloads = {
     133             :   .name            = NAME,
     134             :   .always_recreate = 0,
     135             :   .init_perm       = init_perm,
     136             :   .fini_perm       = NULL,
     137             :   .init            = init,
     138             :   .fini            = NULL,
     139             :   .check           = check,
     140             : };
     141             : 
     142             : #undef NAME

Generated by: LCOV version 1.14