Skip to content

Commit

Permalink
[utilities] Create utility classes for interacting with flex counters (
Browse files Browse the repository at this point in the history
…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
daall authored and yxieca committed Nov 13, 2019
1 parent 190373a commit c7d8c2b
Show file tree
Hide file tree
Showing 5 changed files with 431 additions and 1 deletion.
4 changes: 3 additions & 1 deletion orchagent/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/warmrestart
INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/warmrestart -I flex_counter

CFLAGS_SAI = -I /usr/include/sai

Expand Down Expand Up @@ -56,6 +56,8 @@ orchagent_SOURCES = \
sfloworch.cpp \
chassisorch.cpp

orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp

orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_LDADD = -lnl-3 -lnl-route-3 -lpthread -lsairedis -lswsscommon -lsaimeta -lsaimetadata
Expand Down
225 changes: 225 additions & 0 deletions orchagent/flex_counter/flex_counter_manager.cpp
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;
}
77 changes: 77 additions & 0 deletions orchagent/flex_counter/flex_counter_manager.h
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
Loading

0 comments on commit c7d8c2b

Please sign in to comment.