Skip to content

Commit cad0236

Browse files
vincentpcngdivyachandralekha
authored andcommitted
Add port FEC BER feature swss, HLD#1829 (sonic-net#3363)
What I did This is to add the swss changes for the feature port FEC BER. It modify the port_rates.lua script to compute the BER and stored them in the DB . Two additonal PR(s) will address the cli ( sonic-utilities) and the sonic-mgmt changes Why I did it The HLD for this feature is HLD#1829 How I verified it We verify the counters internally (1) verify when link has correctable FEC errors, the BER were calcuated accordingly (2) verify 400G with 4x100 and the BER , four serdes with 100G rate (3) run a redis-script to polling the DB counters and verify the calculation (4) stop polling manually modify the uncorrectable counter and verify the cli display and calculation
1 parent 1d8d1d7 commit cad0236

1 file changed

Lines changed: 142 additions & 4 deletions

File tree

orchagent/port_rates.lua

Lines changed: 142 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ end
1313
local counters_db = ARGV[1]
1414
local counters_table_name = ARGV[2]
1515
local rates_table_name = "RATES"
16+
local appl_db_port = "PORT_TABLE"
17+
-- refer back to common/schema.h
18+
local appl_db = "0"
1619

1720
-- Get configuration
1821
redis.call('SELECT', counters_db)
@@ -29,11 +32,117 @@ logit(alpha)
2932
logit(one_minus_alpha)
3033
logit(delta)
3134

35+
local port_interface_oid_map = redis.call('HGETALL', "COUNTERS_PORT_NAME_MAP")
36+
local port_interface_oid_key_count = redis.call('HLEN', "COUNTERS_PORT_NAME_MAP")
37+
38+
-- lookup interface name from port oid
39+
40+
local function find_interface_name_from_oid(port)
41+
42+
for i = 1, port_interface_oid_key_count do
43+
local index = i * 2 - 1
44+
if port_interface_oid_map[index + 1] == port then
45+
return port_interface_oid_map[index]
46+
end
47+
end
48+
49+
return 0
50+
end
51+
52+
-- calculate lanes and serdes speed from interface lane count & speed
53+
-- return lane speed and serdes speed
54+
55+
local function calculate_lane_and_serdes_speed(count, speed)
56+
57+
local serdes = 0
58+
local lane_speed = 0
59+
60+
if count == 0 or speed == 0 then
61+
logit("Invalid number of lanes or speed")
62+
return 0, 0
63+
end
64+
65+
-- check serdes_cnt if it is a multiple of speed
66+
local serdes_cnt = math.fmod(speed, count)
67+
68+
if serdes_cnt ~= 0 then
69+
logit("Invalid speed and number of lanes combination")
70+
return 0, 0
71+
end
72+
73+
lane_speed = math.floor(speed / count)
74+
75+
-- return value in bits
76+
if lane_speed == 1000 then
77+
serdes = 1.25e+9
78+
elseif lane_speed == 10000 then
79+
serdes = 10.3125e+9
80+
elseif lane_speed == 25000 then
81+
serdes = 25.78125e+9
82+
elseif lane_speed == 50000 then
83+
serdes = 53.125e+9
84+
elseif lane_speed == 100000 then
85+
serdes = 106.25e+9
86+
else
87+
logit("Invalid serdes speed")
88+
end
89+
90+
return lane_speed, serdes
91+
end
92+
93+
-- look up interface lanes count, lanes speed & serdes speed
94+
-- return lane count, lane speed, serdes speed
95+
96+
local function find_lanes_and_serdes(interface_name)
97+
-- get the port config from config db
98+
local _
99+
local serdes, lane_speed, count = 0, 0, 0
100+
101+
-- Get the port configure
102+
redis.call('SELECT', appl_db)
103+
local lanes = redis.call('HGET', appl_db_port ..':'..interface_name, 'lanes')
104+
105+
if lanes then
106+
local speed = redis.call('HGET', appl_db_port ..':'..interface_name, 'speed')
107+
108+
-- we were spliting it on ','
109+
_, count = string.gsub(lanes, ",", ",")
110+
count = count + 1
111+
112+
lane_speed, serdes = calculate_lane_and_serdes_speed(count, speed)
113+
114+
end
115+
-- switch back to counter db
116+
redis.call('SELECT', counters_db)
117+
118+
return count, lane_speed, serdes
119+
end
120+
32121
local function compute_rate(port)
122+
33123
local state_table = rates_table_name .. ':' .. port .. ':' .. 'PORT'
34124
local initialized = redis.call('HGET', state_table, 'INIT_DONE')
35125
logit(initialized)
36126

127+
-- FEC BER
128+
local fec_corr_bits, fec_uncorr_frames
129+
local fec_corr_bits_ber_new, fec_uncorr_bits_ber_new = -1, -1
130+
-- HLD review suggest to use the statistical average when calculate the post fec ber
131+
local rs_average_frame_ber = 1e-8
132+
local lanes_speed, serdes_speed, lanes_count = 0, 0, 0
133+
134+
-- lookup interface name from oid
135+
local interface_name = find_interface_name_from_oid(port)
136+
if interface_name then
137+
lanes_count, lanes_speed, serdes_speed = find_lanes_and_serdes(interface_name)
138+
139+
if lanes_count and serdes_speed then
140+
fec_corr_bits = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_FEC_CORRECTED_BITS')
141+
fec_uncorr_frames = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES')
142+
end
143+
end
144+
145+
37146
-- Get new COUNTERS values
38147
local in_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_UCAST_PKTS')
39148
local in_non_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS')
@@ -58,10 +167,11 @@ local function compute_rate(port)
58167
local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_OCTETS_last')
59168

60169
-- Calculate new rates values
61-
local rx_bps_new = (in_octets - in_octets_last) / delta * 1000
62-
local tx_bps_new = (out_octets - out_octets_last) / delta * 1000
63-
local rx_pps_new = ((in_ucast_pkts + in_non_ucast_pkts) - (in_ucast_pkts_last + in_non_ucast_pkts_last)) / delta * 1000
64-
local tx_pps_new = ((out_ucast_pkts + out_non_ucast_pkts) - (out_ucast_pkts_last + out_non_ucast_pkts_last)) / delta * 1000
170+
local scale_factor = 1000 / delta
171+
local rx_bps_new = (in_octets - in_octets_last) * scale_factor
172+
local tx_bps_new = (out_octets - out_octets_last) * scale_factor
173+
local rx_pps_new = ((in_ucast_pkts + in_non_ucast_pkts) - (in_ucast_pkts_last + in_non_ucast_pkts_last)) * scale_factor
174+
local tx_pps_new = ((out_ucast_pkts + out_non_ucast_pkts) - (out_ucast_pkts_last + out_non_ucast_pkts_last)) * scale_factor
65175

66176
if initialized == "DONE" then
67177
-- Get old rates values
@@ -83,6 +193,21 @@ local function compute_rate(port)
83193
redis.call('HSET', rates_table_name .. ':' .. port, 'TX_PPS', tx_pps_new)
84194
redis.call('HSET', state_table, 'INIT_DONE', 'DONE')
85195
end
196+
197+
-- only do the calculation when all info present
198+
199+
if fec_corr_bits and fec_uncorr_frames and lanes_count and serdes_speed then
200+
local fec_corr_bits_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_CORRECTED_BITS_last')
201+
local fec_uncorr_frames_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_NOT_CORRECTABLE_FARMES_last')
202+
203+
local serdes_rate_total = lanes_count * serdes_speed * delta / 1000
204+
205+
fec_corr_bits_ber_new = (fec_corr_bits - fec_corr_bits_last) / serdes_rate_total
206+
fec_uncorr_bits_ber_new = (fec_uncorr_frames - fec_uncorr_frames_last) * rs_average_frame_ber / serdes_rate_total
207+
else
208+
logit("FEC counters or lane info not found on " .. port)
209+
end
210+
86211
else
87212
redis.call('HSET', state_table, 'INIT_DONE', 'COUNTERS_LAST')
88213
end
@@ -94,6 +219,19 @@ local function compute_rate(port)
94219
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS_last', out_non_ucast_pkts)
95220
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_OCTETS_last', in_octets)
96221
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_OCTETS_last', out_octets)
222+
223+
-- do not update FEC related stat if we dont have it
224+
225+
if not fec_corr_bits or not fec_uncorr_frames or not fec_corr_bits_ber_new or
226+
not fec_uncorr_bits_ber_new then
227+
logit("FEC counters not found on " .. port)
228+
return
229+
end
230+
-- Set BER values
231+
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_CORRECTED_BITS_last', fec_corr_bits)
232+
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_NOT_CORRECTABLE_FARMES_last', fec_uncorr_frames)
233+
redis.call('HSET', rates_table_name .. ':' .. port, 'FEC_PRE_BER', fec_corr_bits_ber_new)
234+
redis.call('HSET', rates_table_name .. ':' .. port, 'FEC_POST_BER', fec_uncorr_bits_ber_new)
97235
end
98236

99237
local n = table.getn(KEYS)

0 commit comments

Comments
 (0)