Skip to content

Commit e2e5c33

Browse files
authored
Added ipv6-only support to vlan_ping (#21018)
1 parent 4ebcd4f commit e2e5c33

File tree

2 files changed

+145
-82
lines changed

2 files changed

+145
-82
lines changed

tests/common/plugins/conditional_mark/tests_mark_conditions.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4815,10 +4815,6 @@ vlan/test_vlan_ping.py:
48154815
conditions:
48164816
- "asic_type in ['broadcom']"
48174817
- "https://github.com/sonic-net/sonic-mgmt/issues/15061 and 'dualtor-aa' in topo_name"
4818-
xfail:
4819-
reason: "xfail for IPv6-only topologies, need to add support for IPv6-only"
4820-
conditions:
4821-
- "https://github.com/sonic-net/sonic-mgmt/issues/19929 and '-v6-' in topo_name"
48224818

48234819
#######################################
48244820
##### voq #####

tests/vlan/test_vlan_ping.py

Lines changed: 145 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import ptf.packet as scapy
77
from ptf.mask import Mask
88
import six
9-
from ipaddress import ip_address, IPv4Address
109
from tests.common.helpers.assertions import pytest_assert as py_assert
1110
from tests.common.dualtor.mux_simulator_control import toggle_all_simulator_ports_to_rand_selected_tor_m # noqa: F401
1211
from 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

192210
def 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

Comments
 (0)