@@ -77,6 +77,222 @@ def test_PfcWdAclCreationDeletion(self, dvs, dvs_acl, testlog):
7777
7878 finally :
7979 dvs_acl .remove_acl_table (PFCWD_TABLE_NAME )
80+
81+
82+ class TestPfcwdFunc (object ):
83+ @pytest .fixture
84+ def setup_teardown_test (self , dvs ):
85+ self .get_db_handle (dvs )
86+
87+ self .test_ports = ["Ethernet0" ]
88+
89+ self .setup_test (dvs )
90+ self .get_port_oids ()
91+ self .get_queue_oids ()
92+
93+ yield
94+
95+ self .teardown_test (dvs )
96+
97+ def setup_test (self , dvs ):
98+ # get original cable len for test ports
99+ fvs = self .config_db .get_entry ("CABLE_LENGTH" , "AZURE" )
100+ self .orig_cable_len = dict ()
101+ for port in self .test_ports :
102+ self .orig_cable_len [port ] = fvs [port ]
103+ # set cable len to non zero value. if port is down, default cable len is 0
104+ self .set_cable_len (port , "5m" )
105+ # startup port
106+ dvs .runcmd ("config interface startup {}" .format (port ))
107+
108+ # enable pfcwd
109+ self .set_flex_counter_status ("PFCWD" , "enable" )
110+ # enable queue so that queue oids are generated
111+ self .set_flex_counter_status ("QUEUE" , "enable" )
112+
113+ def teardown_test (self , dvs ):
114+ # disable pfcwd
115+ self .set_flex_counter_status ("PFCWD" , "disable" )
116+ # disable queue
117+ self .set_flex_counter_status ("QUEUE" , "disable" )
118+
119+ for port in self .test_ports :
120+ if self .orig_cable_len :
121+ self .set_cable_len (port , self .orig_cable_len [port ])
122+ # shutdown port
123+ dvs .runcmd ("config interface shutdown {}" .format (port ))
124+
125+ def get_db_handle (self , dvs ):
126+ self .app_db = dvs .get_app_db ()
127+ self .asic_db = dvs .get_asic_db ()
128+ self .config_db = dvs .get_config_db ()
129+ self .counters_db = dvs .get_counters_db ()
130+
131+ def set_flex_counter_status (self , key , state ):
132+ fvs = {'FLEX_COUNTER_STATUS' : state }
133+ self .config_db .update_entry ("FLEX_COUNTER_TABLE" , key , fvs )
134+ time .sleep (1 )
135+
136+ def get_queue_oids (self ):
137+ self .queue_oids = self .counters_db .get_entry ("COUNTERS_QUEUE_NAME_MAP" , "" )
138+
139+ def get_port_oids (self ):
140+ self .port_oids = self .counters_db .get_entry ("COUNTERS_PORT_NAME_MAP" , "" )
141+
142+ def _get_bitmask (self , queues ):
143+ mask = 0
144+ if queues is not None :
145+ for queue in queues :
146+ mask = mask | 1 << queue
147+
148+ return str (mask )
149+
150+ def set_ports_pfc (self , status = 'enable' , pfc_queues = [3 ,4 ]):
151+ for port in self .test_ports :
152+ if 'enable' in status :
153+ fvs = {'pfc_enable' : "," .join ([str (q ) for q in pfc_queues ])}
154+ self .config_db .create_entry ("PORT_QOS_MAP" , port , fvs )
155+ else :
156+ self .config_db .delete_entry ("PORT_QOS_MAP" , port )
157+
158+ def set_cable_len (self , port_name , cable_len ):
159+ fvs = {port_name : cable_len }
160+ self .config_db .update_entry ("CABLE_LEN" , "AZURE" , fvs )
161+
162+ def start_pfcwd_on_ports (self , poll_interval = "200" , detection_time = "200" , restoration_time = "200" , action = "drop" ):
163+ pfcwd_info = {"POLL_INTERVAL" : poll_interval }
164+ self .config_db .update_entry ("PFC_WD" , "GLOBAL" , pfcwd_info )
165+
166+ pfcwd_info = {"action" : action ,
167+ "detection_time" : detection_time ,
168+ "restoration_time" : restoration_time
169+ }
170+ for port in self .test_ports :
171+ self .config_db .update_entry ("PFC_WD" , port , pfcwd_info )
172+
173+ def stop_pfcwd_on_ports (self ):
174+ for port in self .test_ports :
175+ self .config_db .delete_entry ("PFC_WD" , port )
176+
177+ def verify_ports_pfc (self , queues = None ):
178+ mask = self ._get_bitmask (queues )
179+ fvs = {"SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL" : mask }
180+ for port in self .test_ports :
181+ self .asic_db .wait_for_field_match ("ASIC_STATE:SAI_OBJECT_TYPE_PORT" , self .port_oids [port ], fvs )
182+
183+ def verify_pfcwd_state (self , queues , state = "stormed" ):
184+ fvs = {"PFC_WD_STATUS" : state }
185+ for port in self .test_ports :
186+ for queue in queues :
187+ queue_name = port + ":" + str (queue )
188+ self .counters_db .wait_for_field_match ("COUNTERS" , self .queue_oids [queue_name ], fvs )
189+
190+ def verify_pfcwd_counters (self , queues , restore = "0" ):
191+ fvs = {"PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED" : "1" ,
192+ "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED" : restore
193+ }
194+ for port in self .test_ports :
195+ for queue in queues :
196+ queue_name = port + ":" + str (queue )
197+ self .counters_db .wait_for_field_match ("COUNTERS" , self .queue_oids [queue_name ], fvs )
198+
199+ def reset_pfcwd_counters (self , queues ):
200+ fvs = {"PFC_WD_QUEUE_STATS_DEADLOCK_DETECTED" : "0" ,
201+ "PFC_WD_QUEUE_STATS_DEADLOCK_RESTORED" : "0"
202+ }
203+ for port in self .test_ports :
204+ for queue in queues :
205+ queue_name = port + ":" + str (queue )
206+ self .counters_db .update_entry ("COUNTERS" , self .queue_oids [queue_name ], fvs )
207+
208+ def set_storm_state (self , queues , state = "enabled" ):
209+ fvs = {"DEBUG_STORM" : state }
210+ for port in self .test_ports :
211+ for queue in queues :
212+ queue_name = port + ":" + str (queue )
213+ self .counters_db .update_entry ("COUNTERS" , self .queue_oids [queue_name ], fvs )
214+
215+ def test_pfcwd_single_queue (self , dvs , setup_teardown_test ):
216+ try :
217+ # enable PFC on queues
218+ test_queues = [3 , 4 ]
219+ self .set_ports_pfc (pfc_queues = test_queues )
220+
221+ # verify in asic db
222+ self .verify_ports_pfc (test_queues )
223+
224+ # start pfcwd
225+ self .start_pfcwd_on_ports ()
226+
227+ # start pfc storm
228+ storm_queue = [3 ]
229+ self .set_storm_state (storm_queue )
230+
231+ # verify pfcwd is triggered
232+ self .verify_pfcwd_state (storm_queue )
233+
234+ # verify pfcwd counters
235+ self .verify_pfcwd_counters (storm_queue )
236+
237+ # verify if queue is disabled
238+ self .verify_ports_pfc (queues = [4 ])
239+
240+ # stop storm
241+ self .set_storm_state (storm_queue , state = "disabled" )
242+
243+ # verify pfcwd state is restored
244+ self .verify_pfcwd_state (storm_queue , state = "operational" )
245+
246+ # verify pfcwd counters
247+ self .verify_pfcwd_counters (storm_queue , restore = "1" )
248+
249+ # verify if queue is enabled
250+ self .verify_ports_pfc (test_queues )
251+
252+ finally :
253+ self .reset_pfcwd_counters (storm_queue )
254+ self .stop_pfcwd_on_ports ()
255+
256+ def test_pfcwd_multi_queue (self , dvs , setup_teardown_test ):
257+ try :
258+ # enable PFC on queues
259+ test_queues = [3 , 4 ]
260+ self .set_ports_pfc (pfc_queues = test_queues )
261+
262+ # verify in asic db
263+ self .verify_ports_pfc (test_queues )
264+
265+ # start pfcwd
266+ self .start_pfcwd_on_ports ()
267+
268+ # start pfc storm
269+ self .set_storm_state (test_queues )
270+
271+ # verify pfcwd is triggered
272+ self .verify_pfcwd_state (test_queues )
273+
274+ # verify pfcwd counters
275+ self .verify_pfcwd_counters (test_queues )
276+
277+ # verify if queue is disabled. Expected mask is 0
278+ self .verify_ports_pfc ()
279+
280+ # stop storm
281+ self .set_storm_state (test_queues , state = "disabled" )
282+
283+ # verify pfcwd state is restored
284+ self .verify_pfcwd_state (test_queues , state = "operational" )
285+
286+ # verify pfcwd counters
287+ self .verify_pfcwd_counters (test_queues , restore = "1" )
288+
289+ # verify if queue is enabled
290+ self .verify_ports_pfc (test_queues )
291+
292+ finally :
293+ self .reset_pfcwd_counters (test_queues )
294+ self .stop_pfcwd_on_ports ()
295+
80296#
81297# Add Dummy always-pass test at end as workaroud
82298# for issue when Flaky fail on final test it invokes module tear-down before retrying
0 commit comments