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 79 0.0 %
Date: 2025-11-26 04:52:47 Functions: 0 6 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 int
      27           0 : enabled( fd_config_t const * config ) {
      28             : 
      29             :   /* if we're running in a network namespace, we configure ethtool on
      30             :      the virtual device as part of netns setup, not here */
      31           0 :   if( config->development.netns.enabled ) return 0;
      32             : 
      33           0 :   return 1;
      34           0 : }
      35             : 
      36             : static void
      37             : init_perm( fd_cap_chk_t *      chk,
      38           0 :            fd_config_t const * config FD_PARAM_UNUSED ) {
      39           0 :   fd_cap_chk_root( chk, NAME, "disable network device features with `ethtool --offload INTF FEATURE off`" );
      40           0 : }
      41             : 
      42             : 
      43             : static void
      44             : init_device( char const * device,
      45           0 :              int          xdp ) {
      46           0 :   if( !xdp ) return;
      47             : 
      48           0 :   fd_ethtool_ioctl_t ioc __attribute__((cleanup(fd_ethtool_ioctl_fini)));
      49           0 :   if( FD_UNLIKELY( &ioc != fd_ethtool_ioctl_init( &ioc, device ) ) )
      50           0 :     FD_LOG_ERR(( "error configuring network device (%s), unable to init ethtool ioctl", device ));
      51             : 
      52             :   /* turn off rx-udp-gro-forwarding, which is entirely incompatible with
      53             :    * AF_XDP and QUIC
      54             :    * It results in multiple UDP payloads being merged into a single UDP packet,
      55             :    * with IP and UDP headers rewritten, combining the lengths and updating the
      56             :    * checksums. QUIC short packets cannot be processed reliably in this case. */
      57           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_RXUDPGROFWD,  0 ) );
      58             : 
      59             :   /* turn off tx-gre-segmentation and tx-gre-csum-segmentation.  When
      60             :      enabled, some packets sent via normal sockets can be corrupted
      61             :      while XDP is in use on the same system. */
      62           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_TXGRESEG,     0 ) );
      63           0 :   FD_TEST( 0==fd_ethtool_ioctl_feature_set( &ioc, FD_ETHTOOL_FEATURE_TXGRECSUMSEG, 0 ) );
      64           0 : }
      65             : 
      66             : static void
      67           0 : init( fd_config_t const * config ) {
      68           0 :   int const xdp = 0==strcmp( config->net.provider, "xdp" );
      69           0 :   if( FD_UNLIKELY( fd_bonding_is_master( config->net.interface ) ) ) {
      70           0 :     fd_bonding_slave_iter_t iter_[1];
      71           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
      72           0 :     for( ; !fd_bonding_slave_iter_done( iter );
      73           0 :          fd_bonding_slave_iter_next( iter ) ) {
      74           0 :       init_device( fd_bonding_slave_iter_ele( iter ), xdp );
      75           0 :     }
      76           0 :   } else {
      77           0 :     init_device( config->net.interface, xdp );
      78           0 :   }
      79           0 :   init_device( "lo", xdp );
      80           0 : }
      81             : 
      82             : static configure_result_t
      83             : check_device( char const * device,
      84             :               int          xdp,
      85           0 :               int          warn_gro ) {
      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           0 :   if( warn_gro ) {
      91           0 :     int gro_active, gro_supported;
      92           0 :     if( FD_LIKELY( 0==fd_ethtool_ioctl_feature_gro_test( &ioc, &gro_active, &gro_supported ) ) ) {
      93           0 :       if( FD_UNLIKELY( !gro_active && gro_supported ) ) {
      94           0 :         FD_LOG_WARNING(( "network device `%s` has generic-receive-offload disabled.  "
      95           0 :                          "Consider enabling with `ethtool --offload %s generic-receive-offload on`.  "
      96           0 :                          "Proceeding but performance may be reduced.", device, device ));
      97           0 :       }
      98           0 :     }
      99           0 :   }
     100             : 
     101           0 :   if( xdp ) {
     102           0 :     int udpgrofwd_active;
     103           0 :     int greseg_active;
     104           0 :     int grecsumseg_active;
     105           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_RXUDPGROFWD,  &udpgrofwd_active  ) );
     106           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_TXGRESEG,     &greseg_active     ) );
     107           0 :     FD_TEST( 0==fd_ethtool_ioctl_feature_test( &ioc, FD_ETHTOOL_FEATURE_TXGRECSUMSEG, &grecsumseg_active ) );
     108             : 
     109           0 :     if( FD_UNLIKELY( udpgrofwd_active ) )
     110           0 :       NOT_CONFIGURED( "device `%s` has rx-udp-gro-forwarding enabled. Should be disabled", device );
     111           0 :     if( FD_UNLIKELY( greseg_active ) )
     112           0 :       NOT_CONFIGURED( "device `%s` has tx-gre-segmentation enabled. Should be disabled", device );
     113           0 :     if( FD_UNLIKELY( grecsumseg_active ) )
     114           0 :       NOT_CONFIGURED( "device `%s` has tx-gre-csum-segmentation enabled. Should be disabled", device );
     115           0 :   }
     116             : 
     117           0 :   CONFIGURE_OK();
     118           0 : }
     119             : 
     120             : static configure_result_t
     121             : check( fd_config_t const * config,
     122           0 :        int                 check_type ) {
     123           0 :   int warn_gro = check_type==FD_CONFIGURE_CHECK_TYPE_PRE_INIT ||
     124           0 :                  check_type==FD_CONFIGURE_CHECK_TYPE_CHECK ||
     125           0 :                  check_type==FD_CONFIGURE_CHECK_TYPE_RUN;
     126           0 :   int const xdp = 0==strcmp( config->net.provider, "xdp" );
     127           0 :   if( FD_UNLIKELY( fd_bonding_is_master( config->net.interface ) ) ) {
     128           0 :     fd_bonding_slave_iter_t iter_[1];
     129           0 :     fd_bonding_slave_iter_t * iter = fd_bonding_slave_iter_init( iter_, config->net.interface );
     130           0 :     for( ; !fd_bonding_slave_iter_done( iter );
     131           0 :          fd_bonding_slave_iter_next( iter ) ) {
     132           0 :       CHECK( check_device( fd_bonding_slave_iter_ele( iter ), xdp, warn_gro ) );
     133           0 :     }
     134           0 :   } else {
     135           0 :     CHECK( check_device( config->net.interface, xdp, warn_gro ) );
     136           0 :   }
     137           0 :   CHECK( check_device( "lo", xdp, 0 ) );
     138             : 
     139           0 :   CONFIGURE_OK();
     140           0 : }
     141             : 
     142             : configure_stage_t fd_cfg_stage_ethtool_offloads = {
     143             :   .name            = NAME,
     144             :   .always_recreate = 0,
     145             :   .enabled         = enabled,
     146             :   .init_perm       = init_perm,
     147             :   .fini_perm       = NULL,
     148             :   .init            = init,
     149             :   .fini            = NULL,
     150             :   .check           = check,
     151             : };
     152             : 
     153             : #undef NAME

Generated by: LCOV version 1.14