Skip to content

Commit ed783e1

Browse files
[orchagent] Add trap flow counter support (sonic-net#1951)
* Add trap flow counter support. See HLD: sonic-net/SONiC#858 * Flow counters are usually used for debugging, troubleshooting and performance enhancement processes. Host interface trap counter can get number of received traps per Trap ID.
1 parent e9b05a3 commit ed783e1

14 files changed

+736
-134
lines changed

orchagent/Makefile.am

+3-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ dist_swss_DATA = \
2525
watermark_pg.lua \
2626
watermark_bufferpool.lua \
2727
lagids.lua \
28-
tunnel_rates.lua
28+
tunnel_rates.lua \
29+
trap_rates.lua
2930

3031
bin_PROGRAMS = orchagent routeresync orchagent_restart_check
3132

@@ -92,7 +93,7 @@ orchagent_SOURCES = \
9293
srv6orch.cpp \
9394
response_publisher.cpp
9495

95-
orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp
96+
orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp flex_counter/flow_counter_handler.cpp
9697
orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp
9798

9899
orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)

orchagent/copporch.cpp

+229-29
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
#include "sai.h"
22
#include "copporch.h"
33
#include "portsorch.h"
4+
#include "flexcounterorch.h"
45
#include "tokenize.h"
56
#include "logger.h"
7+
#include "sai_serialize.h"
8+
#include "schema.h"
9+
#include "directory.h"
10+
#include "flow_counter_handler.h"
11+
#include "timer.h"
612

713
#include <inttypes.h>
814
#include <sstream>
@@ -18,8 +24,11 @@ extern sai_switch_api_t* sai_switch_api;
1824

1925
extern sai_object_id_t gSwitchId;
2026
extern PortsOrch* gPortsOrch;
27+
extern Directory<Orch*> gDirectory;
2128
extern bool gIsNatSupported;
2229

30+
#define FLEX_COUNTER_UPD_INTERVAL 1
31+
2332
static map<string, sai_meter_type_t> policer_meter_map = {
2433
{"packets", SAI_METER_TYPE_PACKETS},
2534
{"bytes", SAI_METER_TYPE_BYTES}
@@ -82,6 +91,21 @@ static map<string, sai_hostif_trap_type_t> trap_id_map = {
8291
{"bfdv6_micro", SAI_HOSTIF_TRAP_TYPE_BFDV6_MICRO}
8392
};
8493

94+
95+
std::string get_trap_name_by_type(sai_hostif_trap_type_t trap_type)
96+
{
97+
static map<sai_hostif_trap_type_t, string> trap_name_to_id_map;
98+
if (trap_name_to_id_map.empty())
99+
{
100+
for (const auto &kv : trap_id_map)
101+
{
102+
trap_name_to_id_map.emplace(kv.second, kv.first);
103+
}
104+
}
105+
106+
return trap_name_to_id_map.at(trap_type);
107+
}
108+
85109
static map<string, sai_packet_action_t> packet_action_map = {
86110
{"drop", SAI_PACKET_ACTION_DROP},
87111
{"forward", SAI_PACKET_ACTION_FORWARD},
@@ -97,11 +121,23 @@ const string default_trap_group = "default";
97121
const vector<sai_hostif_trap_type_t> default_trap_ids = {
98122
SAI_HOSTIF_TRAP_TYPE_TTL_ERROR
99123
};
124+
const uint HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS = 10000;
100125

101126
CoppOrch::CoppOrch(DBConnector* db, string tableName) :
102-
Orch(db, tableName)
127+
Orch(db, tableName),
128+
m_counter_db(std::shared_ptr<DBConnector>(new DBConnector("COUNTERS_DB", 0))),
129+
m_flex_db(std::shared_ptr<DBConnector>(new DBConnector("FLEX_COUNTER_DB", 0))),
130+
m_asic_db(std::shared_ptr<DBConnector>(new DBConnector("ASIC_DB", 0))),
131+
m_counter_table(std::unique_ptr<Table>(new Table(m_counter_db.get(), COUNTERS_TRAP_NAME_MAP))),
132+
m_vidToRidTable(std::unique_ptr<Table>(new Table(m_asic_db.get(), "VIDTORID"))),
133+
m_flex_counter_group_table(std::unique_ptr<ProducerTable>(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE))),
134+
m_trap_counter_manager(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS, false)
103135
{
104136
SWSS_LOG_ENTER();
137+
auto intervT = timespec { .tv_sec = FLEX_COUNTER_UPD_INTERVAL , .tv_nsec = 0 };
138+
m_FlexCounterUpdTimer = new SelectableTimer(intervT);
139+
auto executorT = new ExecutableTimer(m_FlexCounterUpdTimer, this, "FLEX_COUNTER_UPD_TIMER");
140+
Orch::addExecutor(executorT);
105141

106142
initDefaultHostIntfTable();
107143
initDefaultTrapGroup();
@@ -321,6 +357,8 @@ bool CoppOrch::applyAttributesToTrapIds(sai_object_id_t trap_group_id,
321357
}
322358
m_syncdTrapIds[trap_id].trap_group_obj = trap_group_id;
323359
m_syncdTrapIds[trap_id].trap_obj = hostif_trap_id;
360+
m_syncdTrapIds[trap_id].trap_type = trap_id;
361+
bindTrapCounter(hostif_trap_id, trap_id);
324362
}
325363
return true;
326364
}
@@ -706,6 +744,35 @@ void CoppOrch::doTask(Consumer &consumer)
706744
}
707745
}
708746

747+
void CoppOrch::doTask(SelectableTimer &timer)
748+
{
749+
SWSS_LOG_ENTER();
750+
751+
string value;
752+
for (auto it = m_pendingAddToFlexCntr.begin(); it != m_pendingAddToFlexCntr.end(); )
753+
{
754+
const auto id = sai_serialize_object_id(it->first);
755+
if (m_vidToRidTable->hget("", id, value))
756+
{
757+
SWSS_LOG_INFO("Registering %s, id %s", it->second.c_str(), id.c_str());
758+
759+
std::unordered_set<std::string> counter_stats;
760+
FlowCounterHandler::getGenericCounterStatIdList(counter_stats);
761+
m_trap_counter_manager.setCounterIdList(it->first, CounterType::HOSTIF_TRAP, counter_stats);
762+
it = m_pendingAddToFlexCntr.erase(it);
763+
}
764+
else
765+
{
766+
++it;
767+
}
768+
}
769+
770+
if (m_pendingAddToFlexCntr.empty())
771+
{
772+
m_FlexCounterUpdTimer->stop();
773+
}
774+
}
775+
709776
void CoppOrch::getTrapAddandRemoveList(string trap_group_name,
710777
vector<sai_hostif_trap_type_t> &trap_ids,
711778
vector<sai_hostif_trap_type_t> &add_trap_ids,
@@ -777,17 +844,9 @@ bool CoppOrch::trapGroupProcessTrapIdChange (string trap_group_name,
777844
{
778845
if (m_syncdTrapIds.find(i)!= m_syncdTrapIds.end())
779846
{
780-
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(
781-
m_syncdTrapIds[i].trap_obj);
782-
if (sai_status != SAI_STATUS_SUCCESS)
847+
if (!removeTrap(m_syncdTrapIds[i].trap_obj))
783848
{
784-
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
785-
m_syncdTrapIds[i].trap_obj);
786-
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
787-
if (handle_status != task_success)
788-
{
789-
return parseHandleSaiStatusFailure(handle_status);
790-
}
849+
return false;
791850
}
792851
}
793852
}
@@ -830,17 +889,9 @@ bool CoppOrch::trapGroupProcessTrapIdChange (string trap_group_name,
830889
*/
831890
if (m_syncdTrapIds[i].trap_group_obj == m_trap_group_map[trap_group_name])
832891
{
833-
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(
834-
m_syncdTrapIds[i].trap_obj);
835-
if (sai_status != SAI_STATUS_SUCCESS)
892+
if (!removeTrap(m_syncdTrapIds[i].trap_obj))
836893
{
837-
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
838-
m_syncdTrapIds[i].trap_obj);
839-
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
840-
if (handle_status != task_success)
841-
{
842-
return parseHandleSaiStatusFailure(handle_status);
843-
}
894+
return false;
844895
}
845896
m_syncdTrapIds.erase(i);
846897
}
@@ -882,15 +933,9 @@ bool CoppOrch::processTrapGroupDel (string trap_group_name)
882933
if (it.second.trap_group_obj == m_trap_group_map[trap_group_name])
883934
{
884935
trap_ids_to_reset.push_back(it.first);
885-
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(it.second.trap_obj);
886-
if (sai_status != SAI_STATUS_SUCCESS)
936+
if (!removeTrap(it.second.trap_obj))
887937
{
888-
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "", it.second.trap_obj);
889-
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
890-
if (handle_status != task_success)
891-
{
892-
return parseHandleSaiStatusFailure(handle_status);
893-
}
938+
return false;
894939
}
895940
}
896941
}
@@ -1096,3 +1141,158 @@ bool CoppOrch::trapGroupUpdatePolicer (string trap_group_name,
10961141
}
10971142
return true;
10981143
}
1144+
1145+
void CoppOrch::initTrapRatePlugin()
1146+
{
1147+
if (m_trap_rate_plugin_loaded)
1148+
{
1149+
return;
1150+
}
1151+
1152+
std::string trapRatePluginName = "trap_rates.lua";
1153+
try
1154+
{
1155+
std::string trapLuaScript = swss::loadLuaScript(trapRatePluginName);
1156+
std::string trapSha = swss::loadRedisScript(m_counter_db.get(), trapLuaScript);
1157+
1158+
vector<FieldValueTuple> fieldValues;
1159+
fieldValues.emplace_back(FLOW_COUNTER_PLUGIN_FIELD, trapSha);
1160+
fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ);
1161+
m_flex_counter_group_table->set(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, fieldValues);
1162+
}
1163+
catch (const runtime_error &e)
1164+
{
1165+
SWSS_LOG_ERROR("Trap flex counter groups were not set successfully: %s", e.what());
1166+
}
1167+
m_trap_rate_plugin_loaded = true;
1168+
}
1169+
1170+
bool CoppOrch::removeTrap(sai_object_id_t hostif_trap_id)
1171+
{
1172+
unbindTrapCounter(hostif_trap_id);
1173+
1174+
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(hostif_trap_id);
1175+
if (sai_status != SAI_STATUS_SUCCESS)
1176+
{
1177+
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
1178+
hostif_trap_id);
1179+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
1180+
if (handle_status != task_success)
1181+
{
1182+
return parseHandleSaiStatusFailure(handle_status);
1183+
}
1184+
}
1185+
1186+
return true;
1187+
}
1188+
1189+
bool CoppOrch::bindTrapCounter(sai_object_id_t hostif_trap_id, sai_hostif_trap_type_t trap_type)
1190+
{
1191+
auto flex_counters_orch = gDirectory.get<FlexCounterOrch*>();
1192+
1193+
if (!flex_counters_orch || !flex_counters_orch->getHostIfTrapCounterState())
1194+
{
1195+
return false;
1196+
}
1197+
1198+
if (m_trap_obj_name_map.count(hostif_trap_id) > 0)
1199+
{
1200+
return true;
1201+
}
1202+
1203+
initTrapRatePlugin();
1204+
1205+
// Create generic counter
1206+
sai_object_id_t counter_id;
1207+
if (!FlowCounterHandler::createGenericCounter(counter_id))
1208+
{
1209+
return false;
1210+
}
1211+
1212+
// Bind generic counter to trap
1213+
sai_attribute_t trap_attr;
1214+
trap_attr.id = SAI_HOSTIF_TRAP_ATTR_COUNTER_ID;
1215+
trap_attr.value.oid = counter_id;
1216+
sai_status_t sai_status = sai_hostif_api->set_hostif_trap_attribute(hostif_trap_id, &trap_attr);
1217+
if (sai_status != SAI_STATUS_SUCCESS)
1218+
{
1219+
SWSS_LOG_WARN("Failed to bind trap %" PRId64 " to counter %" PRId64 "", hostif_trap_id, counter_id);
1220+
return false;
1221+
}
1222+
1223+
// Update COUNTERS_TRAP_NAME_MAP
1224+
auto trap_name = get_trap_name_by_type(trap_type);
1225+
vector<FieldValueTuple> nameMapFvs;
1226+
nameMapFvs.emplace_back(trap_name, sai_serialize_object_id(counter_id));
1227+
m_counter_table->set("", nameMapFvs);
1228+
1229+
auto was_empty = m_pendingAddToFlexCntr.empty();
1230+
m_pendingAddToFlexCntr[counter_id] = trap_name;
1231+
1232+
if (was_empty)
1233+
{
1234+
m_FlexCounterUpdTimer->start();
1235+
}
1236+
1237+
m_trap_obj_name_map.emplace(hostif_trap_id, trap_name);
1238+
return true;
1239+
}
1240+
1241+
void CoppOrch::unbindTrapCounter(sai_object_id_t hostif_trap_id)
1242+
{
1243+
auto iter = m_trap_obj_name_map.find(hostif_trap_id);
1244+
if (iter == m_trap_obj_name_map.end())
1245+
{
1246+
return;
1247+
}
1248+
1249+
std::string counter_oid_str;
1250+
m_counter_table->hget("", iter->second, counter_oid_str);
1251+
1252+
// Clear FLEX_COUNTER table
1253+
sai_object_id_t counter_id;
1254+
sai_deserialize_object_id(counter_oid_str, counter_id);
1255+
auto update_iter = m_pendingAddToFlexCntr.find(counter_id);
1256+
if (update_iter == m_pendingAddToFlexCntr.end())
1257+
{
1258+
m_trap_counter_manager.clearCounterIdList(counter_id);
1259+
}
1260+
else
1261+
{
1262+
m_pendingAddToFlexCntr.erase(update_iter);
1263+
}
1264+
1265+
// Remove trap from COUNTERS_TRAP_NAME_MAP
1266+
m_counter_table->hdel("", iter->second);
1267+
1268+
// Unbind generic counter to trap
1269+
sai_attribute_t trap_attr;
1270+
trap_attr.id = SAI_HOSTIF_TRAP_ATTR_COUNTER_ID;
1271+
trap_attr.value.oid = SAI_NULL_OBJECT_ID;
1272+
sai_status_t sai_status = sai_hostif_api->set_hostif_trap_attribute(hostif_trap_id, &trap_attr);
1273+
if (sai_status != SAI_STATUS_SUCCESS)
1274+
{
1275+
SWSS_LOG_ERROR("Failed to unbind trap %" PRId64 " to counter %" PRId64 "", hostif_trap_id, counter_id);
1276+
}
1277+
1278+
// Remove generic counter
1279+
FlowCounterHandler::removeGenericCounter(counter_id);
1280+
1281+
m_trap_obj_name_map.erase(iter);
1282+
}
1283+
1284+
void CoppOrch::generateHostIfTrapCounterIdList()
1285+
{
1286+
for (const auto &kv : m_syncdTrapIds)
1287+
{
1288+
bindTrapCounter(kv.second.trap_obj, kv.second.trap_type);
1289+
}
1290+
}
1291+
1292+
void CoppOrch::clearHostIfTrapCounterIdList()
1293+
{
1294+
for (const auto &kv : m_syncdTrapIds)
1295+
{
1296+
unbindTrapCounter(kv.second.trap_obj);
1297+
}
1298+
}

0 commit comments

Comments
 (0)