@@ -247,6 +247,149 @@ def test_rxfh_fields(cfg):
247247 comment = "Config for " + fl_type )
248248
249249
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+
250393def main () -> None :
251394 """ Ksft boiler plate main """
252395
0 commit comments