Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[T2] Add case to test lossy fair-voq #10838

Merged
merged 4 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,12 @@ qos/test_qos_sai.py::TestQosSai::testQosSaiLossyQueueVoq:
conditions:
- "asic_type not in ['cisco-8000']"

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 @@ -321,6 +321,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 @@ -2208,6 +2208,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 @@ -1201,7 +1201,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 @@ -2143,3 +2143,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 @@ -5421,3 +5421,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])
Loading