Skip to content

Commit

Permalink
[orchagent] Add flow counter support
Browse files Browse the repository at this point in the history
  • Loading branch information
Junchao-Mellanox committed Oct 11, 2021
1 parent fbdcaae commit 0fd3c1f
Show file tree
Hide file tree
Showing 14 changed files with 620 additions and 83 deletions.
5 changes: 4 additions & 1 deletion orchagent/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ INCLUDES = -I $(top_srcdir)/lib \
-I $(top_srcdir)/warmrestart \
-I flex_counter \
-I debug_counter \
-I flow_counter \
-I pbh

CFLAGS_SAI = -I /usr/include/sai
Expand All @@ -21,7 +22,8 @@ dist_swss_DATA = \
watermark_queue.lua \
watermark_pg.lua \
watermark_bufferpool.lua \
lagids.lua
lagids.lua \
trap_rates.lua

bin_PROGRAMS = orchagent routeresync orchagent_restart_check

Expand Down Expand Up @@ -81,6 +83,7 @@ orchagent_SOURCES = \

orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp
orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp
orchagent_SOURCES += flow_counter/flow_counter_handler.cpp

orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
Expand Down
210 changes: 180 additions & 30 deletions orchagent/copporch.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#include "sai.h"
#include "copporch.h"
#include "portsorch.h"
#include "flexcounterorch.h"
#include "tokenize.h"
#include "logger.h"
#include "sai_serialize.h"
#include "schema.h"
#include "directory.h"
#include "flow_counter_handler.h"

#include <inttypes.h>
#include <sstream>
Expand All @@ -18,6 +23,7 @@ extern sai_switch_api_t* sai_switch_api;

extern sai_object_id_t gSwitchId;
extern PortsOrch* gPortsOrch;
extern Directory<Orch*> gDirectory;
extern bool gIsNatSupported;

static map<string, sai_meter_type_t> policer_meter_map = {
Expand Down Expand Up @@ -78,6 +84,21 @@ static map<string, sai_hostif_trap_type_t> trap_id_map = {
{"dest_nat_miss", SAI_HOSTIF_TRAP_TYPE_DNAT_MISS}
};


std::string get_trap_name_by_type(sai_hostif_trap_type_t trap_type)
{
static map<sai_hostif_trap_type_t, string> trap_name_to_id_map;
if (trap_name_to_id_map.empty())
{
for (const auto &kv : trap_id_map)
{
trap_name_to_id_map.emplace(kv.second, kv.first);
}
}

return trap_name_to_id_map.at(trap_type);
}

static map<string, sai_packet_action_t> packet_action_map = {
{"drop", SAI_PACKET_ACTION_DROP},
{"forward", SAI_PACKET_ACTION_FORWARD},
Expand All @@ -93,12 +114,17 @@ const string default_trap_group = "default";
const vector<sai_hostif_trap_type_t> default_trap_ids = {
SAI_HOSTIF_TRAP_TYPE_TTL_ERROR
};
const uint HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS = 1000;

CoppOrch::CoppOrch(DBConnector* db, string tableName) :
Orch(db, tableName)
Orch(db, tableName),
m_counter_db(std::shared_ptr<DBConnector>(new DBConnector("COUNTERS_DB", 0))),
m_flex_db(std::shared_ptr<DBConnector>(new DBConnector("FLEX_COUNTER_DB", 0))),
m_counter_table(std::unique_ptr<Table>(new Table(m_counter_db.get(), COUNTERS_TRAP_NAME_MAP))),
m_flex_counter_group_table(std::unique_ptr<ProducerTable>(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE))),
m_trap_counter_manager(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS, false)
{
SWSS_LOG_ENTER();

initDefaultHostIntfTable();
initDefaultTrapGroup();
initDefaultTrapIds();
Expand Down Expand Up @@ -317,6 +343,8 @@ bool CoppOrch::applyAttributesToTrapIds(sai_object_id_t trap_group_id,
}
m_syncdTrapIds[trap_id].trap_group_obj = trap_group_id;
m_syncdTrapIds[trap_id].trap_obj = hostif_trap_id;
m_syncdTrapIds[trap_id].trap_type = trap_id;
bindTrapCounter(hostif_trap_id, trap_id);
}
return true;
}
Expand Down Expand Up @@ -773,17 +801,9 @@ bool CoppOrch::trapGroupProcessTrapIdChange (string trap_group_name,
{
if (m_syncdTrapIds.find(i)!= m_syncdTrapIds.end())
{
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(
m_syncdTrapIds[i].trap_obj);
if (sai_status != SAI_STATUS_SUCCESS)
if (!removeTrap(m_syncdTrapIds[i].trap_obj))
{
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
m_syncdTrapIds[i].trap_obj);
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
if (handle_status != task_success)
{
return parseHandleSaiStatusFailure(handle_status);
}
return false;
}
}
}
Expand Down Expand Up @@ -826,17 +846,9 @@ bool CoppOrch::trapGroupProcessTrapIdChange (string trap_group_name,
*/
if (m_syncdTrapIds[i].trap_group_obj == m_trap_group_map[trap_group_name])
{
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(
m_syncdTrapIds[i].trap_obj);
if (sai_status != SAI_STATUS_SUCCESS)
if (!removeTrap(m_syncdTrapIds[i].trap_obj))
{
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
m_syncdTrapIds[i].trap_obj);
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
if (handle_status != task_success)
{
return parseHandleSaiStatusFailure(handle_status);
}
return false;
}
m_syncdTrapIds.erase(i);
}
Expand Down Expand Up @@ -878,15 +890,9 @@ bool CoppOrch::processTrapGroupDel (string trap_group_name)
if (it.second.trap_group_obj == m_trap_group_map[trap_group_name])
{
trap_ids_to_reset.push_back(it.first);
sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(it.second.trap_obj);
if (sai_status != SAI_STATUS_SUCCESS)
if (!removeTrap(it.second.trap_obj))
{
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "", it.second.trap_obj);
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
if (handle_status != task_success)
{
return parseHandleSaiStatusFailure(handle_status);
}
return false;
}
}
}
Expand Down Expand Up @@ -1093,3 +1099,147 @@ bool CoppOrch::trapGroupUpdatePolicer (string trap_group_name,
return true;
}

void CoppOrch::initTrapRatePlugin()
{
if (m_trap_rate_plugin_loaded)
{
return;
}

std::string trapRatePluginName = "trap_rates.lua";
try
{
std::string trapLuaScript = swss::loadLuaScript(trapRatePluginName);
std::string trapSha = swss::loadRedisScript(m_counter_db.get(), trapLuaScript);

vector<FieldValueTuple> fieldValues;
fieldValues.emplace_back(FLOW_COUNTER_PLUGIN_FIELD, trapSha);
fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ);
m_flex_counter_group_table->set(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, fieldValues);
}
catch (const runtime_error &e)
{
SWSS_LOG_ERROR("Trap flex counter groups were not set successfully: %s", e.what());
}
m_trap_rate_plugin_loaded = true;
}

bool CoppOrch::removeTrap(sai_object_id_t hostif_trap_id)
{
unbindTrapCounter(hostif_trap_id);

sai_status_t sai_status = sai_hostif_api->remove_hostif_trap(hostif_trap_id);
if (sai_status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to remove trap object %" PRId64 "",
hostif_trap_id);
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_HOSTIF, sai_status);
if (handle_status != task_success)
{
return parseHandleSaiStatusFailure(handle_status);
}
}

return true;
}

bool CoppOrch::bindTrapCounter(sai_object_id_t hostif_trap_id, sai_hostif_trap_type_t trap_type)
{
auto flex_counters_orch = gDirectory.get<FlexCounterOrch*>();

if (!flex_counters_orch || !flex_counters_orch->getHostIfTrapCounterState())
{
return false;
}

if (m_trap_id_name_map.count(hostif_trap_id) > 0)
{
return true;
}

initTrapRatePlugin();

// Create generic counter
sai_object_id_t counter_id;
if (!FlowCounterHandler::createGenericCounter(counter_id))
{
return false;
}

// Bind generic counter to trap
sai_attribute_t trap_attr;
trap_attr.id = SAI_HOSTIF_TRAP_ATTR_COUNTER_ID;
trap_attr.value.oid = counter_id;
sai_status_t sai_status = sai_hostif_api->set_hostif_trap_attribute(hostif_trap_id, &trap_attr);
if (sai_status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_WARN("Failed to bind trap %" PRId64 " to counter %" PRId64 "", hostif_trap_id, counter_id);
return false;
}

// Update COUNTERS_TRAP_NAME_MAP
auto trap_name = get_trap_name_by_type(trap_type);
FieldValueTuple tuple(trap_name, sai_serialize_object_id(counter_id));
vector<FieldValueTuple> fields;
fields.push_back(tuple);
m_counter_table->set("", fields);

// Update FLEX_COUNTER table
std::unordered_set<std::string> counter_stats;
FlowCounterHandler::getGenericCounterIdList(counter_stats);
m_trap_counter_manager.setCounterIdList(counter_id, CounterType::HOSTIF_TRAP, counter_stats);
m_trap_id_name_map.emplace(hostif_trap_id, trap_name);
return true;
}

void CoppOrch::unbindTrapCounter(sai_object_id_t hostif_trap_id)
{
auto iter = m_trap_id_name_map.find(hostif_trap_id);
if (iter == m_trap_id_name_map.end())
{
return;
}

std::string counter_oid_str;
m_counter_table->hget("", iter->second, counter_oid_str);

// Clear FLEX_COUNTER table
sai_object_id_t counter_id;
sai_deserialize_object_id(counter_oid_str, counter_id);
m_trap_counter_manager.clearCounterIdList(counter_id);

// Remmove trap from COUNTERS_TRAP_NAME_MAP
m_counter_table->hdel("", iter->second);

// Unbind generic counter to trap
sai_attribute_t trap_attr;
trap_attr.id = SAI_HOSTIF_TRAP_ATTR_COUNTER_ID;
trap_attr.value.oid = SAI_NULL_OBJECT_ID;
sai_status_t sai_status = sai_hostif_api->set_hostif_trap_attribute(hostif_trap_id, &trap_attr);
if (sai_status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to unbind trap %" PRId64 " to counter %" PRId64 "", hostif_trap_id, counter_id);
}

// Remove generic counter
FlowCounterHandler::removeGenericCounter(counter_id);

m_trap_id_name_map.erase(iter);
}

void CoppOrch::generateHostIfTrapCounterIdList()
{
for (const auto &kv : m_syncdTrapIds)
{
bindTrapCounter(kv.second.trap_obj, kv.second.trap_type);
}
}

void CoppOrch::clearHostIfTrapCounterIdList()
{
for (const auto &kv : m_syncdTrapIds)
{
unbindTrapCounter(kv.second.trap_obj);
}
}

30 changes: 30 additions & 0 deletions orchagent/copporch.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@

#include <map>
#include <set>
#include <memory>
#include "dbconnector.h"
#include "orch.h"
#include "flex_counter_manager.h"
#include "producertable.h"
#include "table.h"

using namespace swss;

#define HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP "HOSTIF_TRAP_FLOW_COUNTER"

// trap fields
const std::string copp_trap_id_list = "trap_ids";
Expand Down Expand Up @@ -33,6 +42,7 @@ struct copp_trap_objects
{
sai_object_id_t trap_obj;
sai_object_id_t trap_group_obj;
sai_hostif_trap_type_t trap_type;
};

/* TrapGroupPolicerTable: trap group ID, policer ID */
Expand All @@ -45,11 +55,15 @@ typedef std::map<sai_object_id_t, sai_object_id_t> TrapGroupHostIfMap;
typedef std::map<sai_hostif_trap_type_t, sai_object_id_t> TrapIdHostIfTableMap;
/* Trap group to trap ID attributes */
typedef std::map<std::string, TrapIdAttribs> TrapGroupTrapIdAttribs;
/* Trap OID to trap name*/
typedef std::map<sai_object_id_t, std::string> TrapIdNameMap;

class CoppOrch : public Orch
{
public:
CoppOrch(swss::DBConnector* db, std::string tableName);
void generateHostIfTrapCounterIdList();
void clearHostIfTrapCounterIdList();
protected:
object_map m_trap_group_map;

Expand All @@ -59,10 +73,21 @@ class CoppOrch : public Orch
TrapGroupHostIfMap m_trap_group_hostif_map;
TrapIdHostIfTableMap m_trapid_hostif_table_map;
TrapGroupTrapIdAttribs m_trap_group_trap_id_attrs;
TrapIdNameMap m_trap_id_name_map;

std::shared_ptr<DBConnector> m_counter_db;
std::shared_ptr<DBConnector> m_flex_db;
std::unique_ptr<Table> m_counter_table;
std::unique_ptr<ProducerTable> m_flex_counter_group_table;

FlexCounterManager m_trap_counter_manager;

bool m_trap_rate_plugin_loaded = false;

void initDefaultHostIntfTable();
void initDefaultTrapGroup();
void initDefaultTrapIds();
void initTrapRatePlugin();

task_process_status processCoppRule(Consumer& consumer);
bool isValidList(std::vector<std::string> &trap_id_list, std::vector<std::string> &all_items) const;
Expand Down Expand Up @@ -99,6 +124,11 @@ class CoppOrch : public Orch

bool trapGroupUpdatePolicer (std::string trap_group_name, std::vector<sai_attribute_t> &policer_attribs);

bool removeTrap(sai_object_id_t hostif_trap_id);

bool bindTrapCounter(sai_object_id_t hostif_trap_id, sai_hostif_trap_type_t trap_type);
void unbindTrapCounter(sai_object_id_t hostif_trap_id);

virtual void doTask(Consumer& consumer);
};
#endif /* SWSS_COPPORCH_H */
Expand Down
1 change: 1 addition & 0 deletions orchagent/flex_counter/flex_counter_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lo
{ CounterType::PORT, PORT_COUNTER_ID_LIST },
{ CounterType::QUEUE, QUEUE_COUNTER_ID_LIST },
{ CounterType::MACSEC_SA_ATTR, MACSEC_SA_ATTR_ID_LIST },
{ CounterType::HOSTIF_TRAP, FLOW_COUNTER_ID_LIST },
};

FlexCounterManager::FlexCounterManager(
Expand Down
1 change: 1 addition & 0 deletions orchagent/flex_counter/flex_counter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class CounterType
PORT_DEBUG,
SWITCH_DEBUG,
MACSEC_SA_ATTR,
HOSTIF_TRAP,
};

// FlexCounterManager allows users to manage a group of flex counters.
Expand Down
Loading

0 comments on commit 0fd3c1f

Please sign in to comment.