diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index e4a988b65d4a..ac8db06be3be 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -5,12 +5,14 @@ CFLAGS_SAI = -I /usr/include/sai swssdir = $(datadir)/swss dist_swss_DATA = \ + rif_rates.lua \ pfc_detect_innovium.lua \ pfc_detect_mellanox.lua \ pfc_detect_broadcom.lua \ pfc_detect_barefoot.lua \ pfc_detect_nephos.lua \ pfc_restore.lua \ + port_rates.lua \ watermark_queue.lua \ watermark_pg.lua \ watermark_bufferpool.lua diff --git a/orchagent/flexcounterorch.cpp b/orchagent/flexcounterorch.cpp index 571b69c50fd8..ac5d5749e31c 100644 --- a/orchagent/flexcounterorch.cpp +++ b/orchagent/flexcounterorch.cpp @@ -21,12 +21,14 @@ extern BufferOrch *gBufferOrch; unordered_map flexCounterGroupMap = { {"PORT", PORT_STAT_COUNTER_FLEX_COUNTER_GROUP}, + {"PORT_RATES", PORT_RATE_COUNTER_FLEX_COUNTER_GROUP}, {"QUEUE", QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP}, {"PFCWD", PFC_WD_FLEX_COUNTER_GROUP}, {"QUEUE_WATERMARK", QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP}, {"PG_WATERMARK", PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP}, {BUFFER_POOL_WATERMARK_KEY, BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP}, {"RIF", RIF_STAT_COUNTER_FLEX_COUNTER_GROUP}, + {"RIF_RATES", RIF_RATE_COUNTER_FLEX_COUNTER_GROUP}, {"DEBUG_COUNTER", DEBUG_COUNTER_FLEX_COUNTER_GROUP}, }; diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index 309387a49778..ecd76d2bac2f 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -78,6 +78,24 @@ IntfsOrch::IntfsOrch(DBConnector *db, string tableName, VRFOrch *vrf_orch) : fieldValues.emplace_back(POLL_INTERVAL_FIELD, RIF_FLEX_STAT_COUNTER_POLL_MSECS); fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); m_flexCounterGroupTable->set(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + + string rifRatePluginName = "rif_rates.lua"; + + try + { + string rifRateLuaScript = swss::loadLuaScript(rifRatePluginName); + string rifRateSha = swss::loadRedisScript(m_counter_db.get(), rifRateLuaScript); + + vector fieldValues; + fieldValues.emplace_back(RIF_PLUGIN_FIELD, rifRateSha); + fieldValues.emplace_back(POLL_INTERVAL_FIELD, RIF_FLEX_STAT_COUNTER_POLL_MSECS); + fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); + m_flexCounterGroupTable->set(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + } + catch (const runtime_error &e) + { + SWSS_LOG_WARN("RIF flex counter group plugins was not set successfully: %s", e.what()); + } } sai_object_id_t IntfsOrch::getRouterIntfsId(const string &alias) @@ -1140,7 +1158,6 @@ void IntfsOrch::addRifToFlexCounter(const string &id, const string &name, const /* update RIF in FLEX_COUNTER_DB */ string key = getRifFlexCounterTableKey(id); - std::ostringstream counters_stream; for (const auto& it: rifStatIds) { @@ -1150,7 +1167,6 @@ void IntfsOrch::addRifToFlexCounter(const string &id, const string &name, const /* check the state of intf, if registering the intf to FC will result in runtime error */ vector fieldValues; fieldValues.emplace_back(RIF_COUNTER_ID_LIST, counters_stream.str()); - m_flexCounterTable->set(key, fieldValues); SWSS_LOG_DEBUG("Registered interface %s to Flex counter", name.c_str()); } diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index ee1f1540ff12..9db1a3b228f5 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -17,6 +17,7 @@ extern sai_object_id_t gVirtualRouterId; extern MacAddress gMacAddress; #define RIF_STAT_COUNTER_FLEX_COUNTER_GROUP "RIF_STAT_COUNTER" +#define RIF_RATE_COUNTER_FLEX_COUNTER_GROUP "RIF_RATE_COUNTER" struct IntfsEntry { @@ -36,7 +37,7 @@ class IntfsOrch : public Orch sai_object_id_t getRouterIntfsId(const string&); bool isPrefixSubnet(const IpPrefix&, const string&); string getRouterIntfsAlias(const IpAddress &ip, const string &vrf_name = ""); - + string getRifRateFlexCounterTableKey(string key); void increaseRouterIntfsRefCount(const string&); void decreaseRouterIntfsRefCount(const string&); diff --git a/orchagent/port_rates.lua b/orchagent/port_rates.lua new file mode 100644 index 000000000000..a6bfaaea0261 --- /dev/null +++ b/orchagent/port_rates.lua @@ -0,0 +1,88 @@ +-- KEYS - port IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local rates_table_name = "RATES" + +-- Get configuration +redis.call('SELECT', counters_db) +local smooth_interval = redis.call('HGET', rates_table_name .. ':' .. 'PORT', 'PORT_SMOOTH_INTERVAL') +local alpha = redis.call('HGET', rates_table_name .. ':' .. 'PORT', 'PORT_ALPHA') +local one_minus_alpha = 1.0 - alpha +local delta = tonumber(ARGV[3]) + +logit(alpha) +logit(one_minus_alpha) +logit(delta) + +local initialized = redis.call('HGET', rates_table_name, 'INIT_DONE') + +logit(initialized) + +for i = 1, n do + -- Get new COUNTERS values + local in_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_UCAST_PKTS') + local in_non_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS') + local out_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_UCAST_PKTS') + local out_non_ucast_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS') + local in_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_OCTETS') + local out_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_OCTETS') + + if initialized == 'DONE' or initialized == 'COUNTERS_LAST' then + -- Get old COUNTERS values + local in_ucast_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_UCAST_PKTS_last') + local in_non_ucast_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS_last') + local out_ucast_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_UCAST_PKTS_last') + local out_non_ucast_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS_last') + local in_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_OCTETS_last') + local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_OCTETS_last') + + -- Calculate new rates values + local rx_bps_new = (in_octets - in_octets_last)/delta + local tx_bps_new = (out_octets - out_octets_last)/delta + local rx_pps_new = ((in_ucast_pkts + in_non_ucast_pkts) - (in_ucast_pkts_last + in_non_ucast_pkts_last))/delta + local tx_pps_new = ((out_ucast_pkts + out_non_ucast_pkts) - (out_ucast_pkts_last + out_non_ucast_pkts_last))/delta + + if initialized == "DONE" then + -- Get old rates values + local rx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS') + local rx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS') + local tx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS') + local tx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS') + + -- Smooth the rates values and store them in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', alpha*rx_bps_new + one_minus_alpha*rx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', alpha*rx_pps_new + one_minus_alpha*rx_pps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', alpha*tx_bps_new + one_minus_alpha*tx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', alpha*tx_pps_new + one_minus_alpha*tx_pps_old) + else + -- Store unsmoothed initial rates values in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', rx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', rx_pps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', tx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', tx_pps_new) + redis.call('HSET', rates_table_name, 'INIT_DONE', 'DONE') + end + else + -- Set old COUNTERS values + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_UCAST_PKTS_last', in_ucast_pkts) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS_last', in_non_ucast_pkts) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_UCAST_PKTS_last', out_ucast_pkts) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS_last', out_non_ucast_pkts) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_IN_OCTETS_last', in_octets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_PORT_STAT_IF_OUT_OCTETS_last', out_octets) + redis.call('HSET', rates_table_name, 'INIT_DONE', 'COUNTERS_LAST') + end +end + +return logtable diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index d41ae931ab6c..05b1156dbf00 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -50,6 +50,7 @@ extern BufferOrch *gBufferOrch; #define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000 #define QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "10000" #define PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "10000" +#define PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS "1000" static map fec_mode_map = @@ -226,6 +227,7 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) string queueWmSha, pgWmSha; string queueWmPluginName = "watermark_queue.lua"; string pgWmPluginName = "watermark_pg.lua"; + string portRatePluginName = "port_rates.lua"; try { @@ -235,6 +237,9 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) string pgLuaScript = swss::loadLuaScript(pgWmPluginName); pgWmSha = swss::loadRedisScript(m_counter_db.get(), pgLuaScript); + string portRateLuaScript = swss::loadLuaScript(portRatePluginName); + string portRateSha = swss::loadRedisScript(m_counter_db.get(), portRateLuaScript); + vector fieldValues; fieldValues.emplace_back(QUEUE_PLUGIN_FIELD, queueWmSha); fieldValues.emplace_back(POLL_INTERVAL_FIELD, QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS); @@ -246,10 +251,16 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) fieldValues.emplace_back(POLL_INTERVAL_FIELD, PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS); fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR); m_flexCounterGroupTable->set(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + + fieldValues.clear(); + fieldValues.emplace_back(PORT_PLUGIN_FIELD, portRateSha); + fieldValues.emplace_back(POLL_INTERVAL_FIELD, PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS); + fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); + m_flexCounterGroupTable->set(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); } catch (const runtime_error &e) { - SWSS_LOG_ERROR("Watermark flex counter groups were not set successfully: %s", e.what()); + SWSS_LOG_ERROR("Port flex counter groups were not set successfully: %s", e.what()); } uint32_t i, j; @@ -1827,7 +1838,6 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l vector fields; fields.push_back(tuple); m_counterTable->set("", fields); - // Install a flex counter for this port to track stats std::unordered_set counter_stats; for (const auto& it: port_stat_ids) @@ -1835,7 +1845,6 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l counter_stats.emplace(sai_serialize_port_stat(it)); } port_stat_manager.setCounterIdList(p.m_port_id, CounterType::PORT, counter_stats); - PortUpdate update = { p, true }; notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index d4d3236f22d1..61073d660ab3 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -17,6 +17,7 @@ #define FCS_LEN 4 #define VLAN_TAG_LEN 4 #define PORT_STAT_COUNTER_FLEX_COUNTER_GROUP "PORT_STAT_COUNTER" +#define PORT_RATE_COUNTER_FLEX_COUNTER_GROUP "PORT_RATE_COUNTER" #define QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_STAT_COUNTER" #define QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_WATERMARK_STAT_COUNTER" #define PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "PG_WATERMARK_STAT_COUNTER" @@ -142,6 +143,7 @@ class PortsOrch : public Orch, public Subject std::string getQueueWatermarkFlexCounterTableKey(std::string s); std::string getPriorityGroupWatermarkFlexCounterTableKey(std::string s); + std::string getPortRateFlexCounterTableKey(std::string s); shared_ptr m_counter_db; shared_ptr m_flex_db; diff --git a/orchagent/rif_rates.lua b/orchagent/rif_rates.lua new file mode 100644 index 000000000000..6c89e5233a27 --- /dev/null +++ b/orchagent/rif_rates.lua @@ -0,0 +1,77 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local rates_table_name = "RATES" + +-- Get configuration +redis.call('SELECT', counters_db) +local smooth_interval = redis.call('HGET', rates_table_name .. ':' .. 'RIF', 'RIF_SMOOTH_INTERVAL') +local alpha = redis.call('HGET', rates_table_name .. ':' .. 'RIF', 'RIF_ALPHA') +local one_minus_alpha = 1.0 - alpha +local delta = tonumber(ARGV[3]) + +local initialized = redis.call('HGET', rates_table_name, 'INIT_DONE') +logit(initialized) + +for i = 1, n do + -- Get new COUNTERS values + local in_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_OCTETS') + local in_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_PACKETS') + local out_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS') + local out_pkts = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS') + + if initialized == "DONE" or initialized == "COUNTERS_LAST" then + -- Get old COUNTERS values + local in_octets_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_OCTETS_last') + local in_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_PACKETS_last') + local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS_last') + local out_pkts_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS_last') + + -- Calculate new rates values + local rx_bps_new = (in_octets - in_octets_last)/delta + local tx_bps_new = (out_octets - out_octets_last)/delta + local rx_pps_new = (in_pkts - in_pkts_last)/delta + local tx_pps_new = (out_pkts - out_pkts_last)/delta + + if initialized == "DONE" then + -- Get old rates values + local rx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS') + local rx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS') + local tx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS') + local tx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS') + + -- Smooth the rates values and store them in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', alpha*rx_bps_new + one_minus_alpha*rx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', alpha*rx_pps_new + one_minus_alpha*rx_pps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', alpha*tx_bps_new + one_minus_alpha*tx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', alpha*tx_pps_new + one_minus_alpha*tx_pps_old) + else + -- Store unsmoothed initial rates values in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', rx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', rx_pps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', tx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', tx_pps_new) + redis.call('HSET', rates_table_name, 'INIT_DONE', 'DONE') + end + else + -- Set old COUNTERS values + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_OCTETS_last', in_octets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_IN_PACKETS_last', in_pkts) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS_last', out_octets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS_last', out_pkts) + redis.call('HSET', rates_table_name, 'INIT_DONE', 'COUNTERS_LAST') + end +end + +return logtable