Skip to content

Commit

Permalink
[T2] Add case to test lossy fair-voq (sonic-net#10838)
Browse files Browse the repository at this point in the history
1, Add a new case to test lossy fair-voq.
2, Add lossy_queue_voq_2 and lossy_queue_voq_3 to qos_param_generator.py.
Default-voq and fair-voq will pass lossy_queue_voq_2, fair-voq and split-voq will pass lossy_queue_voq_3.
  • Loading branch information
zhixzhu authored and mssonicbld committed Sep 6, 2024
1 parent ac37f7f commit f0523e8
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,12 @@ qos/test_qos_sai.py::TestQosSai::testQosSaiLossyQueueVoq:
conditions:
- "asic_type not in ['cisco-8000'] or platform in ['x86_64-8122_64eh_o-r0']"

qos/test_qos_sai.py::TestQosSai::testQosSaiLossyQueueVoqMultiSrc:
skip:
reason: "Lossy Queue Voq multiple source test is not supported"
conditions:
- "asic_type not in ['cisco-8000']"

qos/test_qos_sai.py::TestQosSai::testQosSaiPGDrop:
skip:
reason: "PG drop size test is not supported."
Expand Down
19 changes: 19 additions & 0 deletions tests/qos/files/cisco/qos_param_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,25 @@ def __define_lossy_queue_voq(self):
"packet_size": 64,
"cell_size": self.buffer_size}
self.write_params("lossy_queue_voq_1", params)
if self.should_autogen(["lossy_queue_voq_2"]):
params = {"dscp": 8,
"ecn": 1,
"pg": 0,
"flow_config": "shared",
"pkts_num_trig_egr_drp": self.max_depth // self.buffer_size,
"pkts_num_margin": 4,
"packet_size": 64,
"cell_size": self.buffer_size}
self.write_params("lossy_queue_voq_2", params)
if self.should_autogen(["lossy_queue_voq_3"]):
params = {"dscp": 8,
"ecn": 1,
"pg": 0,
"pkts_num_trig_egr_drp": self.max_depth // self.buffer_size,
"pkts_num_margin": 4,
"packet_size": 64,
"cell_size": self.buffer_size}
self.write_params("lossy_queue_voq_3", params)

def __define_lossy_queue(self):
if self.should_autogen(["lossy_queue_1"]):
Expand Down
18 changes: 0 additions & 18 deletions tests/qos/files/qos_params.gb.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,6 @@ qos_params:
pkts_num_margin: 4
packet_size: 1350
cell_size: 384
lossy_queue_voq_2:
dscp: 8
ecn: 1
pg: 0
flow_config: shared
pkts_num_trig_egr_drp: 16000
pkts_num_margin: 4
packet_size: 64
cell_size: 384
wm_pg_shared_lossless:
dscp: 3
ecn: 1
Expand Down Expand Up @@ -308,15 +299,6 @@ qos_params:
pkts_num_margin: 4
packet_size: 1350
cell_size: 384
lossy_queue_voq_2:
dscp: 8
ecn: 1
pg: 0
flow_config: shared
pkts_num_trig_egr_drp: 16000
pkts_num_margin: 4
packet_size: 64
cell_size: 384
wm_pg_shared_lossless:
dscp: 3
ecn: 1
Expand Down
10 changes: 10 additions & 0 deletions tests/qos/qos_sai_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,16 @@ def skip_pacific_dst_asic(self, dutConfig):
yield
return

@pytest.fixture(scope="function", autouse=False)
def skip_longlink(self, dutQosConfig):
portSpeedCableLength = dutQosConfig["portSpeedCableLength"]
match = re.search("_([0-9]*)m", portSpeedCableLength)
if match and int(match.group(1)) > 2000:
pytest.skip(
"This test is skipped for longlink.")
yield
return

def populate_arp_entries(
self, get_src_dst_asic_and_duts,
ptfhost, dutTestParams, dutConfig, releaseAllPorts, handleFdbAging, tbinfo, lower_tor_host # noqa F811
Expand Down
76 changes: 75 additions & 1 deletion tests/qos/test_qos_sai.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ def testQosSaiLossyQueue(
testParams=testParams
)

@pytest.mark.parametrize("LossyVoq", ["lossy_queue_voq_1"])
@pytest.mark.parametrize("LossyVoq", ["lossy_queue_voq_1", "lossy_queue_voq_2"])
def testQosSaiLossyQueueVoq(
self, LossyVoq, ptfhost, dutTestParams, dutConfig, dutQosConfig,
ingressLossyProfile, duthost, localhost, get_src_dst_asic_and_duts,
Expand Down Expand Up @@ -2182,3 +2182,77 @@ def testQosSaiQWatermarkAllPorts(
ptfhost, testCase="sai_qos_tests.QWatermarkAllPortTest",
testParams=testParams
)

def testQosSaiLossyQueueVoqMultiSrc(
self, ptfhost, dutTestParams, dutConfig, dutQosConfig,
get_src_dst_asic_and_duts, skip_longlink
):
"""
Test QoS SAI Lossy queue with multiple source ports, applicable for fair-voq and split-voq
Args:
ptfhost (AnsibleHost): Packet Test Framework (PTF)
dutTestParams (Fixture, dict): DUT host test params
dutConfig (Fixture, dict): Map of DUT config containing dut interfaces, test port IDs, test port IPs,
and test ports
dutQosConfig (Fixture, dict): Map containing DUT host QoS configuration
Returns:
None
Raises:
RunAnsibleModuleFail if ptf test fails
"""
if not get_src_dst_asic_and_duts['single_asic_test']:
pytest.skip("LossyQueueVoqMultiSrc: This test is skipped on multi-asic,"
"since same ingress backplane port will be used on egress asic.")
portSpeedCableLength = dutQosConfig["portSpeedCableLength"]
LossyVoq = "lossy_queue_voq_3"
if LossyVoq in dutQosConfig["param"][portSpeedCableLength].keys():
qosConfig = dutQosConfig["param"][portSpeedCableLength]
else:
qosConfig = dutQosConfig["param"]

self.updateTestPortIdIp(dutConfig, get_src_dst_asic_and_duts, qosConfig[LossyVoq])

src_dut_index = get_src_dst_asic_and_duts['src_dut_index']
src_asic_index = get_src_dst_asic_and_duts['src_asic_index']

testParams = dict()
testParams.update(dutTestParams["basicParams"])
all_src_ports = dutConfig["testPortIps"][src_dut_index][src_asic_index]
all_src_port_ids = set(all_src_ports.keys())
if get_src_dst_asic_and_duts['single_asic_test']:
all_src_port_ids = set(all_src_ports.keys()) - \
set([dutConfig["testPorts"]["src_port_id"],
dutConfig["testPorts"]["dst_port_id"],
dutConfig["testPorts"]["dst_port_2_id"],
dutConfig["testPorts"]["dst_port_3_id"]])
all_src_port_ids = list(all_src_port_ids)
testParams.update({
"dscp": qosConfig[LossyVoq]["dscp"],
"ecn": qosConfig[LossyVoq]["ecn"],
"pg": qosConfig[LossyVoq]["pg"],
"src_port_id": dutConfig["testPorts"]["src_port_id"],
"src_port_ip": dutConfig["testPorts"]["src_port_ip"],
"src_port_2_id": all_src_port_ids[0],
"src_port_2_ip": all_src_ports[all_src_port_ids[0]]['peer_addr'],
"dst_port_id": dutConfig["testPorts"]["dst_port_id"],
"dst_port_ip": dutConfig["testPorts"]["dst_port_ip"],
"pkts_num_leak_out": dutQosConfig["param"][portSpeedCableLength]["pkts_num_leak_out"],
"pkts_num_trig_egr_drp": qosConfig[LossyVoq]["pkts_num_trig_egr_drp"]
})

if "platform_asic" in dutTestParams["basicParams"]:
testParams["platform_asic"] = dutTestParams["basicParams"]["platform_asic"]
else:
testParams["platform_asic"] = None

if "packet_size" in qosConfig[LossyVoq].keys():
testParams["packet_size"] = qosConfig[LossyVoq]["packet_size"]
testParams["cell_size"] = qosConfig[LossyVoq]["cell_size"]

if "pkts_num_margin" in qosConfig[LossyVoq].keys():
testParams["pkts_num_margin"] = qosConfig[LossyVoq]["pkts_num_margin"]

self.runPtfTest(
ptfhost, testCase="sai_qos_tests.LossyQueueVoqMultiSrcTest",
testParams=testParams
)
175 changes: 175 additions & 0 deletions tests/saitests/py3/sai_qos_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5668,3 +5668,178 @@ def runTest(self):

finally:
self.sai_thrift_port_tx_enable(self.dst_client, asic_type, dst_port_ids)


class LossyQueueVoqMultiSrcTest(sai_base_test.ThriftInterfaceDataPlane):
def setUp(self):
sai_base_test.ThriftInterfaceDataPlane.setUp(self)
time.sleep(5)
switch_init(self.clients)
# Parse input parameters
self.dscp = int(self.test_params['dscp'])
self.ecn = int(self.test_params['ecn'])
# The pfc counter index starts from index 2 in sai_thrift_read_port_counters
self.pg = int(self.test_params['pg']) + 2
self.sonic_version = self.test_params['sonic_version']
self.dst_port_id = int(self.test_params['dst_port_id'])
self.dst_port_ip = self.test_params['dst_port_ip']
self.dst_port_mac = self.dataplane.get_mac(0, self.dst_port_id)
router_mac = self.test_params['router_mac']
self.dst_port_mac = router_mac if router_mac != '' else self.dst_port_mac
self.src_port_id = int(self.test_params['src_port_id'])
self.src_port_ip = self.test_params['src_port_ip']
self.src_port_mac = self.dataplane.get_mac(0, self.src_port_id)
self.src_port_2_id = int(self.test_params['src_port_2_id'])
self.src_port_2_ip = self.test_params['src_port_2_ip']
self.src_port_2_mac = self.dataplane.get_mac(0, self.src_port_2_id)
self.asic_type = self.test_params['sonic_asic_type']
self.pkts_num_leak_out = int(self.test_params['pkts_num_leak_out'])
self.pkts_num_trig_egr_drp = int(self.test_params['pkts_num_trig_egr_drp'])
if 'packet_size' in self.test_params.keys():
self.packet_length = int(self.test_params['packet_size'])
cell_size = int(self.test_params['cell_size'])
if self.packet_length != 64:
cell_occupancy = (self.packet_length + cell_size - 1) // cell_size
self.pkts_num_trig_egr_drp //= cell_occupancy
else:
self.packet_length = 64
self.ttl = 64

def runTest(self):
print("dst_port_id: {}, src_port_id: {}, src_port_2_id: {}".format(self.dst_port_id,
self.src_port_id,
self.src_port_2_id),
file=sys.stderr)
# get counter names to query
ingress_counters, egress_counters = get_counter_names(self.sonic_version)

port_counter_indexes = [self.pg]
port_counter_indexes += ingress_counters
port_counter_indexes += egress_counters
port_counter_indexes += [TRANSMITTED_PKTS, RECEIVED_PKTS, RECEIVED_NON_UC_PKTS,
TRANSMITTED_NON_UC_PKTS, EGRESS_PORT_QLEN]

# construct packets
pkt = get_multiple_flows(
self,
self.dst_port_mac,
self.dst_port_id,
self.dst_port_ip,
None,
self.dscp,
self.ecn,
self.ttl,
self.packet_length,
[(self.src_port_id, self.src_port_ip)],
packets_per_port=1)[self.src_port_id][0][0]
pkt2 = get_multiple_flows(
self,
self.dst_port_mac,
self.dst_port_id,
self.dst_port_ip,
None,
self.dscp,
self.ecn,
self.ttl,
self.packet_length,
[(self.src_port_2_id, self.src_port_2_ip)],
packets_per_port=1)[self.src_port_2_id][0][0]

# add slight tolerance in threshold characterization to consider
# the case that npu puts packets in the egress queue after we pause the egress
# or the leak out is simply less than expected as we have occasionally observed
if 'pkts_num_margin' in self.test_params.keys():
margin = int(self.test_params['pkts_num_margin'])
else:
margin = 2

try:
# Test multi-flows
self.sai_thrift_port_tx_disable(self.dst_client, self.asic_type, [self.dst_port_id])
recv_counters_base, _ = sai_thrift_read_port_counters(self.src_client, self.asic_type,
port_list['src'][self.src_port_id])
recv_counters_2_base, _ = sai_thrift_read_port_counters(self.src_client, self.asic_type,
port_list['src'][self.src_port_2_id])
xmit_counters_base, _ = sai_thrift_read_port_counters(self.dst_client, self.asic_type,
port_list['dst'][self.dst_port_id])
fill_leakout_plus_one(self, self.src_port_id, self.dst_port_id, pkt,
int(self.test_params['pg']), self.asic_type)
multi_flow_drop_pkt_count = self.pkts_num_trig_egr_drp
# send packets short of triggering egress drop on both flows, uses the
# "multiple" packet count to cause a drop when 2 flows are present.
short_of_drop_npkts = self.pkts_num_leak_out + multi_flow_drop_pkt_count - 1 - margin
print("Sending {} packets on each of 2 streams to approach drop".format(short_of_drop_npkts),
file=sys.stderr)
send_packet(self, self.src_port_id, pkt, short_of_drop_npkts)
send_packet(self, self.src_port_2_id, pkt2, short_of_drop_npkts)
# allow enough time for counters to update
time.sleep(2)
recv_counters, _ = sai_thrift_read_port_counters(self.src_client, self.asic_type,
port_list['src'][self.src_port_id])
recv_counters_2, _ = sai_thrift_read_port_counters(self.src_client, self.asic_type,
port_list['src'][self.src_port_2_id])
xmit_counters, _ = sai_thrift_read_port_counters(self.dst_client, self.asic_type,
port_list['dst'][self.dst_port_id])

port_cnt_tbl = texttable.TextTable([''] + [port_counter_fields[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['recv_counters_base'] + [recv_counters_base[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['recv_counters'] + [recv_counters[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['recv_counters_2_base'] + [recv_counters_2_base[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['recv_counters_2'] + [recv_counters_2[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['xmit_counters_base'] + [xmit_counters_base[idx] for idx in port_counter_indexes])
port_cnt_tbl.add_row(['xmit_counters'] + [xmit_counters[idx] for idx in port_counter_indexes])
sys.stderr.write('{}\n'.format(port_cnt_tbl))

# recv port no pfc
diff = recv_counters[self.pg] - recv_counters_base[self.pg]
assert diff == 0, "Unexpected PFC frames {} on port {}".format(diff, self.src_port_id)
diff = recv_counters_2[self.pg] - recv_counters_2_base[self.pg]
assert diff == 0, "Unexpected PFC frames {} on port {}".format(diff, self.src_port_2_id)
# recv port no ingress drop
for cntr in ingress_counters:
diff = recv_counters[cntr] - recv_counters_base[cntr]
assert diff == 0, "Unexpected ingress drop {} on port {}".format(diff, self.src_port_id)
for cntr in ingress_counters:
diff = recv_counters_2[cntr] - recv_counters_2_base[cntr]
assert diff == 0, "Unexpected ingress drop {} on port {}".format(diff, self.src_port_2_id)
# xmit port no egress drop
for cntr in egress_counters:
diff = xmit_counters[cntr] - xmit_counters_base[cntr]
assert diff == 0, "Unexpected TX drop {} on port {}".format(diff, self.dst_port_id)

# send 1 packet to trigger egress drop
npkts = 1 + 2 * margin
print("Sending {} packets on 2 streams to trigger drop".format(npkts),
file=sys.stderr)
send_packet(self, self.src_port_id, pkt, npkts)
send_packet(self, self.src_port_2_id, pkt2, npkts)
# allow enough time for counters to update
time.sleep(2)
recv_counters, _ = sai_thrift_read_port_counters(self.src_client,
self.asic_type,
port_list['src'][self.src_port_id])
recv_counters_2, _ = sai_thrift_read_port_counters(self.src_client,
self.asic_type,
port_list['src'][self.src_port_2_id])
xmit_counters, _ = sai_thrift_read_port_counters(self.dst_client,
self.asic_type,
port_list['dst'][self.dst_port_id])
# recv port no pfc
diff = recv_counters[self.pg] - recv_counters_base[self.pg]
assert diff == 0, "Unexpected PFC frames {} on port {}".format(diff, self.src_port_id)
diff = recv_counters_2[self.pg] - recv_counters_2_base[self.pg]
assert diff == 0, "Unexpected PFC frames {} on port {}".format(diff, self.src_port_2_id)
# recv port no ingress drop
for cntr in ingress_counters:
diff = recv_counters[cntr] - recv_counters_base[cntr]
assert diff == 0, "Unexpected ingress drop {} on port {}".format(diff, self.src_port_id)
for cntr in ingress_counters:
diff = recv_counters_2[cntr] - recv_counters_2_base[cntr]
assert diff == 0, "Unexpected ingress drop {} on port {}".format(diff, self.src_port_2_id)
# xmit port egress drop
for cntr in egress_counters:
drops = xmit_counters[cntr] - xmit_counters_base[cntr]
assert drops > 0, "Failed to detect egress drops ({})".format(drops)
print("Successfully dropped {} packets".format(drops), file=sys.stderr)
finally:
self.sai_thrift_port_tx_enable(self.dst_client, self.asic_type, [self.dst_port_id])

0 comments on commit f0523e8

Please sign in to comment.