Skip to content
Merged
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
146 changes: 142 additions & 4 deletions orchagent/port_rates.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ end
local counters_db = ARGV[1]
local counters_table_name = ARGV[2]
local rates_table_name = "RATES"
local appl_db_port = "PORT_TABLE"
-- refer back to common/schema.h
local appl_db = "0"

-- Get configuration
redis.call('SELECT', counters_db)
Expand All @@ -29,11 +32,117 @@ logit(alpha)
logit(one_minus_alpha)
logit(delta)

local port_interface_oid_map = redis.call('HGETALL', "COUNTERS_PORT_NAME_MAP")
local port_interface_oid_key_count = redis.call('HLEN', "COUNTERS_PORT_NAME_MAP")

-- lookup interface name from port oid

local function find_interface_name_from_oid(port)

for i = 1, port_interface_oid_key_count do
local index = i * 2 - 1
if port_interface_oid_map[index + 1] == port then
return port_interface_oid_map[index]
end
end

return 0
end

-- calculate lanes and serdes speed from interface lane count & speed
-- return lane speed and serdes speed

local function calculate_lane_and_serdes_speed(count, speed)

local serdes = 0
local lane_speed = 0

if count == 0 or speed == 0 then
logit("Invalid number of lanes or speed")
return 0, 0
end

-- check serdes_cnt if it is a multiple of speed
local serdes_cnt = math.fmod(speed, count)

if serdes_cnt ~= 0 then
logit("Invalid speed and number of lanes combination")
return 0, 0
end

lane_speed = math.floor(speed / count)

-- return value in bits
if lane_speed == 1000 then
serdes = 1.25e+9
elseif lane_speed == 10000 then
serdes = 10.3125e+9
elseif lane_speed == 25000 then
serdes = 25.78125e+9
elseif lane_speed == 50000 then
serdes = 53.125e+9
elseif lane_speed == 100000 then
serdes = 106.25e+9
else
logit("Invalid serdes speed")
end

return lane_speed, serdes
end

-- look up interface lanes count, lanes speed & serdes speed
-- return lane count, lane speed, serdes speed

local function find_lanes_and_serdes(interface_name)
-- get the port config from config db
local _
local serdes, lane_speed, count = 0, 0, 0

-- Get the port configure
redis.call('SELECT', appl_db)
local lanes = redis.call('HGET', appl_db_port ..':'..interface_name, 'lanes')

if lanes then
local speed = redis.call('HGET', appl_db_port ..':'..interface_name, 'speed')

-- we were spliting it on ','
_, count = string.gsub(lanes, ",", ",")
count = count + 1

lane_speed, serdes = calculate_lane_and_serdes_speed(count, speed)

end
-- switch back to counter db
redis.call('SELECT', counters_db)

return count, lane_speed, serdes
end

local function compute_rate(port)

local state_table = rates_table_name .. ':' .. port .. ':' .. 'PORT'
local initialized = redis.call('HGET', state_table, 'INIT_DONE')
logit(initialized)

-- FEC BER
local fec_corr_bits, fec_uncorr_frames
local fec_corr_bits_ber_new, fec_uncorr_bits_ber_new = -1, -1
-- HLD review suggest to use the statistical average when calculate the post fec ber
local rs_average_frame_ber = 1e-8
local lanes_speed, serdes_speed, lanes_count = 0, 0, 0

-- lookup interface name from oid
local interface_name = find_interface_name_from_oid(port)
if interface_name then
lanes_count, lanes_speed, serdes_speed = find_lanes_and_serdes(interface_name)

if lanes_count and serdes_speed then
fec_corr_bits = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_FEC_CORRECTED_BITS')
fec_uncorr_frames = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES')
end
end


-- Get new COUNTERS values
local in_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_UCAST_PKTS')
local in_non_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS')
Expand All @@ -58,10 +167,11 @@ local function compute_rate(port)
local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_OCTETS_last')

-- Calculate new rates values
local rx_bps_new = (in_octets - in_octets_last) / delta * 1000
local tx_bps_new = (out_octets - out_octets_last) / delta * 1000
local rx_pps_new = ((in_ucast_pkts + in_non_ucast_pkts) - (in_ucast_pkts_last + in_non_ucast_pkts_last)) / delta * 1000
local tx_pps_new = ((out_ucast_pkts + out_non_ucast_pkts) - (out_ucast_pkts_last + out_non_ucast_pkts_last)) / delta * 1000
local scale_factor = 1000 / delta
local rx_bps_new = (in_octets - in_octets_last) * scale_factor
local tx_bps_new = (out_octets - out_octets_last) * scale_factor
local rx_pps_new = ((in_ucast_pkts + in_non_ucast_pkts) - (in_ucast_pkts_last + in_non_ucast_pkts_last)) * scale_factor
local tx_pps_new = ((out_ucast_pkts + out_non_ucast_pkts) - (out_ucast_pkts_last + out_non_ucast_pkts_last)) * scale_factor

if initialized == "DONE" then
-- Get old rates values
Expand All @@ -83,6 +193,21 @@ local function compute_rate(port)
redis.call('HSET', rates_table_name .. ':' .. port, 'TX_PPS', tx_pps_new)
redis.call('HSET', state_table, 'INIT_DONE', 'DONE')
end

-- only do the calculation when all info present

if fec_corr_bits and fec_uncorr_frames and lanes_count and serdes_speed then
local fec_corr_bits_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_CORRECTED_BITS_last')
local fec_uncorr_frames_last = redis.call('HGET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_NOT_CORRECTABLE_FARMES_last')

local serdes_rate_total = lanes_count * serdes_speed * delta / 1000

fec_corr_bits_ber_new = (fec_corr_bits - fec_corr_bits_last) / serdes_rate_total
fec_uncorr_bits_ber_new = (fec_uncorr_frames - fec_uncorr_frames_last) * rs_average_frame_ber / serdes_rate_total
else
logit("FEC counters or lane info not found on " .. port)
end

else
redis.call('HSET', state_table, 'INIT_DONE', 'COUNTERS_LAST')
end
Expand All @@ -94,6 +219,19 @@ local function compute_rate(port)
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS_last', out_non_ucast_pkts)
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_IN_OCTETS_last', in_octets)
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_OUT_OCTETS_last', out_octets)

-- do not update FEC related stat if we dont have it

if not fec_corr_bits or not fec_uncorr_frames or not fec_corr_bits_ber_new or
not fec_uncorr_bits_ber_new then
logit("FEC counters not found on " .. port)
return
end
-- Set BER values
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_CORRECTED_BITS_last', fec_corr_bits)
redis.call('HSET', rates_table_name .. ':' .. port, 'SAI_PORT_STAT_IF_FEC_NOT_CORRECTABLE_FARMES_last', fec_uncorr_frames)
redis.call('HSET', rates_table_name .. ':' .. port, 'FEC_PRE_BER', fec_corr_bits_ber_new)
redis.call('HSET', rates_table_name .. ':' .. port, 'FEC_POST_BER', fec_uncorr_bits_ber_new)
end

local n = table.getn(KEYS)
Expand Down