66import ptf .packet as scapy
77from ptf .mask import Mask
88import six
9- from ipaddress import ip_address , IPv4Address
109from tests .common .helpers .assertions import pytest_assert as py_assert
1110from tests .common .dualtor .mux_simulator_control import toggle_all_simulator_ports_to_rand_selected_tor_m # noqa: F401
1211from tests .common .dualtor .dual_tor_utils import lower_tor_host # noqa: F401
@@ -24,18 +23,15 @@ def static_neighbor_entry(duthost, dic, oper, ip_version="both"):
2423 Performs addition or deletion of static entries of ipv4 and v6 neighbors in DUT based on 'oper' parameter
2524 """
2625 for member in list (dic .values ()):
27- if ip_version in ["4" , "both" ]:
26+ if ip_version in ["4" , "both" ] and 'ipv4' in member :
2827 if oper == "add" :
2928 logger .debug ("adding ipv4 static arp entry for ip %s on DUT" % (member ['ipv4' ]))
3029 duthost .shell ("sudo arp -s {0} {1}" .format (member ['ipv4' ], member ['mac' ]))
31-
3230 elif oper == "del" :
3331 logger .debug ("deleting ipv4 static arp entry for ip %s on DUT" % (member ['ipv4' ]))
3432 duthost .shell ("sudo arp -d {0}" .format (member ['ipv4' ]))
35- else :
36- logger .debug ("unknown operation" )
3733
38- if ip_version in ["6" , "both" ]:
34+ if ip_version in ["6" , "both" ] and 'ipv6' in member :
3935 if oper == "add" :
4036 logger .debug ("adding ipv6 static arp entry for ip %s on DUT" % (member ['ipv6' ]))
4137 duthost .shell (
@@ -47,7 +43,6 @@ def static_neighbor_entry(duthost, dic, oper, ip_version="both"):
4743 member ['Vlanid' ]))
4844 else :
4945 logger .debug ("unknown operation" )
50-
5146 else :
5247 logger .debug ("unknown IP version" )
5348
@@ -69,23 +64,35 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
6964 break
7065
7166 py_assert (vm_name is not None , "Can't get neighbor vm" )
67+
68+ # Determine which interface to use
7269 if topo_type == "mx" :
73- vm_ip_with_prefix = six . ensure_text ( vm_info [ 'conf' ][ 'interfaces' ][ ' Ethernet1'][ 'ipv4' ])
74- output = vm_info [ 'host' ]. command ( "ip addr show dev eth1" )
70+ interface_name = ' Ethernet1'
71+ dev_name = ' eth1'
7572 else :
7673 if 'Port-Channel1' in vm_info ['conf' ]['interfaces' ]:
77- vm_ip_with_prefix = six . ensure_text ( vm_info [ 'conf' ][ 'interfaces' ][ ' Port-Channel1'][ 'ipv4' ])
78- output = vm_info [ 'host' ]. command ( "ip addr show dev po1" )
74+ interface_name = ' Port-Channel1'
75+ dev_name = ' po1'
7976 else :
80- vm_ip_with_prefix = six . ensure_text ( vm_info [ 'conf' ][ 'interfaces' ][ ' Ethernet1'][ 'ipv4' ])
81- output = vm_info [ 'host' ]. command ( "ip addr show dev eth1" )
77+ interface_name = ' Ethernet1'
78+ dev_name = ' eth1'
8279 # in case of lower tor host we need to use the next portchannel
8380 if "dualtor-aa" in tbinfo ["topo" ]["name" ] and rand_one_dut_hostname == lower_tor_host .hostname :
84- vm_ip_with_prefix = six .ensure_text (vm_info ['conf' ]['interfaces' ]['Port-Channel2' ]['ipv4' ])
85- output = vm_info ['host' ].command ("ip addr show dev po2" )
81+ interface_name = 'Port-Channel2'
82+ dev_name = 'po2'
83+
84+ # Get IPv4 and IPv6 addresses if available
85+ vm_interface = vm_info ['conf' ]['interfaces' ][interface_name ]
86+ if 'ipv4' in vm_interface :
87+ vm_host_info ["ipv4" ] = ipaddress .IPv4Interface (six .ensure_text (vm_interface ['ipv4' ])).ip
88+ if 'ipv6' in vm_interface :
89+ vm_host_info ["ipv6" ] = ipaddress .IPv6Interface (six .ensure_text (vm_interface ['ipv6' ])).ip
90+
91+ py_assert ('ipv4' in vm_host_info or 'ipv6' in vm_host_info ,
92+ "VM interface {} has neither IPv4 nor IPv6 address" .format (interface_name ))
93+
94+ output = vm_info ['host' ].command ("ip addr show dev {}" .format (dev_name ))
8695 vm_host_info ["mac" ] = output ['stdout_lines' ][1 ].split ()[1 ]
87- vm_ip_intf = ipaddress .IPv4Interface (vm_ip_with_prefix ).ip
88- vm_host_info ["ipv4" ] = vm_ip_intf
8996 duthost = duthosts [rand_one_dut_hostname ]
9097 mg_facts = duthost .get_extended_minigraph_facts (tbinfo )
9198 if "dualtor-aa" in tbinfo ["topo" ]["name" ]:
@@ -105,21 +112,22 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
105112 ptfhost_info = {}
106113 ip4 = None
107114 ip6 = None
115+
116+ # Find the interface that connects to the selected VM
117+ vm_addr = vm_host_info .get ('ipv4' ) or vm_host_info .get ('ipv6' )
108118 for a_bgp_nbr in mg_facts ['minigraph_bgp' ]:
109- # Get the bgp neighbor connected to the selected VM
110- if a_bgp_nbr ['name' ] == vm_name and a_bgp_nbr ['addr' ] == str (vm_host_info ['ipv4' ]):
111- # Find the interface that connects to the selected VM
119+ if a_bgp_nbr ['name' ] == vm_name :
112120 if topo_type == "mx" :
113121 for intf in mg_facts ['minigraph_interfaces' ]:
114- if intf ['peer_addr' ] == str (vm_host_info [ 'ipv4' ] ):
122+ if intf ['peer_addr' ]. lower () == str (vm_addr ). lower ( ):
115123 vm_host_info ['port_index_list' ] = [mg_facts ['minigraph_ptf_indices' ][intf ['attachto' ]]]
116124 break
117125 else :
118126 ifaces_list = []
119127 # UL pkt may take any of the tor in case of dualtor-aa
120128 if "dualtor-aa" in tbinfo ["topo" ]["name" ]:
121129 for intf in mg_facts ['minigraph_portchannel_interfaces' ]:
122- if type ( ip_address ( intf ['peer_addr' ])) is IPv4Address :
130+ if intf ['peer_addr' ]. lower () == str ( vm_addr ). lower () :
123131 portchannel = intf ['attachto' ]
124132 for iface in mg_facts ['minigraph_portchannels' ][portchannel ]['members' ]:
125133 ifaces_list .append (mg_facts ['minigraph_ptf_indices' ][iface ])
@@ -128,7 +136,7 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
128136 else :
129137 if mg_facts ['minigraph_portchannel_interfaces' ]:
130138 for intf in mg_facts ['minigraph_portchannel_interfaces' ]:
131- if intf ['peer_addr' ] == str (vm_host_info [ 'ipv4' ] ):
139+ if intf ['peer_addr' ]. lower () == str (vm_addr ). lower ( ):
132140 portchannel = intf ['attachto' ]
133141 for iface in mg_facts ['minigraph_portchannels' ][portchannel ]['members' ]:
134142 ifaces_list .append (mg_facts ['minigraph_ptf_indices' ][iface ])
@@ -139,6 +147,9 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
139147 vm_host_info ['port_index_list' ] = ifaces_list
140148 break
141149
150+ py_assert ('port_index_list' in vm_host_info ,
151+ "Could not find interface connecting to VM {} with address {}" .format (vm_name , vm_addr ))
152+
142153 # getting the ipv4, ipv6 and vlan id of a vlan in DUT with 2 or more vlan members
143154 for k , v in list (my_cfg_facts ['VLAN' ].items ()):
144155 vlanid = v ['vlanid' ]
@@ -154,34 +165,41 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
154165 else :
155166 continue
156167
157- # ip prefixes of the vlan
158- vlan_ip_address_v4 = ipaddress .IPv4Interface (ip4 ).ip
159- vlan_ip_network_v4 = ipaddress .IPv4Interface (ip4 ).network
168+ # Ensure at least one IP version is configured on the VLAN
169+ py_assert (ip4 or ip6 , "VLAN{} has neither IPv4 nor IPv6 address configured" .format (vlanid ))
160170
161171 # selecting 2 random vlan members of DUT
162172 # Remove portchannel in vlan member list
163173 filter_vlan_member_list = [member for member in list (my_cfg_facts ['VLAN_MEMBER' ]['Vlan' + vlanid ].keys ())
164174 if member in mg_facts ['minigraph_ptf_indices' ]]
165175 rand_vlan_member_list = random .sample (filter_vlan_member_list , 2 )
166- exclude_ip = []
167- exclude_ip .extend (
168- [ipaddress .IPv4Interface (ip4 ).network .network_address , ipaddress .IPv4Interface (ip4 ).network .broadcast_address ,
169- vlan_ip_address_v4 ]
170- )
176+
177+ # Prepare IPv4 address pool if VLAN has IPv4
178+ ips_in_vlan = []
179+ if ip4 :
180+ vlan_ip_network_v4 = ipaddress .IPv4Interface (ip4 ).network
181+ vlan_ip_address_v4 = ipaddress .IPv4Interface (ip4 ).ip
182+ exclude_ip = [vlan_ip_network_v4 .network_address , vlan_ip_network_v4 .broadcast_address , vlan_ip_address_v4 ]
183+ ips_in_vlan = [x for x in vlan_ip_network_v4 if x not in exclude_ip ]
184+
171185 # getting port index, mac, ipv4 and ipv6 of ptf ports into a dict
172- ips_in_vlan = [x for x in vlan_ip_network_v4 if x not in exclude_ip ]
173186 for member in rand_vlan_member_list :
174- # Get first and last ip in vlan for two vlan members
175- ip_in_vlan = ips_in_vlan [0 if len (list (ptfhost_info .keys ())) == 0 else - 1 ]
176187 ptfhost_info [member ] = {}
177188 ptfhost_info [member ]["Vlanid" ] = vlanid
178189 ptfhost_info [member ]["port_index_list" ] = [mg_facts ['minigraph_ptf_indices' ][member ]]
179190 ptfhost_info [member ]["mac" ] = (ptfhost .shell (
180191 "ifconfig eth%d | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}'" % ptfhost_info [member ][
181192 "port_index_list" ][0 ]))['stdout' ]
182- ptfhost_info [member ]["ipv4" ] = str (ip_in_vlan )
183- ptfhost_info [member ]["ipv6" ] = str (
184- ipaddress .IPv6Interface (ip6 ).network [ptfhost_info [member ]["port_index_list" ][0 ]])
193+
194+ # Assign IPv4 address if VLAN has IPv4
195+ if ip4 :
196+ ip_in_vlan = ips_in_vlan [0 if len (ptfhost_info ) == 1 else - 1 ]
197+ ptfhost_info [member ]["ipv4" ] = str (ip_in_vlan )
198+
199+ # Assign IPv6 address if VLAN has IPv6
200+ if ip6 :
201+ ptfhost_info [member ]["ipv6" ] = str (
202+ ipaddress .IPv6Interface (ip6 ).network [ptfhost_info [member ]["port_index_list" ][0 ]])
185203
186204 yield vm_host_info , ptfhost_info
187205
@@ -190,35 +208,50 @@ def vlan_ping_setup(duthosts, rand_one_dut_hostname, ptfhost, nbrhosts, tbinfo,
190208
191209
192210def verify_icmp_packet (dut_mac , src_port , dst_port , ptfadapter , tbinfo ,
193- vlan_mac = None , dtor_ul = False , dtor_dl = False ):
194- if dtor_ul is True :
195- # use vlan int mac in case of dualtor UL test pkt
196- pkt = testutils .simple_icmp_packet (eth_src = str (src_port ['mac' ]),
197- eth_dst = str (vlan_mac ),
198- ip_src = str (src_port ['ipv4' ]),
199- ip_dst = str (dst_port ['ipv4' ]), ip_ttl = 64 )
200- else :
201- # use dut mac addr for all other test pkts
202- pkt = testutils .simple_icmp_packet (eth_src = str (src_port ['mac' ]),
203- eth_dst = str (dut_mac ),
204- ip_src = str (src_port ['ipv4' ]),
205- ip_dst = str (dst_port ['ipv4' ]), ip_ttl = 64 )
206- if dtor_dl is True :
207- # expect vlan int mac as src mac in dualtor DL test pkt
208- exptd_pkt = testutils .simple_icmp_packet (eth_src = str (vlan_mac ),
209- eth_dst = str (dst_port ['mac' ]),
210- ip_src = str (src_port ['ipv4' ]),
211- ip_dst = str (dst_port ['ipv4' ]), ip_ttl = 63 )
211+ vlan_mac = None , dtor_ul = False , dtor_dl = False , is_ipv6 = False ):
212+
213+ # Determine IP key and packet function based on IP version
214+ ip_key = 'ipv6' if is_ipv6 else 'ipv4'
215+ packet_func = testutils .simple_icmpv6_packet if is_ipv6 else testutils .simple_icmp_packet
216+
217+ # Build packet parameters based on IP version
218+ if is_ipv6 :
219+ ip_params = {
220+ 'ipv6_src' : str (src_port [ip_key ]),
221+ 'ipv6_dst' : str (dst_port [ip_key ]),
222+ 'ipv6_hlim' : 64
223+ }
224+ exp_ip_params = {
225+ 'ipv6_src' : str (src_port [ip_key ]),
226+ 'ipv6_dst' : str (dst_port [ip_key ]),
227+ 'ipv6_hlim' : 63
228+ }
212229 else :
213- # expect dut mac as src mac for non dualtor DL test pkt
214- exptd_pkt = testutils .simple_icmp_packet (eth_src = str (dut_mac ),
215- eth_dst = str (dst_port ['mac' ]),
216- ip_src = str (src_port ['ipv4' ]),
217- ip_dst = str (dst_port ['ipv4' ]), ip_ttl = 63 )
218- # skip smac check for dualtor-aa UL test pkt
230+ ip_params = {
231+ 'ip_src' : str (src_port [ip_key ]),
232+ 'ip_dst' : str (dst_port [ip_key ]),
233+ 'ip_ttl' : 64
234+ }
235+ exp_ip_params = {
236+ 'ip_src' : str (src_port [ip_key ]),
237+ 'ip_dst' : str (dst_port [ip_key ]),
238+ 'ip_ttl' : 63
239+ }
240+
241+ # Create test packet - use vlan mac for dualtor UL, otherwise use dut mac
242+ eth_dst = str (vlan_mac ) if dtor_ul else str (dut_mac )
243+ pkt = packet_func (eth_src = str (src_port ['mac' ]), eth_dst = eth_dst , ** ip_params )
244+
245+ # Create expected packet - use vlan mac for dualtor DL, otherwise use dut mac
246+ exp_eth_src = str (vlan_mac ) if dtor_dl else str (dut_mac )
247+ exptd_pkt = packet_func (eth_src = exp_eth_src , eth_dst = str (dst_port ['mac' ]), ** exp_ip_params )
248+
249+ # Skip smac check for dualtor-aa UL test pkt
219250 if "dualtor-aa" in tbinfo ["topo" ]["name" ] and dtor_ul is True :
220251 exptd_pkt = Mask (exptd_pkt )
221252 exptd_pkt .set_do_not_care_scapy (scapy .Ether , "src" )
253+
254+ # Send packet and verify with retry logic
222255 for i in range (5 ):
223256 testutils .send_packet (ptfadapter , src_port ['port_index_list' ][0 ], pkt )
224257 try :
@@ -257,14 +290,31 @@ def test_vlan_ping(vlan_ping_setup, duthosts, rand_one_dut_hostname, ptfadapter,
257290 logger .info ("Checking connectivity to ptf ports" )
258291
259292 for member in ptfhost_info :
260- if 'dualtor' in tbinfo ["topo" ]["name" ]:
261- verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
262- vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True )
263- verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
264- ptfadapter , tbinfo , vlan_mac , dtor_dl = True )
265- else :
266- verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info , ptfadapter , tbinfo )
267- verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ], ptfadapter , tbinfo )
293+ # Test IPv4 connectivity if VM has IPv4
294+ if 'ipv4' in vmhost_info :
295+ if 'dualtor' in tbinfo ["topo" ]["name" ]:
296+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
297+ vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True , is_ipv6 = False )
298+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
299+ ptfadapter , tbinfo , vlan_mac , dtor_dl = True , is_ipv6 = False )
300+ else :
301+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info ,
302+ ptfadapter , tbinfo , is_ipv6 = False )
303+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
304+ ptfadapter , tbinfo , is_ipv6 = False )
305+
306+ # Test IPv6 connectivity if VM has IPv6
307+ if 'ipv6' in vmhost_info :
308+ if 'dualtor' in tbinfo ["topo" ]["name" ]:
309+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
310+ vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True , is_ipv6 = True )
311+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
312+ ptfadapter , tbinfo , vlan_mac , dtor_dl = True , is_ipv6 = True )
313+ else :
314+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info ,
315+ ptfadapter , tbinfo , is_ipv6 = True )
316+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
317+ ptfadapter , tbinfo , is_ipv6 = True )
268318
269319 # flushing and re-adding ipv6 static arp entry
270320 static_neighbor_entry (duthost , ptfhost_info , "del" , "6" )
@@ -281,11 +331,28 @@ def test_vlan_ping(vlan_ping_setup, duthosts, rand_one_dut_hostname, ptfadapter,
281331 # Checking for connectivity
282332 logger .info ("Check connectivity to both ptfhost" )
283333 for member in ptfhost_info :
284- if 'dualtor' in tbinfo ["topo" ]["name" ]:
285- verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
286- vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True )
287- verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
288- ptfadapter , tbinfo , vlan_mac , dtor_dl = True )
289- else :
290- verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info , ptfadapter , tbinfo )
291- verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ], ptfadapter , tbinfo )
334+ # Test IPv4 connectivity if VM has IPv4
335+ if 'ipv4' in vmhost_info :
336+ if 'dualtor' in tbinfo ["topo" ]["name" ]:
337+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
338+ vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True , is_ipv6 = False )
339+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
340+ ptfadapter , tbinfo , vlan_mac , dtor_dl = True , is_ipv6 = False )
341+ else :
342+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info ,
343+ ptfadapter , tbinfo , is_ipv6 = False )
344+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
345+ ptfadapter , tbinfo , is_ipv6 = False )
346+
347+ # Test IPv6 connectivity if VM has IPv6
348+ if 'ipv6' in vmhost_info :
349+ if 'dualtor' in tbinfo ["topo" ]["name" ]:
350+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ],
351+ vmhost_info , ptfadapter , tbinfo , vlan_mac , dtor_ul = True , is_ipv6 = True )
352+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
353+ ptfadapter , tbinfo , vlan_mac , dtor_dl = True , is_ipv6 = True )
354+ else :
355+ verify_icmp_packet (duthost .facts ['router_mac' ], ptfhost_info [member ], vmhost_info ,
356+ ptfadapter , tbinfo , is_ipv6 = True )
357+ verify_icmp_packet (duthost .facts ['router_mac' ], vmhost_info , ptfhost_info [member ],
358+ ptfadapter , tbinfo , is_ipv6 = True )
0 commit comments