Skip to content

Commit 011edfe

Browse files
authored
VPP srv6 sonic mgmt support (#21103)
Enabling srv6/test_srv6_static_config.py and srv6/test_srv6_dataplane.py test cases for SONiC-VPP on T1 and T1-lag. Dependent on sonic-net/sonic-buildimage#24359 and sonic-net/sonic-sairedis#1673 to pass. What is the motivation for this PR? SONiC VPP has some SRv6 features enabled, but currently no sonic-mgmt test cases are covering them. How did you do it? How did you verify/test it? Ran sonic-mgmt locally with the above two PRs applied to SONiC-VPP image and all cases are passing.
1 parent b99f16b commit 011edfe

File tree

4 files changed

+70
-27
lines changed

4 files changed

+70
-27
lines changed

.azure-pipelines/pr_test_scripts.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,8 @@ t1-lag-vpp:
710710
- route/test_route_flap.py
711711
- route/test_route_perf.py
712712
- route/test_route_bgp_ecmp.py
713+
- srv6/test_srv6_dataplane.py
714+
- srv6/test_srv6_static_config.py
713715
- vxlan/test_vxlan_ecmp.py
714716
- vxlan/test_vxlan_decap.py
715717
- vxlan/test_vnet_decap.py

tests/common/plugins/conditional_mark/tests_mark_conditions.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4629,7 +4629,8 @@ srv6/test_srv6_dataplane.py:
46294629
reason: "Only target mellanox and brcm platform with 202412 image at this time. Skip for non Arista-7060X6-64PE-B-* TH5 SKUs. Skip for t0-isolated-d96u32, t1-isolated-d32/128. Or test case has issue on the t0-isolated-d256u256s2 topo."
46304630
conditions_logical_operator: or
46314631
conditions:
4632-
- "asic_type not in ['mellanox', 'broadcom'] or release not in ['202412']"
4632+
- "asic_type not in ['mellanox', 'broadcom', 'vpp']"
4633+
- "release not in ['202412'] and asic_type not in ['vpp']"
46334634
- "'Arista-7060X6-64PE' in hwsku and 'Arista-7060X6-64PE-B' not in hwsku"
46344635
- "topo_name in ['t0-isolated-d96u32s2', 't1-isolated-d128', 't1-isolated-d32']"
46354636
- "'t0-isolated-d256u256s2' in topo_name and platform in ['x86_64-nvidia_sn5640-r0']"
@@ -4639,15 +4640,15 @@ srv6/test_srv6_static_config.py:
46394640
reason: "Requires particular image support, skip in PR testing. Skip for non Arista-7060X6-64PE-B-* TH5 SKUs. Skip for t0-isolated-d96u32, t1-isolated-d32/128"
46404641
conditions_logical_operator: or
46414642
conditions:
4642-
- "release not in ['202412']"
4643+
- "release not in ['202412'] and asic_type not in ['vpp']"
46434644
- "'Arista-7060X6-64PE' in hwsku and 'Arista-7060X6-64PE-B' not in hwsku"
46444645
- "topo_name in ['t0-isolated-d96u32s2', 't1-isolated-d128', 't1-isolated-d32']"
46454646

46464647
srv6/test_srv6_static_config.py::test_uDT46_config:
46474648
skip:
46484649
reason: "Unsupported platform"
46494650
conditions:
4650-
- "asic_type in ['mellanox']"
4651+
- "asic_type in ['mellanox', 'vpp']"
46514652

46524653
srv6/test_srv6_vlan_forwarding.py:
46534654
skip:

tests/srv6/srv6_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ def validate_srv6_counters(duthost, srv6_pkt_list, mysid_list, pkt_num):
505505
Returns:
506506
bool: True if counters match expected values, False otherwise
507507
"""
508+
if duthost.facts["asic_type"] == "vpp":
509+
return True
508510
try:
509511
stats_list = duthost.show_and_parse('show srv6 stats')
510512
stats_dict = {item['mysid']: item for item in stats_list}

tests/srv6/test_srv6_dataplane.py

Lines changed: 62 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
logger = logging.getLogger(__name__)
2727

2828
pytestmark = [
29-
pytest.mark.asic("mellanox", "broadcom"),
29+
pytest.mark.asic("mellanox", "broadcom", "vpp"),
3030
pytest.mark.topology("t0", "t1")
3131
]
3232

@@ -70,12 +70,38 @@ def get_ptf_src_port_and_dut_port_and_neighbor(dut, tbinfo):
7070
for entry in neighbor_table:
7171
intf = entry[0]
7272
if intf in ports_map:
73-
return intf, ports_map[intf], entry[1] # local intf, ptf_src_port, neighbor hostname
73+
# Check if this interface is part of a portchannel
74+
ptf_ports = [ports_map[intf]]
75+
76+
# Check if the interface is a member of any portchannel
77+
if 'minigraph_portchannels' in dut_mg_facts:
78+
for pc_name, pc_info in dut_mg_facts['minigraph_portchannels'].items():
79+
if intf in pc_info.get('members', []):
80+
# Found a portchannel - get PTF ports for all members
81+
logger.info("Interface {} is a member of portchannel {}".format(intf, pc_name))
82+
ptf_ports = []
83+
for member in pc_info['members']:
84+
if member in ports_map:
85+
ptf_ports.append(ports_map[member])
86+
logger.info("Added portchannel member {} with PTF port {}".format(
87+
member, ports_map[member]))
88+
break
89+
90+
return intf, ptf_ports, entry[1] # local intf, ptf_src_ports (list), neighbor hostname
7491

7592
pytest.skip("No active LLDP neighbor found for {}".format(dut))
7693

7794

78-
def run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh):
95+
def run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh):
96+
# Convert single port to list for uniform handling
97+
if isinstance(ptf_src_ports, int):
98+
ptf_src_ports_list = [ptf_src_ports]
99+
else:
100+
ptf_src_ports_list = ptf_src_ports
101+
102+
# Use the first port for sending packets
103+
ptf_src_port = ptf_src_ports_list[0]
104+
79105
for i in range(0, 10):
80106
# generate a random payload
81107
payload = ''.join(random.choices(string.ascii_letters + string.digits, k=20))
@@ -100,7 +126,7 @@ def run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapte
100126
expected_pkt['IPv6'].dst = "fcbb:bbbb:2::"
101127
expected_pkt['IPv6'].hlim -= 1
102128
logger.debug("Expected packet #{}: {}".format(i, expected_pkt.summary()))
103-
runSendReceive(injected_pkt, ptf_src_port, expected_pkt, [ptf_src_port], True, ptfadapter)
129+
runSendReceive(injected_pkt, ptf_src_port, expected_pkt, ptf_src_ports_list, True, ptfadapter)
104130

105131

106132
@pytest.fixture()
@@ -118,13 +144,13 @@ def setup_uN(duthosts, enum_frontend_dut_hostname, enum_frontend_asic_index, tbi
118144
cli_options = " -n " + duthost.get_namespace_from_asic_id(asic_index)
119145
dut_asic = duthost.asic_instance[asic_index]
120146
dut_mac = dut_asic.get_router_mac()
121-
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(dut_asic, tbinfo)
147+
dut_port, ptf_src_ports, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(dut_asic, tbinfo)
122148
else:
123149
cli_options = ''
124150
dut_mac = duthost._get_router_mac()
125-
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(duthost, tbinfo)
151+
dut_port, ptf_src_ports, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(duthost, tbinfo)
126152

127-
logger.info("Doing test on DUT port {} | PTF port {}".format(dut_port, ptf_src_port))
153+
logger.info("Doing test on DUT port {} | PTF ports {}".format(dut_port, ptf_src_ports))
128154

129155
neighbor_ip = None
130156
# get neighbor IP
@@ -141,6 +167,8 @@ def setup_uN(duthosts, enum_frontend_dut_hostname, enum_frontend_asic_index, tbi
141167
for line in lines:
142168
if dut_port in line:
143169
dut_port = line.split()[1]
170+
logger.info("Using portchannel interface: {}".format(dut_port))
171+
break
144172

145173
sonic_db_cli = "sonic-db-cli" + cli_options
146174

@@ -169,7 +197,7 @@ def setup_uN(duthosts, enum_frontend_dut_hostname, enum_frontend_asic_index, tbi
169197
"duthost": duthost,
170198
"dut_mac": dut_mac,
171199
"dut_port": dut_port,
172-
"ptf_src_port": ptf_src_port,
200+
"ptf_src_ports": ptf_src_ports,
173201
"neighbor_ip": neighbor_ip,
174202
"cli_options": cli_options,
175203
"ptf_port_ids": ptf_port_ids
@@ -215,6 +243,11 @@ def _validate_srv6_function(self, duthost, ptfadapter, dscp_mode):
215243
logger.info("Skip the test for Broadcom ASIC with SRH")
216244
continue
217245

246+
if duthost.facts["asic_type"] == "vpp" and \
247+
(srv6_packet['validate_usd_flavor']):
248+
logger.info("Skip the test for VPP with USD flavor.")
249+
continue
250+
218251
logger.info('-------------------------------------------------------------------------')
219252
if srv6_packet['validate_dip_shift']:
220253
logger.info('Validate DIP shift')
@@ -348,11 +381,11 @@ def test_srv6_full_func(self, config_setup, srv6_crm_total_sids,
348381
def test_srv6_dataplane_after_config_reload(setup_uN, ptfadapter, ptfhost, with_srh):
349382
duthost = setup_uN['duthost']
350383
dut_mac = setup_uN['dut_mac']
351-
ptf_src_port = setup_uN['ptf_src_port']
384+
ptf_src_ports = setup_uN['ptf_src_ports']
352385
neighbor_ip = setup_uN['neighbor_ip']
353386

354387
# verify the forwarding works
355-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
388+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
356389

357390
# reload the config
358391
duthost.command("config reload -y -f")
@@ -372,18 +405,18 @@ def test_srv6_dataplane_after_config_reload(setup_uN, ptfadapter, ptfhost, with_
372405
"IP table not updating MAC for neighbour")
373406

374407
# verify the forwarding works after config reload
375-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
408+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
376409

377410

378411
@pytest.mark.parametrize("with_srh", [True, False])
379412
def test_srv6_dataplane_after_bgp_restart(setup_uN, ptfadapter, ptfhost, with_srh):
380413
duthost = setup_uN['duthost']
381414
dut_mac = setup_uN['dut_mac']
382-
ptf_src_port = setup_uN['ptf_src_port']
415+
ptf_src_ports = setup_uN['ptf_src_ports']
383416
neighbor_ip = setup_uN['neighbor_ip']
384417

385418
# verify the forwarding works
386-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
419+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
387420

388421
# restart BGP service, which will restart the BGP container
389422
if duthost.is_multi_asic:
@@ -402,26 +435,27 @@ def test_srv6_dataplane_after_bgp_restart(setup_uN, ptfadapter, ptfhost, with_sr
402435

403436
pytest_assert(wait_until(60, 5, 0, is_bgp_route_synced, duthost), "BGP route is not synced")
404437
# verify the forwarding works after BGP restart
405-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
438+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
406439

407440

408441
@pytest.mark.parametrize("with_srh", [True, False])
409442
def test_srv6_dataplane_after_reboot(setup_uN, ptfadapter, ptfhost, localhost, with_srh, loganalyzer):
410443
duthost = setup_uN['duthost']
411444
dut_mac = setup_uN['dut_mac']
412-
ptf_src_port = setup_uN['ptf_src_port']
445+
ptf_src_ports = setup_uN['ptf_src_ports']
413446
neighbor_ip = setup_uN['neighbor_ip']
414447

415448
# Reloading the configuration will restart eth0 and update the TACACS settings.
416449
# This change may introduce a delay, potentially causing temporary TACACS reporting errors.
417-
loganalyzer[duthost.hostname].ignore_regex.extend([r".*tac_connect_single: .*",
418-
r".*nss_tacplus: .*"])
450+
if loganalyzer and duthost.hostname and duthost.hostname in loganalyzer:
451+
loganalyzer[duthost.hostname].ignore_regex.extend([r".*tac_connect_single: .*",
452+
r".*nss_tacplus: .*"])
419453

420454
# verify the forwarding works
421-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
455+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
422456

423457
# reboot DUT
424-
reboot(duthost, localhost, safe_reboot=True, check_intf_up_ports=True, wait_for_bgp=True)
458+
reboot(duthost, localhost, wait=300, safe_reboot=True, check_intf_up_ports=True, wait_for_bgp=True)
425459

426460
sonic_db_cli = "sonic-db-cli" + setup_uN['cli_options']
427461
# wait for the config to be reprogrammed
@@ -433,17 +467,21 @@ def test_srv6_dataplane_after_reboot(setup_uN, ptfadapter, ptfhost, localhost, w
433467

434468
pytest_assert(wait_until(60, 5, 0, is_bgp_route_synced, duthost), "BGP route is not synced")
435469
# verify the forwarding works after reboot
436-
run_srv6_traffic_test(duthost, dut_mac, ptf_src_port, neighbor_ip, ptfadapter, ptfhost, with_srh)
470+
run_srv6_traffic_test(duthost, dut_mac, ptf_src_ports, neighbor_ip, ptfadapter, ptfhost, with_srh)
437471

438472

439473
@pytest.mark.parametrize("with_srh", [True, False])
440474
def test_srv6_no_sid_blackhole(setup_uN, ptfadapter, ptfhost, with_srh):
441475
duthost = setup_uN['duthost']
442476
dut_mac = setup_uN['dut_mac']
443477
dut_port = setup_uN['dut_port']
444-
ptf_src_port = setup_uN['ptf_src_port']
478+
ptf_src_ports = setup_uN['ptf_src_ports']
445479
neighbor_ip = setup_uN['neighbor_ip']
446480
ptf_port_ids = setup_uN['ptf_port_ids']
481+
482+
# Use the first port to send traffic
483+
first_ptf_port = ptf_src_ports[0] if isinstance(ptf_src_ports, list) else ptf_src_ports
484+
447485
# Verify that the ASIC DB has the SRv6 SID entries
448486
sonic_db_cli = "sonic-db-cli" + setup_uN['cli_options']
449487
assert wait_until(20, 5, 0, verify_asic_db_sid_entry_exist, duthost, sonic_db_cli), \
@@ -462,7 +500,7 @@ def test_srv6_no_sid_blackhole(setup_uN, ptfadapter, ptfhost, with_srh):
462500
if with_srh:
463501
injected_pkt = simple_ipv6_sr_packet(
464502
eth_dst=dut_mac,
465-
eth_src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode(),
503+
eth_src=ptfadapter.dataplane.get_mac(0, first_ptf_port).decode(),
466504
ipv6_src=ptfhost.mgmt_ipv6 if ptfhost.mgmt_ipv6 else "1000::1",
467505
ipv6_dst="fcbb:bbbb:3:2::",
468506
srh_seg_left=1,
@@ -471,7 +509,7 @@ def test_srv6_no_sid_blackhole(setup_uN, ptfadapter, ptfhost, with_srh):
471509
dport=4791) / Raw(load=payload)
472510
)
473511
else:
474-
injected_pkt = Ether(dst=dut_mac, src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode()) \
512+
injected_pkt = Ether(dst=dut_mac, src=ptfadapter.dataplane.get_mac(0, first_ptf_port).decode()) \
475513
/ IPv6(src=ptfhost.mgmt_ipv6 if ptfhost.mgmt_ipv6 else "1000::1", dst="fcbb:bbbb:3:2::") \
476514
/ IPv6(dst=neighbor_ip, src=ptfhost.mgmt_ipv6 if ptfhost.mgmt_ipv6 else "1000::1") \
477515
/ UDP(dport=4791) / Raw(load=payload)
@@ -484,7 +522,7 @@ def test_srv6_no_sid_blackhole(setup_uN, ptfadapter, ptfhost, with_srh):
484522
expected_pkt = Mask(expected_pkt)
485523
expected_pkt.set_do_not_care_packet(Ether, "dst")
486524
expected_pkt.set_do_not_care_packet(Ether, "src")
487-
send_packet(ptfadapter, ptf_src_port, injected_pkt, count=pkt_count)
525+
send_packet(ptfadapter, first_ptf_port, injected_pkt, count=pkt_count)
488526
verify_no_packet_any(ptfadapter, expected_pkt, ptf_port_ids, 0, 1)
489527

490528
# verify that the RX_DROP counter is incremented

0 commit comments

Comments
 (0)