@@ -247,6 +247,149 @@ def test_rxfh_fields(cfg):
247
247
comment = "Config for " + fl_type )
248
248
249
249
250
+ def test_rxfh_fields_set (cfg ):
251
+ """ Test configuring Rx Flow Hash over Netlink. """
252
+
253
+ flow_types = ["tcp4" , "tcp6" , "udp4" , "udp6" ]
254
+
255
+ # Collect current settings
256
+ cfg_old = cfg .ethnl .rss_get ({"header" : {"dev-index" : cfg .ifindex }})
257
+ # symmetric hashing is config-order-sensitive make sure we leave
258
+ # symmetric mode, or make the flow-hash sym-compatible first
259
+ changes = [{"flow-hash" : cfg_old ["flow-hash" ],},
260
+ {"input-xfrm" : cfg_old .get ("input-xfrm" , {}),}]
261
+ if cfg_old .get ("input-xfrm" ):
262
+ changes = list (reversed (changes ))
263
+ for old in changes :
264
+ defer (cfg .ethnl .rss_set , {"header" : {"dev-index" : cfg .ifindex },} | old )
265
+
266
+ # symmetric hashing prevents some of the configs below
267
+ if cfg_old .get ("input-xfrm" ):
268
+ cfg .ethnl .rss_set ({"header" : {"dev-index" : cfg .ifindex },
269
+ "input-xfrm" : {}})
270
+
271
+ for fl_type in flow_types :
272
+ cur = _ethtool_get_cfg (cfg , fl_type )
273
+ if cur == "sdfn" :
274
+ change_nl = {"ip-src" , "ip-dst" }
275
+ change_ic = "sd"
276
+ else :
277
+ change_nl = {"l4-b-0-1" , "l4-b-2-3" , "ip-src" , "ip-dst" }
278
+ change_ic = "sdfn"
279
+
280
+ cfg .ethnl .rss_set ({
281
+ "header" : {"dev-index" : cfg .ifindex },
282
+ "flow-hash" : {fl_type : change_nl }
283
+ })
284
+ reset = defer (ethtool , f"--disable-netlink -N { cfg .ifname } "
285
+ f"rx-flow-hash { fl_type } { cur } " )
286
+
287
+ cfg_nl = cfg .ethnl .rss_get ({"header" : {"dev-index" : cfg .ifindex }})
288
+ ksft_eq (change_nl , cfg_nl ["flow-hash" ][fl_type ],
289
+ comment = f"Config for { fl_type } over Netlink" )
290
+ cfg_ic = _ethtool_get_cfg (cfg , fl_type )
291
+ ksft_eq (change_ic , cfg_ic ,
292
+ comment = f"Config for { fl_type } over IOCTL" )
293
+
294
+ reset .exec ()
295
+ cfg_nl = cfg .ethnl .rss_get ({"header" : {"dev-index" : cfg .ifindex }})
296
+ ksft_eq (cfg_old ["flow-hash" ][fl_type ], cfg_nl ["flow-hash" ][fl_type ],
297
+ comment = f"Un-config for { fl_type } over Netlink" )
298
+ cfg_ic = _ethtool_get_cfg (cfg , fl_type )
299
+ ksft_eq (cur , cfg_ic , comment = f"Un-config for { fl_type } over IOCTL" )
300
+
301
+ # Try to set multiple at once, the defer was already installed at the start
302
+ change = {"ip-src" }
303
+ if change == cfg_old ["flow-hash" ]["tcp4" ]:
304
+ change = {"ip-dst" }
305
+ cfg .ethnl .rss_set ({
306
+ "header" : {"dev-index" : cfg .ifindex },
307
+ "flow-hash" : {x : change for x in flow_types }
308
+ })
309
+
310
+ cfg_nl = cfg .ethnl .rss_get ({"header" : {"dev-index" : cfg .ifindex }})
311
+ for fl_type in flow_types :
312
+ ksft_eq (change , cfg_nl ["flow-hash" ][fl_type ],
313
+ comment = f"multi-config for { fl_type } over Netlink" )
314
+
315
+
316
+ def test_rxfh_fields_set_xfrm (cfg ):
317
+ """ Test changing Rx Flow Hash vs xfrm_input at once. """
318
+
319
+ def set_rss (cfg , xfrm , fh ):
320
+ cfg .ethnl .rss_set ({"header" : {"dev-index" : cfg .ifindex },
321
+ "input-xfrm" : xfrm , "flow-hash" : fh })
322
+
323
+ # Install the reset handler
324
+ cfg_old = cfg .ethnl .rss_get ({"header" : {"dev-index" : cfg .ifindex }})
325
+ # symmetric hashing is config-order-sensitive make sure we leave
326
+ # symmetric mode, or make the flow-hash sym-compatible first
327
+ changes = [{"flow-hash" : cfg_old ["flow-hash" ],},
328
+ {"input-xfrm" : cfg_old .get ("input-xfrm" , {}),}]
329
+ if cfg_old .get ("input-xfrm" ):
330
+ changes = list (reversed (changes ))
331
+ for old in changes :
332
+ defer (cfg .ethnl .rss_set , {"header" : {"dev-index" : cfg .ifindex },} | old )
333
+
334
+ # Make sure we start with input-xfrm off, and tcp4 config non-sym
335
+ set_rss (cfg , {}, {})
336
+ set_rss (cfg , {}, {"tcp4" : {"ip-src" }})
337
+
338
+ # Setting sym and fixing tcp4 config not expected to pass right now
339
+ with ksft_raises (NlError ):
340
+ set_rss (cfg , {"sym-xor" }, {"tcp4" : {"ip-src" , "ip-dst" }})
341
+ # One at a time should work, hopefully
342
+ set_rss (cfg , 0 , {"tcp4" : {"ip-src" , "ip-dst" }})
343
+ no_support = False
344
+ try :
345
+ set_rss (cfg , {"sym-xor" }, {})
346
+ except NlError :
347
+ try :
348
+ set_rss (cfg , {"sym-or-xor" }, {})
349
+ except NlError :
350
+ no_support = True
351
+ if no_support :
352
+ raise KsftSkipEx ("no input-xfrm supported" )
353
+ # Disabling two at once should not work either without kernel changes
354
+ with ksft_raises (NlError ):
355
+ set_rss (cfg , {}, {"tcp4" : {"ip-src" }})
356
+
357
+
358
+ def test_rxfh_fields_ntf (cfg ):
359
+ """ Test Rx Flow Hash notifications. """
360
+
361
+ cur = _ethtool_get_cfg (cfg , "tcp4" )
362
+ if cur == "sdfn" :
363
+ change = {"ip-src" , "ip-dst" }
364
+ else :
365
+ change = {"l4-b-0-1" , "l4-b-2-3" , "ip-src" , "ip-dst" }
366
+
367
+ ethnl = EthtoolFamily ()
368
+ ethnl .ntf_subscribe ("monitor" )
369
+
370
+ ethnl .rss_set ({
371
+ "header" : {"dev-index" : cfg .ifindex },
372
+ "flow-hash" : {"tcp4" : change }
373
+ })
374
+ reset = defer (ethtool ,
375
+ f"--disable-netlink -N { cfg .ifname } rx-flow-hash tcp4 { cur } " )
376
+
377
+ ntf = next (ethnl .poll_ntf (duration = 0.2 ), None )
378
+ if ntf is None :
379
+ raise KsftFailEx ("No notification received after IOCTL change" )
380
+ ksft_eq (ntf ["name" ], "rss-ntf" )
381
+ ksft_eq (ntf ["msg" ]["flow-hash" ]["tcp4" ], change )
382
+ ksft_eq (next (ethnl .poll_ntf (duration = 0.01 ), None ), None )
383
+
384
+ reset .exec ()
385
+ ntf = next (ethnl .poll_ntf (duration = 0.2 ), None )
386
+ if ntf is None :
387
+ raise KsftFailEx ("No notification received after Netlink change" )
388
+ ksft_eq (ntf ["name" ], "rss-ntf" )
389
+ ksft_ne (ntf ["msg" ]["flow-hash" ]["tcp4" ], change )
390
+ ksft_eq (next (ethnl .poll_ntf (duration = 0.01 ), None ), None )
391
+
392
+
250
393
def main () -> None :
251
394
""" Ksft boiler plate main """
252
395
0 commit comments