@@ -102,7 +102,7 @@ def build_tunnel(cfg, outer_ipver, tun_info):
102102 remote_addr = cfg .remote_addr_v [outer_ipver ]
103103
104104 tun_type = tun_info [0 ]
105- tun_arg = tun_info [2 ]
105+ tun_arg = tun_info [1 ]
106106 ip (f"link add { tun_type } -ksft type { tun_type } { tun_arg } local { local_addr } remote { remote_addr } dev { cfg .ifname } " )
107107 defer (ip , f"link del { tun_type } -ksft" )
108108 ip (f"link set dev { tun_type } -ksft up" )
@@ -119,15 +119,30 @@ def build_tunnel(cfg, outer_ipver, tun_info):
119119 return remote_v4 , remote_v6
120120
121121
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+
122133def test_builder (name , cfg , outer_ipver , feature , tun = None , inner_ipver = None ):
123134 """Construct specific tests from the common template."""
124135 def f (cfg ):
125136 cfg .require_ipver (outer_ipver )
137+ defer (restore_wanted_features , cfg )
126138
127139 if not cfg .have_stat_super_count and \
128140 not cfg .have_stat_wire_count :
129141 raise KsftSkipEx (f"Device does not support LSO queue stats" )
130142
143+ if feature not in cfg .hw_features :
144+ raise KsftSkipEx (f"Device does not support { feature } " )
145+
131146 ipver = outer_ipver
132147 if tun :
133148 remote_v4 , remote_v6 = build_tunnel (cfg , ipver , tun )
@@ -136,36 +151,21 @@ def f(cfg):
136151 remote_v4 = cfg .remote_addr_v ["4" ]
137152 remote_v6 = cfg .remote_addr_v ["6" ]
138153
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-
150154 # First test without the feature enabled.
151155 ethtool (f"-K { cfg .ifname } { feature } off" )
152- if has_gso_partial :
153- ethtool (f"-K { cfg .ifname } tx-gso-partial off" )
154156 run_one_stream (cfg , ipver , remote_v4 , remote_v6 , should_lso = False )
155157
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 :
159161 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" )
162165
163166 # 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 )
169169
170170 f .__name__ = name + ((outer_ipver + "_" ) if tun else "" ) + "ipv" + inner_ipver
171171 return f
@@ -176,23 +176,39 @@ def query_nic_features(cfg) -> None:
176176 cfg .have_stat_super_count = False
177177 cfg .have_stat_wire_count = False
178178
179- cfg .features = set ()
180179 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" )
183197
184198 # Check which features are supported via GSO partial
185199 cfg .partial_features = set ()
186- if 'tx-gso-partial' in cfg .features :
200+ if 'tx-gso-partial' in cfg .hw_features :
187201 ethtool (f"-K { cfg .ifname } tx-gso-partial off" )
188202
189203 no_partial = set ()
190204 features = cfg .ethnl .features_get ({"header" : {"dev-index" : cfg .ifindex }})
191205 for f in features ["active" ]["bits" ]["bit" ]:
192206 no_partial .add (f ["name" ])
193- cfg .partial_features = cfg .features - no_partial
207+ cfg .partial_features = cfg .hw_features - no_partial
194208 ethtool (f"-K { cfg .ifname } tx-gso-partial on" )
195209
210+ restore_wanted_features (cfg )
211+
196212 stats = cfg .netnl .qstats_get ({"ifindex" : cfg .ifindex }, dump = True )
197213 if stats :
198214 if 'tx-hw-gso-packets' in stats [0 ]:
@@ -211,13 +227,14 @@ def main() -> None:
211227 query_nic_features (cfg )
212228
213229 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" ))),
221238 )
222239
223240 cases = []
@@ -227,11 +244,13 @@ def main() -> None:
227244 if info [1 ] and outer_ipver != info [1 ]:
228245 continue
229246
230- cases .append (test_builder (info [0 ], cfg , outer_ipver , info [2 ],
231- tun = info [3 ], inner_ipver = "4" ))
232247 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 ))
235254
236255 ksft_run (cases = cases , args = (cfg , ))
237256 ksft_exit ()
0 commit comments