44import datetime
55import random
66import re
7+ import time
78from lib .py import ksft_run , ksft_pr , ksft_exit
89from lib .py import ksft_eq , ksft_ne , ksft_ge , ksft_in , ksft_lt , ksft_true , ksft_raises
910from lib .py import NetDrvEpEnv
1011from lib .py import EthtoolFamily , NetdevFamily
1112from lib .py import KsftSkipEx , KsftFailEx
13+ from lib .py import ksft_disruptive
1214from lib .py import rand_port
13- from lib .py import ethtool , ip , defer , GenerateTraffic , CmdExitFailure
15+ from lib .py import cmd , ethtool , ip , defer , GenerateTraffic , CmdExitFailure , wait_file
1416
1517
1618def _rss_key_str (key ):
@@ -809,6 +811,98 @@ def test_rss_default_context_rule(cfg):
809811 'noise' : (0 , 1 ) })
810812
811813
814+ @ksft_disruptive
815+ def test_rss_context_persist_ifupdown (cfg , pre_down = False ):
816+ """
817+ Test that RSS contexts and their associated ntuple filters persist across
818+ an interface down/up cycle.
819+
820+ """
821+
822+ require_ntuple (cfg )
823+
824+ qcnt = len (_get_rx_cnts (cfg ))
825+ if qcnt < 6 :
826+ try :
827+ ethtool (f"-L { cfg .ifname } combined 6" )
828+ defer (ethtool , f"-L { cfg .ifname } combined { qcnt } " )
829+ except Exception as exc :
830+ raise KsftSkipEx ("Not enough queues for the test" ) from exc
831+
832+ ethtool (f"-X { cfg .ifname } equal 2" )
833+ defer (ethtool , f"-X { cfg .ifname } default" )
834+
835+ ifup = defer (ip , f"link set dev { cfg .ifname } up" )
836+ if pre_down :
837+ ip (f"link set dev { cfg .ifname } down" )
838+
839+ try :
840+ ctx1_id = ethtool_create (cfg , "-X" , "context new start 2 equal 2" )
841+ defer (ethtool , f"-X { cfg .ifname } context { ctx1_id } delete" )
842+ except CmdExitFailure as exc :
843+ raise KsftSkipEx ("Create context not supported with interface down" ) from exc
844+
845+ ctx2_id = ethtool_create (cfg , "-X" , "context new start 4 equal 2" )
846+ defer (ethtool , f"-X { cfg .ifname } context { ctx2_id } delete" )
847+
848+ port_ctx2 = rand_port ()
849+ flow = f"flow-type tcp{ cfg .addr_ipver } dst-ip { cfg .addr } dst-port { port_ctx2 } context { ctx2_id } "
850+ ntuple_id = ethtool_create (cfg , "-N" , flow )
851+ defer (ethtool , f"-N { cfg .ifname } delete { ntuple_id } " )
852+
853+ if not pre_down :
854+ ip (f"link set dev { cfg .ifname } down" )
855+ ifup .exec ()
856+
857+ wait_file (f"/sys/class/net/{ cfg .ifname } /carrier" ,
858+ lambda x : x .strip () == "1" , deadline = 20 )
859+
860+ remote_addr = cfg .remote_addr_v [cfg .addr_ipver ]
861+ for _ in range (10 ):
862+ if cmd (f"ping -c 1 -W 1 { remote_addr } " , fail = False ).ret == 0 :
863+ break
864+ time .sleep (1 )
865+ else :
866+ raise KsftSkipEx ("Cannot reach remote host after interface up" )
867+
868+ ctxs = cfg .ethnl .rss_get ({'header' : {'dev-name' : cfg .ifname }}, dump = True )
869+
870+ data1 = [c for c in ctxs if c .get ('context' ) == ctx1_id ]
871+ ksft_eq (len (data1 ), 1 , f"Context { ctx1_id } should persist after ifup" )
872+
873+ data2 = [c for c in ctxs if c .get ('context' ) == ctx2_id ]
874+ ksft_eq (len (data2 ), 1 , f"Context { ctx2_id } should persist after ifup" )
875+
876+ _ntuple_rule_check (cfg , ntuple_id , ctx2_id )
877+
878+ cnts = _get_rx_cnts (cfg )
879+ GenerateTraffic (cfg ).wait_pkts_and_stop (20000 )
880+ cnts = _get_rx_cnts (cfg , prev = cnts )
881+
882+ main_traffic = sum (cnts [0 :2 ])
883+ ksft_ge (main_traffic , 18000 , f"Main context traffic distribution: { cnts } " )
884+ ksft_lt (sum (cnts [2 :6 ]), 500 , f"Other context queues should be mostly empty: { cnts } " )
885+
886+ _send_traffic_check (cfg , port_ctx2 , f"context { ctx2_id } " ,
887+ {'target' : (4 , 5 ),
888+ 'noise' : (0 , 1 ),
889+ 'empty' : (2 , 3 )})
890+
891+
892+ def test_rss_context_persist_create_and_ifdown (cfg ):
893+ """
894+ Create RSS contexts then cycle the interface down and up.
895+ """
896+ test_rss_context_persist_ifupdown (cfg , pre_down = False )
897+
898+
899+ def test_rss_context_persist_ifdown_and_create (cfg ):
900+ """
901+ Bring interface down first, then create RSS contexts and bring up.
902+ """
903+ test_rss_context_persist_ifupdown (cfg , pre_down = True )
904+
905+
812906def main () -> None :
813907 with NetDrvEpEnv (__file__ , nsim_test = False ) as cfg :
814908 cfg .context_cnt = None
@@ -823,7 +917,9 @@ def main() -> None:
823917 test_rss_context_out_of_order , test_rss_context4_create_with_cfg ,
824918 test_flow_add_context_missing ,
825919 test_delete_rss_context_busy , test_rss_ntuple_addition ,
826- test_rss_default_context_rule ],
920+ test_rss_default_context_rule ,
921+ test_rss_context_persist_create_and_ifdown ,
922+ test_rss_context_persist_ifdown_and_create ],
827923 args = (cfg , ))
828924 ksft_exit ()
829925
0 commit comments