77
88DEFAULT_HLIM_TTL = 64
99WAIT_EXPECTED_PACKET_TIMEOUT = 5
10+ STATIC_ROUTE = '201.1.1.1/32'
11+ STATIC_ROUTE_IPV6 = '2001:db8:1::1/128'
1012
1113logger = logging .getLogger (__name__ )
1214
@@ -23,67 +25,309 @@ def lldp_setup(duthosts, enum_rand_one_per_hwsku_frontend_hostname, patch_lldpct
2325 unpatch_lldpctl (localhost , duthost )
2426
2527
26- def run_test_ipv6 (ptfadapter , facts ):
27- logger .info ("Running test with ipv6 packets" )
28+ @pytest .fixture (scope = "function" , autouse = True )
29+ def setup_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts , request ):
30+ """
31+ Fixture to set up and tear down static routes for IPv4 and IPv6.
2832
29- pkt = testutils .simple_udpv6_packet (
30- eth_dst = facts ['src_router_mac' ],
31- eth_src = facts ['src_host_mac' ],
32- ipv6_src = facts ['dst_host_ipv6' ],
33- ipv6_dst = facts ['dst_host_ipv6' ],
34- ipv6_hlim = DEFAULT_HLIM_TTL
33+ This fixture performs the following actions:
34+ 1. Adds IPv4 and IPv6 static routes to the DUT.
35+ 2. Verifies that the routes are added correctly.
36+ 3. Yields control back to the test.
37+ 4. Removes the static routes after the test is complete.
3538
36- )
37- logger .info ("\n Send Packet:\n eth_dst: {}, eth_src: {}, ipv6 ip: {}" .format (
38- facts ['src_router_mac' ], facts ['src_host_mac' ], facts ['dst_host_ipv6' ])
39- )
39+ Args:
40+ duthosts: Fixture providing access to DUT hosts.
41+ enum_rand_one_per_hwsku_frontend_hostname: Fixture selecting a random frontend DUT.
42+ gather_facts: Fixture providing network facts.
43+ request: Pytest request object.
4044
41- testutils .send (ptfadapter , facts ['src_port_ids' ][0 ], pkt )
45+ Raises:
46+ pytest.fail: If any step in adding or verifying routes fails.
4247
43- exp_pkt = testutils .simple_udpv6_packet (
44- eth_dst = facts ['dst_host_mac' ],
45- eth_src = facts ['dst_router_mac' ],
46- ipv6_src = facts ['dst_host_ipv6' ],
47- ipv6_dst = facts ['dst_host_ipv6' ],
48- ipv6_hlim = DEFAULT_HLIM_TTL - 1
48+ Yields:
49+ None
50+ """
51+ duthost = duthosts [enum_rand_one_per_hwsku_frontend_hostname ]
52+
53+ # Configure IPv4 static route
54+ try :
55+ result = duthost .command ("ip route add {} via {}" .format (STATIC_ROUTE , gather_facts ['dst_host_ipv4' ]))
56+ if result ['rc' ] != 0 :
57+ raise Exception ("Failed to add IPv4 static route: {}" .format (result ['stderr' ]))
58+ except Exception as e :
59+ logger .error ("Error occurred while adding IPv4 static route: %s" , str (e ))
60+ pytest .fail ("IPv4 static route addition failed" )
61+
62+ # Configure IPv6 static route
63+ try :
64+ result = duthost .command ("ip -6 route add {} via {}" .format (STATIC_ROUTE_IPV6 , gather_facts ['dst_host_ipv6' ]))
65+ if result ['rc' ] != 0 :
66+ raise Exception ("Failed to add IPv6 static route: {}" .format (result ['stderr' ]))
67+ except Exception as e :
68+ logger .error ("Error occurred while adding IPv6 static route: %s" , str (e ))
69+ pytest .fail ("IPv6 static route addition failed" )
70+
71+ # Verify IPv4 route is in the routing table
72+
73+ try :
74+ result = duthost .command ("ip route show {}" .format (STATIC_ROUTE ))
75+ assert result ['rc' ] == 0 , "Failed to show IPv4 static route: {}" .format (result ['stderr' ])
76+ assert "via " + gather_facts ['dst_host_ipv4' ] in result ["stdout" ], "IPv4 static route verification failed"
77+ except Exception as e :
78+ logger .error ("Error occurred while verifying IPv4 static route: %s" , str (e ))
79+ pytest .fail ("IPv4 static route verification failed" )
80+
81+ # # Verify IPv6 route is in the routing table
82+ try :
83+ result = duthost .command ("ip -6 route show {}" .format (STATIC_ROUTE_IPV6 ))
84+ assert result ['rc' ] == 0 , "Failed to show IPv6 static route: {}" .format (result ['stderr' ])
85+ assert "via " + gather_facts ['dst_host_ipv6' ] in result ["stdout" ], "IPv6 static route verification failed"
86+ except Exception as e :
87+ logger .error ("Error occurred while verifying IPv6 static route: %s" , str (e ))
88+ pytest .fail ("IPv6 static route verification failed" )
89+
90+ # Continue with the test
91+ yield
92+
93+ # Use either individual functions
94+ delete_ipv4_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts )
95+ delete_ipv6_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts )
96+
97+ # Or use the combined function
98+ # delete_static_routes(duthosts, enum_rand_one_per_hwsku_frontend_hostname, gather_facts)
99+
100+
101+ @pytest .fixture (autouse = True )
102+ def setup_teardown (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts ):
103+ yield
104+ # Teardown - delete the static routes
105+ delete_ipv4_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts )
106+ delete_ipv6_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts )
107+
108+
109+ def delete_ipv4_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts ):
110+ """
111+ Function to delete IPv4 static route from the DUT.
112+
113+ This function performs the following actions:
114+ 1. Gets the correct DUT host instance
115+ 2. Deletes IPv4 static route from the DUT
116+ 3. Verifies that the route is removed correctly
117+
118+ Args:
119+ duthosts: Fixture providing access to DUT hosts
120+ enum_rand_one_per_hwsku_frontend_hostname: Fixture selecting a random frontend DUT
121+ gather_facts: Fixture providing network facts
122+
123+ Raises:
124+ pytest.fail: If any step in removing or verifying route fails
125+ """
126+ duthost = duthosts [enum_rand_one_per_hwsku_frontend_hostname ]
127+
128+ # Check if IPv4 route exists before deleting
129+ try :
130+ check_result = duthost .command ("ip route show {}" .format (STATIC_ROUTE ))
131+ if check_result ['rc' ] == 0 and check_result ['stdout' ].strip ():
132+ # Route exists, delete it
133+ result = duthost .command ("ip route del {}" .format (STATIC_ROUTE ))
134+ if result ['rc' ] != 0 :
135+ raise Exception ("Failed to delete IPv4 static route: {}" .format (result ['stderr' ]))
136+ logger .info ("Successfully deleted IPv4 static route: {}" .format (STATIC_ROUTE ))
137+ else :
138+ logger .info ("IPv4 static route {} not present, skipping deletion" .format (STATIC_ROUTE ))
139+ except Exception as e :
140+ logger .error ("Error occurred while handling IPv4 static route: %s" , str (e ))
141+ pytest .fail ("IPv4 static route operation failed" )
142+
143+ # Verify IPv4 route is removed from the routing table
144+ try :
145+ result = duthost .command ("ip route show {}" .format (STATIC_ROUTE ))
146+ assert "No such process" in result ['stderr' ] or result ['stdout' ].strip () == "" , \
147+ "IPv4 static route still exists in routing table"
148+ except Exception as e :
149+ logger .error ("Error occurred while verifying IPv4 static route removal: %s" , str (e ))
150+ pytest .fail ("IPv4 static route removal verification failed" )
151+
152+
153+ def delete_ipv6_static_route (duthosts , enum_rand_one_per_hwsku_frontend_hostname , gather_facts ):
154+ """
155+ Function to delete IPv6 static route from the DUT.
156+
157+ This function performs the following actions:
158+ 1. Gets the correct DUT host instance
159+ 2. Deletes IPv6 static route from the DUT
160+ 3. Verifies that the route is removed correctly
161+
162+ Args:
163+ duthosts: Fixture providing access to DUT hosts
164+ enum_rand_one_per_hwsku_frontend_hostname: Fixture selecting a random frontend DUT
165+ gather_facts: Fixture providing network facts
166+
167+ Raises:
168+ pytest.fail: If any step in removing or verifying route fails
169+ """
170+ duthost = duthosts [enum_rand_one_per_hwsku_frontend_hostname ]
171+
172+ # Check if IPv6 route exists before deleting
173+ try :
174+ check_result = duthost .command ("ip -6 route show {}" .format (STATIC_ROUTE_IPV6 ))
175+ if check_result ['rc' ] == 0 and check_result ['stdout' ].strip ():
176+ # Route exists, delete it
177+ result = duthost .command ("ip -6 route del {}" .format (STATIC_ROUTE_IPV6 ))
178+ if result ['rc' ] != 0 :
179+ raise Exception ("Failed to delete IPv6 static route: {}" .format (result ['stderr' ]))
180+ logger .info ("Successfully deleted IPv6 static route: {}" .format (STATIC_ROUTE_IPV6 ))
181+ else :
182+ logger .info ("IPv6 static route {} not present, skipping deletion" .format (STATIC_ROUTE_IPV6 ))
183+ except Exception as e :
184+ logger .error ("Error occurred while handling IPv6 static route: %s" , str (e ))
185+ pytest .fail ("IPv6 static route operation failed" )
186+
187+ # Verify IPv6 route is removed from the routing table
188+ try :
189+ result = duthost .command ("ip -6 route show {}" .format (STATIC_ROUTE_IPV6 ))
190+ assert "No such process" in result ['stderr' ] or result ['stdout' ].strip () == "" , \
191+ "IPv6 static route still exists in routing table"
192+ except Exception as e :
193+ logger .error ("Error occurred while verifying IPv6 static route removal: %s" , str (e ))
194+ pytest .fail ("IPv6 static route removal verification failed" )
195+
196+
197+ ipv4_test_cases = [
198+ pytest .param (
199+ 'Same SIP and DIP' ,
200+ lambda facts : facts ['dst_host_ipv4' ],
201+ lambda facts : facts ['dst_host_ipv4' ],
202+ id = 'ipv4_same_sip_dip'
203+ ),
204+ pytest .param (
205+ 'Different subnet SIP/DIP - Directly connected route' ,
206+ lambda facts : facts ['src_host_ipv4' ],
207+ lambda facts : facts ['dst_host_ipv4' ],
208+ id = 'ipv4_different_sip_dip_connectedroute'
209+ ),
210+ pytest .param (
211+ 'Different subnet SIP/DIP - Destination not directly connected' ,
212+ lambda facts : facts ['src_host_ipv4' ],
213+ lambda facts : STATIC_ROUTE .split ('/' )[0 ],
214+ id = 'ipv4_different_sip_dip_staticrouteprefix'
49215 )
50- logger .info ("\n Expect Packet:\n eth_dst: {}, eth_src: {}, ipv6 ip: {}" .format (
51- facts ['dst_host_mac' ], facts ['dst_router_mac' ], facts ['dst_host_ipv6' ])
216+ ]
217+
218+ ipv6_test_cases = [
219+ pytest .param (
220+ 'Same SIP and DIP' ,
221+ lambda facts : facts ['dst_host_ipv6' ],
222+ lambda facts : facts ['dst_host_ipv6' ],
223+ id = 'ipv6_same_sip_dip'
224+ ),
225+ pytest .param (
226+ 'Different subnet SIP/DIP - Directly connected route' ,
227+ lambda facts : facts ['src_host_ipv6' ],
228+ lambda facts : facts ['dst_host_ipv6' ],
229+ id = 'ipv6_different_sip_dip_connectedroute'
230+ ),
231+ pytest .param (
232+ 'Different subnet SIP/DIP - Destination not directly connected' ,
233+ lambda facts : facts ['src_host_ipv6' ],
234+ lambda facts : STATIC_ROUTE_IPV6 .split ('/' )[0 ],
235+ id = 'ipv6_different_sip_dip_staticrouteprefix'
52236 )
237+ ]
53238
54- testutils .verify_packet_any_port (ptfadapter , exp_pkt , facts ['dst_port_ids' ], timeout = WAIT_EXPECTED_PACKET_TIMEOUT )
55239
240+ @pytest .mark .parametrize ('test_name, get_src_ip, get_dst_ip' , ipv4_test_cases )
241+ def test_ipv4_forwarding (tbinfo , ptfadapter , gather_facts , enum_rand_one_frontend_asic_index ,
242+ test_name , get_src_ip , get_dst_ip ):
243+ """Test IPv4 forwarding with various source/destination IP combinations"""
244+ ptfadapter .reinit ()
245+ logger .info ("Testing case: {}" .format (test_name ))
246+
247+ ip_src = get_src_ip (gather_facts )
248+ ip_dst = get_dst_ip (gather_facts )
56249
57- def run_test_ipv4 (ptfadapter , facts ):
58- logger .info ("Running test with ipv4 packets" )
59250 pkt = testutils .simple_udp_packet (
60- eth_dst = facts ['src_router_mac' ],
61- eth_src = facts ['src_host_mac' ],
62- ip_src = facts [ 'dst_host_ipv4' ] ,
63- ip_dst = facts [ 'dst_host_ipv4' ] ,
251+ eth_dst = gather_facts ['src_router_mac' ],
252+ eth_src = gather_facts ['src_host_mac' ],
253+ ip_src = ip_src ,
254+ ip_dst = ip_dst ,
64255 ip_ttl = DEFAULT_HLIM_TTL
65256 )
66- logger .info ("\n Send Packet:\n eth_dst: {}, eth_src: {}, ipv4 ip: {}" .format (
67- facts ['src_router_mac' ], facts ['src_host_mac' ], facts ['dst_host_ipv4' ])
257+ logger .info ("\n Send Packet:\n eth_dst: {}, eth_src: {}, ip_src: {}, ip_dst: {}" .format (
258+ gather_facts ['src_router_mac' ], gather_facts ['src_host_mac' ],
259+ ip_src , ip_dst )
68260 )
69261
70- testutils .send (ptfadapter , facts ['src_port_ids' ][0 ], pkt )
262+ testutils .send (ptfadapter , gather_facts ['src_port_ids' ][0 ], pkt )
71263
72264 exp_pkt = testutils .simple_udp_packet (
73- eth_dst = facts ['dst_host_mac' ],
74- eth_src = facts ['dst_router_mac' ],
75- ip_src = facts [ 'dst_host_ipv4' ] ,
76- ip_dst = facts [ 'dst_host_ipv4' ] ,
265+ eth_dst = gather_facts ['dst_host_mac' ],
266+ eth_src = gather_facts ['dst_router_mac' ],
267+ ip_src = ip_src ,
268+ ip_dst = ip_dst ,
77269 ip_ttl = DEFAULT_HLIM_TTL - 1
78270 )
79- logger .info ("\n Expect Packet:\n eth_dst: {}, eth_src: {}, ipv4 ip: {}" .format (
80- facts ['dst_host_mac' ], facts ['dst_router_mac' ], facts ['dst_host_ipv4' ])
271+ logger .info (
272+ "\n Expect Packet:\n eth_dst: {}, eth_src: {}, ip_src: {}, ip_dst: {}" .format (
273+ gather_facts ['dst_host_mac' ], gather_facts ['dst_router_mac' ],
274+ ip_src , ip_dst )
81275 )
82276
83- testutils .verify_packet_any_port (ptfadapter , exp_pkt , facts ['dst_port_ids' ], timeout = WAIT_EXPECTED_PACKET_TIMEOUT )
277+ try :
278+ testutils .verify_packet_any_port (ptfadapter , exp_pkt ,
279+ gather_facts ['dst_port_ids' ],
280+ timeout = WAIT_EXPECTED_PACKET_TIMEOUT )
281+ except AssertionError as e :
282+ logger .error ("Expected packet was not received" )
283+ pytest .fail ("Test case failed: {} - {}" .format (test_name , str (e )))
284+
285+ logger .info ("Test case passed: {}\n " .format (test_name ))
84286
85287
86- def test_dip_sip (tbinfo , ptfadapter , gather_facts , enum_rand_one_frontend_asic_index ):
288+ @pytest .mark .parametrize ('test_name, get_src_ip, get_dst_ip' , ipv6_test_cases )
289+ def test_ipv6_forwarding (tbinfo , ptfadapter , gather_facts , enum_rand_one_frontend_asic_index ,
290+ test_name , get_src_ip , get_dst_ip ):
291+ """Test IPv6 forwarding with various source/destination IP combinations"""
87292 ptfadapter .reinit ()
88- run_test_ipv4 (ptfadapter , gather_facts )
89- run_test_ipv6 (ptfadapter , gather_facts )
293+
294+ logger .info ("Testing case: {}" .format (test_name ))
295+
296+ ipv6_src = get_src_ip (gather_facts )
297+ ipv6_dst = get_dst_ip (gather_facts )
298+
299+ pkt = testutils .simple_udpv6_packet (
300+ eth_dst = gather_facts ['src_router_mac' ],
301+ eth_src = gather_facts ['src_host_mac' ],
302+ ipv6_src = ipv6_src ,
303+ ipv6_dst = ipv6_dst ,
304+ ipv6_hlim = DEFAULT_HLIM_TTL
305+ )
306+ logger .info ("\n Send Packet:\n eth_dst: {}, eth_src: {}, ipv6_src: {}, ipv6_dst: {}" .format (
307+ gather_facts ['src_router_mac' ], gather_facts ['src_host_mac' ],
308+ ipv6_src , ipv6_dst )
309+ )
310+
311+ testutils .send (ptfadapter , gather_facts ['src_port_ids' ][0 ], pkt )
312+
313+ exp_pkt = testutils .simple_udpv6_packet (
314+ eth_dst = gather_facts ['dst_host_mac' ],
315+ eth_src = gather_facts ['dst_router_mac' ],
316+ ipv6_src = ipv6_src ,
317+ ipv6_dst = ipv6_dst ,
318+ ipv6_hlim = DEFAULT_HLIM_TTL - 1
319+ )
320+ logger .info (
321+ "\n Expect Packet:\n eth_dst: {}, eth_src: {}, ipv6_src: {}, ipv6_dst: {}" .format (
322+ gather_facts ['dst_host_mac' ], gather_facts ['dst_router_mac' ],
323+ ipv6_src , ipv6_dst )
324+ )
325+
326+ try :
327+ testutils .verify_packet_any_port (ptfadapter , exp_pkt ,
328+ gather_facts ['dst_port_ids' ],
329+ timeout = WAIT_EXPECTED_PACKET_TIMEOUT )
330+ except AssertionError as e :
331+ logger .error ("Expected packet was not received" )
332+ pytest .fail ("Test case failed: {} - {}" .format (test_name , str (e )))
333+ logger .info ("Test case passed: {}\n " .format (test_name ))
0 commit comments