forked from sonic-net/sonic-buildimage
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[utilities] Create utility classes for interacting with flex counters (…
…sonic-net#1093) * [utilities] Create utility classes for interacting with flex counters - Adds utility classes for interacting with flex counters - Updates makefiles to support new utilities Signed-off-by: Danny Allen <daall@microsoft.com> * Reorganize helper classes * Respond to PR feedback * Fix stray includes * Strip comma from end of string instead of beginning * Fix build issue * Fix style issues * Add workaround for flex counter behavior
- Loading branch information
Showing
5 changed files
with
431 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#include "flex_counter_manager.h" | ||
|
||
#include <vector> | ||
|
||
#include "schema.h" | ||
#include "rediscommand.h" | ||
#include "logger.h" | ||
#include "sai_serialize.h" | ||
|
||
using std::shared_ptr; | ||
using std::string; | ||
using std::unordered_map; | ||
using std::unordered_set; | ||
using std::vector; | ||
using swss::DBConnector; | ||
using swss::FieldValueTuple; | ||
using swss::ProducerTable; | ||
|
||
const string FLEX_COUNTER_ENABLE("enable"); | ||
const string FLEX_COUNTER_DISABLE("disable"); | ||
|
||
const unordered_map<StatsMode, string> FlexCounterManager::stats_mode_lookup = | ||
{ | ||
{ StatsMode::READ, STATS_MODE_READ }, | ||
}; | ||
|
||
const unordered_map<bool, string> FlexCounterManager::status_lookup = | ||
{ | ||
{ false, FLEX_COUNTER_DISABLE }, | ||
{ true, FLEX_COUNTER_ENABLE } | ||
}; | ||
|
||
const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lookup = | ||
{ | ||
{ CounterType::PORT_DEBUG, PORT_DEBUG_COUNTER_ID_LIST }, | ||
{ CounterType::SWITCH_DEBUG, SWITCH_DEBUG_COUNTER_ID_LIST }, | ||
}; | ||
|
||
// This constructor will create a group that is disabled by default. | ||
FlexCounterManager::FlexCounterManager( | ||
const string& group_name, | ||
const StatsMode stats_mode, | ||
const uint polling_interval) : | ||
group_name(group_name), | ||
stats_mode(stats_mode), | ||
polling_interval(polling_interval), | ||
enabled(false), | ||
flex_counter_db(new DBConnector(FLEX_COUNTER_DB, DBConnector::DEFAULT_UNIXSOCKET, 0)), | ||
flex_counter_group_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_GROUP_TABLE)), | ||
flex_counter_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_TABLE)) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
applyGroupConfiguration(); | ||
|
||
SWSS_LOG_DEBUG("Initialized flex counter group '%s'.", group_name.c_str()); | ||
} | ||
|
||
FlexCounterManager::~FlexCounterManager() | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
for (const auto& counter: installed_counters) | ||
{ | ||
flex_counter_table->del(getFlexCounterTableKey(group_name, counter)); | ||
} | ||
|
||
flex_counter_group_table->del(group_name); | ||
|
||
SWSS_LOG_DEBUG("Deleted flex counter group '%s'.", group_name.c_str()); | ||
} | ||
|
||
void FlexCounterManager::applyGroupConfiguration() | ||
{ | ||
vector<FieldValueTuple> field_values = | ||
{ | ||
FieldValueTuple(STATS_MODE_FIELD, stats_mode_lookup.at(stats_mode)), | ||
FieldValueTuple(POLL_INTERVAL_FIELD, std::to_string(polling_interval)), | ||
FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, status_lookup.at(enabled)) | ||
}; | ||
|
||
flex_counter_group_table->set(group_name, field_values); | ||
} | ||
|
||
void FlexCounterManager::updateGroupPollingInterval( | ||
const uint polling_interval) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
vector<FieldValueTuple> field_values = | ||
{ | ||
FieldValueTuple(POLL_INTERVAL_FIELD, std::to_string(polling_interval)) | ||
}; | ||
flex_counter_group_table->set(group_name, field_values); | ||
|
||
SWSS_LOG_DEBUG("Set polling interval for flex counter group '%s' to %d ms.", | ||
group_name.c_str(), polling_interval); | ||
} | ||
|
||
// enableFlexCounterGroup will do nothing if the flex counter group is already | ||
// enabled. | ||
void FlexCounterManager::enableFlexCounterGroup() | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
if (enabled) | ||
{ | ||
return; | ||
} | ||
|
||
vector<FieldValueTuple> field_values = | ||
{ | ||
FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, FLEX_COUNTER_ENABLE) | ||
}; | ||
flex_counter_group_table->set(group_name, field_values); | ||
enabled = true; | ||
|
||
SWSS_LOG_DEBUG("Enabling flex counters for group '%s'.", | ||
group_name.c_str()); | ||
} | ||
|
||
// disableFlexCounterGroup will do nothing if the flex counter group has been | ||
// disabled. | ||
void FlexCounterManager::disableFlexCounterGroup() | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
if (!enabled) | ||
{ | ||
return; | ||
} | ||
|
||
vector<FieldValueTuple> field_values = | ||
{ | ||
FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, FLEX_COUNTER_DISABLE) | ||
}; | ||
flex_counter_group_table->set(group_name, field_values); | ||
enabled = false; | ||
|
||
SWSS_LOG_DEBUG("Disabling flex counters for group '%s'.", | ||
group_name.c_str()); | ||
} | ||
|
||
// setCounterIdList configures a flex counter to poll the set of provided stats | ||
// that are associated with the given object. | ||
void FlexCounterManager::setCounterIdList( | ||
const sai_object_id_t object_id, | ||
const CounterType counter_type, | ||
const unordered_set<string>& counter_stats) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
auto counter_type_it = counter_id_field_lookup.find(counter_type); | ||
if (counter_type_it == counter_id_field_lookup.end()) | ||
{ | ||
SWSS_LOG_ERROR("Could not update flex counter id list for group '%s': counter type not found.", | ||
group_name.c_str()); | ||
return; | ||
} | ||
|
||
std::vector<swss::FieldValueTuple> field_values = | ||
{ | ||
FieldValueTuple(counter_type_it->second, serializeCounterStats(counter_stats)) | ||
}; | ||
flex_counter_table->set(getFlexCounterTableKey(group_name, object_id), field_values); | ||
installed_counters.insert(object_id); | ||
|
||
SWSS_LOG_DEBUG("Updated flex counter id list for object '%lu' in group '%s'.", | ||
object_id, | ||
group_name.c_str()); | ||
} | ||
|
||
// clearCounterIdList clears all stats that are currently being polled from | ||
// the given object. | ||
void FlexCounterManager::clearCounterIdList(const sai_object_id_t object_id) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
auto counter_it = installed_counters.find(object_id); | ||
if (counter_it == installed_counters.end()) | ||
{ | ||
SWSS_LOG_WARN("No counters found on object '%lu' in group '%s'.", | ||
object_id, | ||
group_name.c_str()); | ||
return; | ||
} | ||
|
||
flex_counter_table->del(getFlexCounterTableKey(group_name, object_id)); | ||
installed_counters.erase(counter_it); | ||
|
||
SWSS_LOG_DEBUG("Cleared flex counter id list for object '%lu' in group '%s'.", | ||
object_id, | ||
group_name.c_str()); | ||
} | ||
|
||
string FlexCounterManager::getFlexCounterTableKey( | ||
const string& group_name, | ||
const sai_object_id_t object_id) const | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
return group_name + flex_counter_table->getTableNameSeparator() + sai_serialize_object_id(object_id); | ||
} | ||
|
||
// serializeCounterStats turns a set of stats into a format suitable for FLEX_COUNTER_DB. | ||
string FlexCounterManager::serializeCounterStats( | ||
const unordered_set<string>& counter_stats) const | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
string stats_string; | ||
for (const auto& stat : counter_stats) | ||
{ | ||
stats_string.append(stat); | ||
stats_string.append(","); | ||
} | ||
|
||
if (!stats_string.empty()) | ||
{ | ||
// Fence post: remove the trailing comma | ||
stats_string.pop_back(); | ||
} | ||
|
||
return stats_string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#ifndef ORCHAGENT_FLEX_COUNTER_MANAGER_H | ||
#define ORCHAGENT_FLEX_COUNTER_MANAGER_H | ||
|
||
#include <string> | ||
#include <unordered_set> | ||
#include <unordered_map> | ||
#include "dbconnector.h" | ||
#include "producertable.h" | ||
|
||
extern "C" { | ||
#include "sai.h" | ||
} | ||
|
||
enum class StatsMode | ||
{ | ||
READ | ||
}; | ||
|
||
enum class CounterType | ||
{ | ||
PORT_DEBUG, | ||
SWITCH_DEBUG | ||
}; | ||
|
||
// FlexCounterManager allows users to manage a group of flex counters. | ||
// | ||
// TODO: FlexCounterManager doesn't currently support the full range of | ||
// flex counter features. In particular, support for standard (i.e. non-debug) | ||
// counters and support for plugins needs to be added. | ||
class FlexCounterManager | ||
{ | ||
public: | ||
FlexCounterManager( | ||
const std::string& group_name, | ||
const StatsMode stats_mode, | ||
const uint polling_interval); | ||
|
||
FlexCounterManager(const FlexCounterManager&) = delete; | ||
FlexCounterManager& operator=(const FlexCounterManager&) = delete; | ||
virtual ~FlexCounterManager(); | ||
|
||
void updateGroupPollingInterval(const uint polling_interval); | ||
void enableFlexCounterGroup(); | ||
void disableFlexCounterGroup(); | ||
|
||
void setCounterIdList( | ||
const sai_object_id_t object_id, | ||
const CounterType counter_type, | ||
const std::unordered_set<std::string>& counter_stats); | ||
void clearCounterIdList(const sai_object_id_t object_id); | ||
|
||
protected: | ||
void applyGroupConfiguration(); | ||
|
||
private: | ||
std::string getFlexCounterTableKey( | ||
const std::string& group_name, | ||
const sai_object_id_t object_id) const; | ||
std::string serializeCounterStats( | ||
const std::unordered_set<std::string>& counter_stats) const; | ||
|
||
std::string group_name; | ||
StatsMode stats_mode; | ||
uint polling_interval; | ||
bool enabled; | ||
std::unordered_set<sai_object_id_t> installed_counters; | ||
|
||
std::shared_ptr<swss::DBConnector> flex_counter_db = nullptr; | ||
std::shared_ptr<swss::ProducerTable> flex_counter_group_table = nullptr; | ||
std::shared_ptr<swss::ProducerTable> flex_counter_table = nullptr; | ||
|
||
static const std::unordered_map<StatsMode, std::string> stats_mode_lookup; | ||
static const std::unordered_map<bool, std::string> status_lookup; | ||
static const std::unordered_map<CounterType, std::string> counter_id_field_lookup; | ||
}; | ||
|
||
#endif // ORCHAGENT_FLEX_COUNTER_MANAGER_H |
Oops, something went wrong.