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
|