Skip to content

Commit 10557ec

Browse files
authored
[Mellanox] [QoS] Support shared headroom pool (#2565)
1 parent 26dab0a commit 10557ec

File tree

5 files changed

+156
-22
lines changed

5 files changed

+156
-22
lines changed

tests/qos/files/mellanox/qos_param_generator.py

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import math
22

33
class QosParamMellanox(object):
4-
def __init__(self, qos_params, asic_type, speed_cable_len, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile, egressLossyProfile):
4+
def __init__(self, qos_params, asic_type, speed_cable_len, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile, egressLossyProfile, sharedHeadroomPoolSize):
55
asic_param_dic = {
66
'spc1': {
77
'cell_size': 96,
@@ -36,6 +36,7 @@ def __init__(self, qos_params, asic_type, speed_cable_len, ingressLosslessProfil
3636
self.ingressLossyProfile = ingressLossyProfile
3737
self.egressLosslessProfile = egressLosslessProfile
3838
self.egressLossyProfile = egressLossyProfile
39+
self.sharedHeadroomPoolSize = sharedHeadroomPoolSize
3940

4041
return
4142

@@ -57,16 +58,46 @@ def collect_qos_configurations(self):
5758
xon = int(math.ceil(float(self.ingressLosslessProfile['xon']) / self.cell_size))
5859
xoff = int(math.ceil(float(self.ingressLosslessProfile['xoff']) / self.cell_size))
5960
size = int(math.ceil(float(self.ingressLosslessProfile['size']) / self.cell_size))
60-
headroom = size
61+
62+
if self.sharedHeadroomPoolSize:
63+
headroom = xon + xoff
64+
ingress_lossless_size = int(math.ceil(float(self.ingressLosslessProfile['static_th']) / self.cell_size)) - xon
65+
else:
66+
headroom = size
67+
ingress_lossless_size = int(math.ceil(float(self.ingressLosslessProfile['static_th']) / self.cell_size)) - headroom
6168
hysteresis = headroom - (xon + xoff)
62-
ingress_lossless_size = int(math.ceil(float(self.ingressLosslessProfile['static_th']) / self.cell_size)) - headroom
69+
6370
egress_lossy_size = int(math.ceil(float(self.egressLossyProfile['static_th']) / self.cell_size))
6471

6572
pkts_num_trig_pfc = ingress_lossless_size + xon + hysteresis
66-
pkts_num_trig_ingr_drp = ingress_lossless_size + headroom - self.headroom_overhead
73+
pkts_num_trig_ingr_drp = ingress_lossless_size + headroom
74+
if self.sharedHeadroomPoolSize:
75+
pkts_num_trig_ingr_drp += xoff
76+
else:
77+
pkts_num_trig_ingr_drp -= self.headroom_overhead
6778
pkts_num_dismiss_pfc = ingress_lossless_size + 1
6879
pkts_num_trig_egr_drp = egress_lossy_size + 1
6980

81+
if self.sharedHeadroomPoolSize:
82+
ingress_ports_num_shp = 8
83+
pkts_num_trig_pfc_shp = []
84+
ing_port = 1
85+
ingress_ports_list_shp = []
86+
occupancy_per_port = ingress_lossless_size
87+
for i in range(1, ingress_ports_num_shp):
88+
# for the first PG
89+
pkts_num_trig_pfc_shp.append(occupancy_per_port + xon + hysteresis)
90+
# for the second PG
91+
occupancy_per_port /= 2
92+
pkts_num_trig_pfc_shp.append(occupancy_per_port + xon + hysteresis)
93+
occupancy_per_port /= 2
94+
ingress_ports_list_shp.append(ing_port)
95+
ing_port += 1
96+
self.qos_parameters['pkts_num_trig_pfc_shp'] = pkts_num_trig_pfc_shp
97+
self.qos_parameters['src_port_ids'] = ingress_ports_list_shp
98+
self.qos_parameters['pkts_num_hdrm_full'] = xoff - 2
99+
self.qos_parameters['pkts_num_hdrm_partial'] = xoff - 2
100+
70101
self.qos_parameters['pkts_num_trig_pfc'] = pkts_num_trig_pfc
71102
self.qos_parameters['pkts_num_trig_ingr_drp'] = pkts_num_trig_ingr_drp
72103
self.qos_parameters['pkts_num_dismiss_pfc'] = pkts_num_dismiss_pfc
@@ -93,6 +124,18 @@ def calculate_parameters(self):
93124
pkts_num_trig_egr_drp = self.qos_parameters['pkts_num_trig_egr_drp']
94125
pkts_num_hysteresis = self.qos_parameters['pkts_num_hysteresis']
95126

127+
if self.sharedHeadroomPoolSize:
128+
hdrm_pool_size = self.qos_params_mlnx[self.speed_cable_len]['hdrm_pool_size']
129+
hdrm_pool_size['pkts_num_trig_pfc_shp'] = self.qos_parameters['pkts_num_trig_pfc_shp']
130+
hdrm_pool_size['pkts_num_hdrm_full'] = self.qos_parameters['pkts_num_hdrm_full']
131+
hdrm_pool_size['pkts_num_hdrm_partial'] = self.qos_parameters['pkts_num_hdrm_partial']
132+
hdrm_pool_size['src_port_ids'] = self.qos_parameters['src_port_ids']
133+
hdrm_pool_size['pgs_num'] = 2 * len(self.qos_parameters['src_port_ids'])
134+
hdrm_pool_size['cell_size'] = self.cell_size
135+
hdrm_pool_size['margin'] = 3
136+
else:
137+
self.qos_params_mlnx[self.speed_cable_len].pop('hdrm_pool_size')
138+
96139
xoff = {}
97140
xoff['pkts_num_trig_pfc'] = pkts_num_trig_pfc
98141
xoff['pkts_num_trig_ingr_drp'] = pkts_num_trig_ingr_drp
@@ -152,3 +195,5 @@ def calculate_parameters(self):
152195

153196
for i in range(4):
154197
self.qos_params_mlnx['ecn_{}'.format(i+1)]['cell_size'] = self.cell_size
198+
199+
self.qos_params_mlnx['shared-headroom-pool'] = self.sharedHeadroomPoolSize

tests/qos/files/qos.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ qos_params:
4040
pkts_num_leak_out: 0
4141
pkts_num_fill_min: 0
4242
packet_size: 300
43+
hdrm_pool_size:
44+
dscps: [3, 4]
45+
ecn: 1
46+
pgs: [3, 4]
47+
dst_port_id: 0
48+
pkts_num_trig_pfc: 0
49+
pkts_num_leak_out: 0
50+
pkts_num_fill_min: 0
51+
packet_size: 300
4352
xon_1:
4453
dscp: 3
4554
ecn: 1

tests/qos/qos_sai_base.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,26 @@ def __getBufferProfile(self, request, duthost, table, port, priorityGroup):
148148

149149
return bufferProfile
150150

151+
def __getSharedHeadroomPoolSize(self, request, duthost):
152+
"""
153+
Get shared headroom pool size from Redis db
154+
155+
Args:
156+
request (Fixture): pytest request object
157+
duthost (AnsibleHost): Device Under Test (DUT)
158+
159+
Returns:
160+
size (str) size of shared headroom pool
161+
None if shared headroom pool isn't enabled
162+
"""
163+
result = self.__runRedisCommandOrAssert(
164+
duthost,
165+
argv = ["redis-cli", "-n", "4", "HGETALL", "BUFFER_POOL|ingress_lossless_pool"]
166+
)
167+
it = iter(result)
168+
ingressLosslessPool = dict(zip(it, it))
169+
return ingressLosslessPool.get("xoff")
170+
151171
def __getEcnWredParam(self, duthost, table, port):
152172
"""
153173
Get ECN/WRED parameters from Redis db
@@ -543,7 +563,7 @@ def disablePacketAging(self, duthosts, rand_one_dut_hostname, stopServices):
543563
duthost.command("docker exec syncd rm -rf /packets_aging.py")
544564

545565
@pytest.fixture(scope='class', autouse=True)
546-
def dutQosConfig(self, duthosts, rand_one_dut_hostname, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile, egressLossyProfile, tbinfo):
566+
def dutQosConfig(self, duthosts, rand_one_dut_hostname, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile, egressLossyProfile, sharedHeadroomPoolSize, tbinfo):
547567
"""
548568
Prepares DUT host QoS configuration
549569
@@ -591,11 +611,13 @@ def dutQosConfig(self, duthosts, rand_one_dut_hostname, ingressLosslessProfile,
591611
sys.path.append(sub_folder_dir)
592612
import qos_param_generator
593613
qpm = qos_param_generator.QosParamMellanox(qosConfigs['qos_params']['mellanox'], dutAsic,
594-
portSpeedCableLength,
595-
ingressLosslessProfile,
596-
ingressLossyProfile,
597-
egressLosslessProfile,
598-
egressLossyProfile)
614+
portSpeedCableLength,
615+
ingressLosslessProfile,
616+
ingressLossyProfile,
617+
egressLosslessProfile,
618+
egressLossyProfile,
619+
sharedHeadroomPoolSize
620+
)
599621
qosParams = qpm.run()
600622
else:
601623
qosParams = qosConfigs['qos_params'][dutAsic]
@@ -687,6 +709,25 @@ def populateArpEntries(self, duthosts, rand_one_dut_hostname, ptfhost, dutTestPa
687709
testParams.update(dutConfig["testPorts"])
688710
self.runPtfTest(ptfhost, testCase=saiQosTest, testParams=testParams)
689711

712+
@pytest.fixture(scope='class', autouse=True)
713+
def sharedHeadroomPoolSize(self, request, duthosts, rand_one_dut_hostname):
714+
"""
715+
Retreives shared headroom pool size
716+
717+
Args:
718+
request (Fixture): pytest request object
719+
duthost (AnsibleHost): Device Under Test (DUT)
720+
721+
Returns:
722+
size: shared headroom pool size
723+
none if it is not defined
724+
"""
725+
duthost = duthosts[rand_one_dut_hostname]
726+
yield self.__getSharedHeadroomPoolSize(
727+
request,
728+
duthost
729+
)
730+
690731
@pytest.fixture(scope='class', autouse=True)
691732
def ingressLosslessProfile(self, request, duthosts, rand_one_dut_hostname, dutConfig):
692733
"""

tests/qos/test_qos_sai.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ class TestQosSai(QosSaiBase):
5454
'Arista-7260CX3-Q64'
5555
]
5656

57-
def testParameter(self, duthost, dutQosConfig, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile):
57+
def testParameter(self, duthost, dutConfig, dutQosConfig, ingressLosslessProfile, ingressLossyProfile, egressLosslessProfile):
5858
logger.info("asictype {}".format(duthost.facts["asic_type"]))
59+
logger.info("config {}".format(dutConfig))
5960
logger.info("qosConfig {}".format(dutQosConfig))
6061

6162
@pytest.mark.parametrize("xoffProfile", ["xoff_1", "xoff_2"])
@@ -168,13 +169,16 @@ def testQosSaiHeadroomPoolSize(self, ptfhost, dutTestParams, dutConfig, dutQosCo
168169
Raises:
169170
RunAnsibleModuleFail if ptf test fails
170171
"""
171-
if dutTestParams["hwsku"] not in self.SUPPORTED_HEADROOM_SKUS:
172+
if dutTestParams["hwsku"] not in self.SUPPORTED_HEADROOM_SKUS and dutTestParams["basicParams"]["sonic_asic_type"] != "mellanox":
172173
pytest.skip("Headroom pool size not supported")
173174

174175
portSpeedCableLength = dutQosConfig["portSpeedCableLength"]
175176
qosConfig = dutQosConfig["param"][portSpeedCableLength]
176177
testPortIps = dutConfig["testPortIps"]
177178

179+
if not 'hdrm_pool_size' in qosConfig.keys():
180+
pytest.skip("Headroom pool size is not enabled on this DUT")
181+
178182
testParams = dict()
179183
testParams.update(dutTestParams["basicParams"])
180184
testParams.update({
@@ -187,11 +191,25 @@ def testQosSaiHeadroomPoolSize(self, ptfhost, dutTestParams, dutConfig, dutQosCo
187191
"dst_port_id": qosConfig["hdrm_pool_size"]["dst_port_id"],
188192
"dst_port_ip": testPortIps[qosConfig["hdrm_pool_size"]["dst_port_id"]],
189193
"pgs_num": qosConfig["hdrm_pool_size"]["pgs_num"],
190-
"pkts_num_leak_out": qosConfig["pkts_num_leak_out"],
191194
"pkts_num_trig_pfc": qosConfig["hdrm_pool_size"]["pkts_num_trig_pfc"],
195+
"pkts_num_leak_out": qosConfig["pkts_num_leak_out"],
192196
"pkts_num_hdrm_full": qosConfig["hdrm_pool_size"]["pkts_num_hdrm_full"],
193197
"pkts_num_hdrm_partial": qosConfig["hdrm_pool_size"]["pkts_num_hdrm_partial"],
194198
})
199+
200+
pkts_num_trig_pfc_shp = qosConfig["hdrm_pool_size"].get("pkts_num_trig_pfc_shp")
201+
if pkts_num_trig_pfc_shp:
202+
testParams["pkts_num_trig_pfc_shp"] = pkts_num_trig_pfc_shp
203+
204+
packet_size = qosConfig["hdrm_pool_size"].get("packet_size")
205+
if packet_size:
206+
testParams["packet_size"] = packet_size
207+
testParams["cell_size"] = qosConfig["hdrm_pool_size"]["cell_size"]
208+
209+
margin = qosConfig["hdrm_pool_size"].get("margin")
210+
if margin:
211+
testParams["margin"] = margin
212+
195213
self.runPtfTest(ptfhost, testCase="sai_qos_tests.HdrmPoolSizeTest", testParams=testParams)
196214

197215
@pytest.mark.parametrize("bufPool", ["wm_buf_pool_lossless", "wm_buf_pool_lossy"])

tests/saitests/sai_qos_tests.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import sai_base_test
1111
import operator
1212
import sys
13+
import math
1314
from ptf.testutils import (ptf_ports,
1415
simple_arp_packet,
1516
send_packet,
@@ -857,10 +858,24 @@ def setUp(self):
857858
self.pgs_num = self.test_params['pgs_num']
858859
self.asic_type = self.test_params['sonic_asic_type']
859860
self.pkts_num_leak_out = self.test_params['pkts_num_leak_out']
860-
self.pkts_num_trig_pfc = self.test_params['pkts_num_trig_pfc']
861+
self.pkts_num_trig_pfc = self.test_params.get('pkts_num_trig_pfc')
862+
if not self.pkts_num_trig_pfc:
863+
self.pkts_num_trig_pfc_shp = self.test_params.get('pkts_num_trig_pfc_shp')
861864
self.pkts_num_hdrm_full = self.test_params['pkts_num_hdrm_full']
862865
self.pkts_num_hdrm_partial = self.test_params['pkts_num_hdrm_partial']
863-
print >> sys.stderr, ("pkts num: leak_out: %d, trig_pfc: %d, hdrm_full: %d, hdrm_partial: %d" % (self.pkts_num_leak_out, self.pkts_num_trig_pfc, self.pkts_num_hdrm_full, self.pkts_num_hdrm_partial))
866+
packet_size = self.test_params.get('packet_size')
867+
if packet_size:
868+
self.pkt_size = packet_size
869+
cell_size = self.test_params.get('cell_size')
870+
self.pkt_size_factor = int(math.ceil(float(packet_size)/cell_size))
871+
else:
872+
self.pkt_size = 64
873+
self.pkt_size_factor = 1
874+
875+
if self.pkts_num_trig_pfc:
876+
print >> sys.stderr, ("pkts num: leak_out: %d, trig_pfc: %d, hdrm_full: %d, hdrm_partial: %d, pkt_size %d" % (self.pkts_num_leak_out, self.pkts_num_trig_pfc, self.pkts_num_hdrm_full, self.pkts_num_hdrm_partial, self.pkt_size))
877+
elif self.pkts_num_trig_pfc_shp:
878+
print >> sys.stderr, ("pkts num: leak_out: {}, trig_pfc: {}, hdrm_full: {}, hdrm_partial: {}, pkt_size {}".format(self.pkts_num_leak_out, self.pkts_num_trig_pfc_shp, self.pkts_num_hdrm_full, self.pkts_num_hdrm_partial, self.pkt_size))
864879
sys.stderr.flush()
865880

866881
self.dst_port_mac = self.dataplane.get_mac(0, self.dst_port_id)
@@ -894,7 +909,9 @@ def tearDown(self):
894909
sai_base_test.ThriftInterfaceDataPlane.tearDown(self)
895910

896911
def runTest(self):
897-
margin = 0
912+
margin = self.test_params.get('margin')
913+
if not margin:
914+
margin = 0
898915
sidx_dscp_pg_tuples = [(sidx, dscp, self.pgs[pgidx]) for sidx, sid in enumerate(self.src_port_ids) for pgidx, dscp in enumerate(self.dscps)]
899916
assert(len(sidx_dscp_pg_tuples) >= self.pgs_num)
900917
print >> sys.stderr, sidx_dscp_pg_tuples
@@ -911,7 +928,7 @@ def runTest(self):
911928
try:
912929
# send packets to leak out
913930
sidx = 0
914-
pkt = simple_tcp_packet(pktlen=64,
931+
pkt = simple_tcp_packet(pktlen=self.pkt_size,
915932
eth_dst=self.router_mac if self.router_mac != '' else self.dst_port_mac,
916933
eth_src=self.src_port_macs[sidx],
917934
ip_src=self.src_port_ips[sidx],
@@ -926,15 +943,19 @@ def runTest(self):
926943
tos = sidx_dscp_pg_tuples[i][1] << 2
927944
tos |= self.ecn
928945
ttl = 64
929-
default_packet_length = 64
946+
default_packet_length = self.pkt_size
930947
pkt = simple_tcp_packet(pktlen=default_packet_length,
931948
eth_dst=self.router_mac if self.router_mac != '' else self.dst_port_mac,
932949
eth_src=self.src_port_macs[sidx_dscp_pg_tuples[i][0]],
933950
ip_src=self.src_port_ips[sidx_dscp_pg_tuples[i][0]],
934951
ip_dst=self.dst_port_ip,
935952
ip_tos=tos,
936953
ip_ttl=ttl)
937-
send_packet(self, self.src_port_ids[sidx_dscp_pg_tuples[i][0]], pkt, self.pkts_num_trig_pfc)
954+
if self.pkts_num_trig_pfc:
955+
pkts_num_trig_pfc = self.pkts_num_trig_pfc
956+
else:
957+
pkts_num_trig_pfc = self.pkts_num_trig_pfc_shp[i]
958+
send_packet(self, self.src_port_ids[sidx_dscp_pg_tuples[i][0]], pkt, pkts_num_trig_pfc / self.pkt_size_factor)
938959

939960
print >> sys.stderr, "Service pool almost filled"
940961
sys.stderr.flush()
@@ -946,7 +967,7 @@ def runTest(self):
946967
tos = sidx_dscp_pg_tuples[i][1] << 2
947968
tos |= self.ecn
948969
ttl = 64
949-
default_packet_length = 64
970+
default_packet_length = self.pkt_size
950971
pkt = simple_tcp_packet(pktlen=default_packet_length,
951972
eth_dst=self.router_mac if self.router_mac != '' else self.dst_port_mac,
952973
eth_src=self.src_port_macs[sidx_dscp_pg_tuples[i][0]],
@@ -982,7 +1003,7 @@ def runTest(self):
9821003
tos = sidx_dscp_pg_tuples[i][1] << 2
9831004
tos |= self.ecn
9841005
ttl = 64
985-
default_packet_length = 64
1006+
default_packet_length = self.pkt_size
9861007
pkt = simple_tcp_packet(pktlen=default_packet_length,
9871008
eth_dst=self.router_mac if self.router_mac != '' else self.dst_port_mac,
9881009
eth_src=self.src_port_macs[sidx_dscp_pg_tuples[i][0]],
@@ -991,7 +1012,7 @@ def runTest(self):
9911012
ip_tos=tos,
9921013
ip_ttl=ttl)
9931014

994-
send_packet(self, self.src_port_ids[sidx_dscp_pg_tuples[i][0]], pkt, self.pkts_num_hdrm_full if i != self.pgs_num - 1 else self.pkts_num_hdrm_partial)
1015+
send_packet(self, self.src_port_ids[sidx_dscp_pg_tuples[i][0]], pkt, self.pkts_num_hdrm_full / self.pkt_size_factor if i != self.pgs_num - 1 else self.pkts_num_hdrm_partial / self.pkt_size_factor)
9951016
# allow enough time for the dut to sync up the counter values in counters_db
9961017
time.sleep(8)
9971018

0 commit comments

Comments
 (0)