@@ -102,7 +102,7 @@ def build_tunnel(cfg, outer_ipver, tun_info):
102
102
remote_addr = cfg .remote_addr_v [outer_ipver ]
103
103
104
104
tun_type = tun_info [0 ]
105
- tun_arg = tun_info [2 ]
105
+ tun_arg = tun_info [1 ]
106
106
ip (f"link add { tun_type } -ksft type { tun_type } { tun_arg } local { local_addr } remote { remote_addr } dev { cfg .ifname } " )
107
107
defer (ip , f"link del { tun_type } -ksft" )
108
108
ip (f"link set dev { tun_type } -ksft up" )
@@ -119,15 +119,30 @@ def build_tunnel(cfg, outer_ipver, tun_info):
119
119
return remote_v4 , remote_v6
120
120
121
121
122
+ def restore_wanted_features (cfg ):
123
+ features_cmd = ""
124
+ for feature in cfg .hw_features :
125
+ setting = "on" if feature in cfg .wanted_features else "off"
126
+ features_cmd += f" { feature } { setting } "
127
+ try :
128
+ ethtool (f"-K { cfg .ifname } { features_cmd } " )
129
+ except Exception as e :
130
+ ksft_pr (f"WARNING: failure restoring wanted features: { e } " )
131
+
132
+
122
133
def test_builder (name , cfg , outer_ipver , feature , tun = None , inner_ipver = None ):
123
134
"""Construct specific tests from the common template."""
124
135
def f (cfg ):
125
136
cfg .require_ipver (outer_ipver )
137
+ defer (restore_wanted_features , cfg )
126
138
127
139
if not cfg .have_stat_super_count and \
128
140
not cfg .have_stat_wire_count :
129
141
raise KsftSkipEx (f"Device does not support LSO queue stats" )
130
142
143
+ if feature not in cfg .hw_features :
144
+ raise KsftSkipEx (f"Device does not support { feature } " )
145
+
131
146
ipver = outer_ipver
132
147
if tun :
133
148
remote_v4 , remote_v6 = build_tunnel (cfg , ipver , tun )
@@ -136,36 +151,21 @@ def f(cfg):
136
151
remote_v4 = cfg .remote_addr_v ["4" ]
137
152
remote_v6 = cfg .remote_addr_v ["6" ]
138
153
139
- tun_partial = tun and tun [1 ]
140
- # Tunnel which can silently fall back to gso-partial
141
- has_gso_partial = tun and 'tx-gso-partial' in cfg .features
142
-
143
- # For TSO4 via partial we need mangleid
144
- if ipver == "4" and feature in cfg .partial_features :
145
- ksft_pr ("Testing with mangleid enabled" )
146
- if 'tx-tcp-mangleid-segmentation' not in cfg .features :
147
- ethtool (f"-K { cfg .ifname } tx-tcp-mangleid-segmentation on" )
148
- defer (ethtool , f"-K { cfg .ifname } tx-tcp-mangleid-segmentation off" )
149
-
150
154
# First test without the feature enabled.
151
155
ethtool (f"-K { cfg .ifname } { feature } off" )
152
- if has_gso_partial :
153
- ethtool (f"-K { cfg .ifname } tx-gso-partial off" )
154
156
run_one_stream (cfg , ipver , remote_v4 , remote_v6 , should_lso = False )
155
157
156
- # Now test with the feature enabled.
157
- # For compatible tunnels only - just GSO partial, not specific feature.
158
- if has_gso_partial :
158
+ ethtool ( f"-K { cfg . ifname } tx-gso-partial off" )
159
+ ethtool ( f"-K { cfg . ifname } tx-tcp-mangleid-segmentation off" )
160
+ if feature in cfg . partial_features :
159
161
ethtool (f"-K { cfg .ifname } tx-gso-partial on" )
160
- run_one_stream (cfg , ipver , remote_v4 , remote_v6 ,
161
- should_lso = tun_partial )
162
+ if ipver == "4" :
163
+ ksft_pr ("Testing with mangleid enabled" )
164
+ ethtool (f"-K { cfg .ifname } tx-tcp-mangleid-segmentation on" )
162
165
163
166
# Full feature enabled.
164
- if feature in cfg .features :
165
- ethtool (f"-K { cfg .ifname } { feature } on" )
166
- run_one_stream (cfg , ipver , remote_v4 , remote_v6 , should_lso = True )
167
- else :
168
- raise KsftXfailEx (f"Device does not support { feature } " )
167
+ ethtool (f"-K { cfg .ifname } { feature } on" )
168
+ run_one_stream (cfg , ipver , remote_v4 , remote_v6 , should_lso = True )
169
169
170
170
f .__name__ = name + ((outer_ipver + "_" ) if tun else "" ) + "ipv" + inner_ipver
171
171
return f
@@ -176,23 +176,39 @@ def query_nic_features(cfg) -> None:
176
176
cfg .have_stat_super_count = False
177
177
cfg .have_stat_wire_count = False
178
178
179
- cfg .features = set ()
180
179
features = cfg .ethnl .features_get ({"header" : {"dev-index" : cfg .ifindex }})
181
- for f in features ["active" ]["bits" ]["bit" ]:
182
- cfg .features .add (f ["name" ])
180
+
181
+ cfg .wanted_features = set ()
182
+ for f in features ["wanted" ]["bits" ]["bit" ]:
183
+ cfg .wanted_features .add (f ["name" ])
184
+
185
+ cfg .hw_features = set ()
186
+ hw_all_features_cmd = ""
187
+ for f in features ["hw" ]["bits" ]["bit" ]:
188
+ if f .get ("value" , False ):
189
+ feature = f ["name" ]
190
+ cfg .hw_features .add (feature )
191
+ hw_all_features_cmd += f" { feature } on"
192
+ try :
193
+ ethtool (f"-K { cfg .ifname } { hw_all_features_cmd } " )
194
+ except Exception as e :
195
+ ksft_pr (f"WARNING: failure enabling all hw features: { e } " )
196
+ ksft_pr ("partial gso feature detection may be impacted" )
183
197
184
198
# Check which features are supported via GSO partial
185
199
cfg .partial_features = set ()
186
- if 'tx-gso-partial' in cfg .features :
200
+ if 'tx-gso-partial' in cfg .hw_features :
187
201
ethtool (f"-K { cfg .ifname } tx-gso-partial off" )
188
202
189
203
no_partial = set ()
190
204
features = cfg .ethnl .features_get ({"header" : {"dev-index" : cfg .ifindex }})
191
205
for f in features ["active" ]["bits" ]["bit" ]:
192
206
no_partial .add (f ["name" ])
193
- cfg .partial_features = cfg .features - no_partial
207
+ cfg .partial_features = cfg .hw_features - no_partial
194
208
ethtool (f"-K { cfg .ifname } tx-gso-partial on" )
195
209
210
+ restore_wanted_features (cfg )
211
+
196
212
stats = cfg .netnl .qstats_get ({"ifindex" : cfg .ifindex }, dump = True )
197
213
if stats :
198
214
if 'tx-hw-gso-packets' in stats [0 ]:
@@ -211,13 +227,14 @@ def main() -> None:
211
227
query_nic_features (cfg )
212
228
213
229
test_info = (
214
- # name, v4/v6 ethtool_feature tun:(type, partial, args)
215
- ("" , "4" , "tx-tcp-segmentation" , None ),
216
- ("" , "6" , "tx-tcp6-segmentation" , None ),
217
- ("vxlan" , "" , "tx-udp_tnl-segmentation" , ("vxlan" , True , "id 100 dstport 4789 noudpcsum" )),
218
- ("vxlan_csum" , "" , "tx-udp_tnl-csum-segmentation" , ("vxlan" , False , "id 100 dstport 4789 udpcsum" )),
219
- ("gre" , "4" , "tx-gre-segmentation" , ("gre" , False , "" )),
220
- ("gre" , "6" , "tx-gre-segmentation" , ("ip6gre" , False , "" )),
230
+ # name, v4/v6 ethtool_feature tun:(type, args, inner ip versions)
231
+ ("" , "4" , "tx-tcp-segmentation" , None ),
232
+ ("" , "6" , "tx-tcp6-segmentation" , None ),
233
+ ("vxlan" , "4" , "tx-udp_tnl-segmentation" , ("vxlan" , "id 100 dstport 4789 noudpcsum" , ("4" , "6" ))),
234
+ ("vxlan" , "6" , "tx-udp_tnl-segmentation" , ("vxlan" , "id 100 dstport 4789 udp6zerocsumtx udp6zerocsumrx" , ("4" , "6" ))),
235
+ ("vxlan_csum" , "" , "tx-udp_tnl-csum-segmentation" , ("vxlan" , "id 100 dstport 4789 udpcsum" , ("4" , "6" ))),
236
+ ("gre" , "4" , "tx-gre-segmentation" , ("gre" , "" , ("4" , "6" ))),
237
+ ("gre" , "6" , "tx-gre-segmentation" , ("ip6gre" ,"" , ("4" , "6" ))),
221
238
)
222
239
223
240
cases = []
@@ -227,11 +244,13 @@ def main() -> None:
227
244
if info [1 ] and outer_ipver != info [1 ]:
228
245
continue
229
246
230
- cases .append (test_builder (info [0 ], cfg , outer_ipver , info [2 ],
231
- tun = info [3 ], inner_ipver = "4" ))
232
247
if info [3 ]:
233
- cases .append (test_builder (info [0 ], cfg , outer_ipver , info [2 ],
234
- tun = info [3 ], inner_ipver = "6" ))
248
+ cases += [
249
+ test_builder (info [0 ], cfg , outer_ipver , info [2 ], info [3 ], inner_ipver )
250
+ for inner_ipver in info [3 ][2 ]
251
+ ]
252
+ else :
253
+ cases .append (test_builder (info [0 ], cfg , outer_ipver , info [2 ], None , outer_ipver ))
235
254
236
255
ksft_run (cases = cases , args = (cfg , ))
237
256
ksft_exit ()
0 commit comments