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
|