Skip to content

Commit

Permalink
Add api recording capability and fix getrequest (sonic-net#74)
Browse files Browse the repository at this point in the history
* Handle default trap group and remove vlan members

* Revert log level to notice

* Add api recorder to sairedis

* Use same asic view table for get request

* Remove flush command from recording

* Fix buffer size and handle SAI defines
  • Loading branch information
kcudnik authored Oct 3, 2016
1 parent 7df75aa commit 5372d8d
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 17 deletions.
3 changes: 3 additions & 0 deletions common/saiserialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ sai_serialization_map_t sai_get_serialization_map()
map[SAI_OBJECT_TYPE_SWITCH][SAI_SWITCH_ATTR_INGRESS_BUFFER_POOL_NUM] = SAI_SERIALIZATION_TYPE_UINT32;
map[SAI_OBJECT_TYPE_SWITCH][SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_CHILDS_PER_SCHEDULER_GROUP] = SAI_SERIALIZATION_TYPE_INT32;
map[SAI_OBJECT_TYPE_SWITCH][SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP] = SAI_SERIALIZATION_TYPE_OBJECT_ID;

#ifdef BRCMSAI
map[SAI_OBJECT_TYPE_SWITCH][SAI_SWITCH_ATTR_SWITCH_SHELL_ENABLE] = SAI_SERIALIZATION_TYPE_BOOL;
#endif

map[SAI_OBJECT_TYPE_FDB][SAI_FDB_ENTRY_ATTR_TYPE] = SAI_SERIALIZATION_TYPE_INT32;
map[SAI_OBJECT_TYPE_FDB][SAI_FDB_ENTRY_ATTR_PORT_ID] = SAI_SERIALIZATION_TYPE_OBJECT_ID;
Expand Down
9 changes: 7 additions & 2 deletions lib/inc/sai_redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,22 @@ extern "C" {
#include "swss/table.h"
#include "swss/select.h"
#include "swss/logger.h"

#include "sai_meta.h"

extern volatile bool g_record;
extern void setRecording(bool record);
extern void recordLine(std::string s);

extern std::string joinFieldValues(
_In_ const std::vector<swss::FieldValueTuple> &values);

// other global declarations

extern service_method_table_t g_services;
extern swss::DBConnector *g_db;
extern swss::ProducerTable *g_asicState;

extern swss::NotificationProducer *g_notifySyncdProducer;
extern swss::ProducerTable *g_redisGetProducer;
extern swss::ConsumerTable *g_redisGetConsumer;
extern swss::NotificationConsumer *g_redisNotifications;
extern swss::NotificationConsumer *g_notifySyncdConsumer;
Expand Down
1 change: 1 addition & 0 deletions lib/src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ libsairedis_la_SOURCES = \
sai_redis_generic_set.cpp \
sai_redis_generic_get.cpp \
sai_redis_notifications.cpp \
sai_redis_record.cpp \
../../common/redisclient.cpp \
../../common/saiserialize.cpp \
../../common/saiattributelist.cpp \
Expand Down
5 changes: 5 additions & 0 deletions lib/src/sai_redis_generic_create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ sai_status_t internal_redis_generic_create(

SWSS_LOG_DEBUG("generic create key: %s, fields: %lu", key.c_str(), entry.size());

if (g_record)
{
recordLine("c," + key + "," + joinFieldValues(entry));
}

g_asicState->set(key, entry, "create");

// we assume create will always succeed which may not be true
Expand Down
24 changes: 22 additions & 2 deletions lib/src/sai_redis_generic_get.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,14 @@ sai_status_t internal_redis_generic_get(

SWSS_LOG_DEBUG("generic get key: %s, fields: %lu", key.c_str(), entry.size());

g_redisGetProducer->set(key, entry, "get");
g_redisGetProducer->del(key, "delget");
if (g_record)
{
recordLine("g," + key + "," + joinFieldValues(entry));
}

// get is special, it will not put data
// into asic view, only to message queue
g_asicState->set(key, entry, "get");

// wait for response

Expand Down Expand Up @@ -118,6 +124,15 @@ sai_status_t internal_redis_generic_get(
attr_list,
kco);

if (g_record)
{
const std::string &str_status = kfvKey(kco);
const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);

// first serialized is status
recordLine("G," + str_status + "," + joinFieldValues(values));
}

SWSS_LOG_DEBUG("generic get status: %d", status);

return status;
Expand All @@ -127,6 +142,11 @@ sai_status_t internal_redis_generic_get(
break;
}

if (g_record)
{
recordLine("G,FAILURE");
}

SWSS_LOG_ERROR("generic get failed to get response");

return SAI_STATUS_FAILURE;
Expand Down
5 changes: 5 additions & 0 deletions lib/src/sai_redis_generic_remove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ sai_status_t internal_redis_generic_remove(

SWSS_LOG_DEBUG("generic remove key: %s", key.c_str());

if (g_record)
{
recordLine("r," + key);
}

g_asicState->del(key, "remove");

return SAI_STATUS_SUCCESS;
Expand Down
5 changes: 5 additions & 0 deletions lib/src/sai_redis_generic_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ sai_status_t internal_redis_generic_set(

SWSS_LOG_DEBUG("generic set key: %s, fields: %lu", key.c_str(), entry.size());

if (g_record)
{
recordLine("s," + key + "," + joinFieldValues(entry));
}

g_asicState->set(key, entry, "set");

return SAI_STATUS_SUCCESS;
Expand Down
6 changes: 0 additions & 6 deletions lib/src/sai_redis_interfacequery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ swss::ProducerTable *g_asicState = NULL;

// we probably don't need those to tables to access GET requests
swss::NotificationProducer *g_notifySyncdProducer = NULL;
swss::ProducerTable *g_redisGetProducer = NULL;
swss::ConsumerTable *g_redisGetConsumer = NULL;
swss::NotificationConsumer *g_redisNotifications = NULL;
swss::NotificationConsumer *g_notifySyncdConsumer = NULL;
Expand Down Expand Up @@ -63,11 +62,6 @@ sai_status_t sai_api_initialize(

g_notifySyncdProducer = new swss::NotificationProducer(g_db, "NOTIFYSYNCDREQUERY");

if (g_redisGetProducer != NULL)
delete g_redisGetProducer;

g_redisGetProducer = new swss::ProducerTable(g_db, "GETREQUEST");

if (g_notifySyncdConsumer != NULL)
delete g_notifySyncdConsumer;

Expand Down
5 changes: 5 additions & 0 deletions lib/src/sai_redis_notifications.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ void handle_notification(
{
SWSS_LOG_ENTER();

if (g_record)
{
recordLine("n," + notification + "," + data + "," + joinFieldValues(values));
}

if (notification == "switch_state_change")
{
handle_switch_state_change(data);
Expand Down
102 changes: 102 additions & 0 deletions lib/src/sai_redis_record.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include "sai_redis.h"

std::string getTimestamp()
{
SWSS_LOG_ENTER();

char buffer[64];
struct timeval tv;

gettimeofday(&tv, NULL);

size_t size = strftime(buffer, 32 ,"%Y-%m-%d.%T.", localtime(&tv.tv_sec));

snprintf(&buffer[size], 32, "%06ld", tv.tv_usec);

return std::string(buffer);
}

// currenly true by default for debugging
volatile bool g_record = true;

std::ofstream recording;

void recordLine(std::string s)
{
SWSS_LOG_ENTER();

if (recording.is_open())
{
recording << getTimestamp() << "," << s << std::endl;
}
}

std::string recfile = "dummy.rec";

void startRecording()
{
SWSS_LOG_ENTER();

recfile = "sairedis." + getTimestamp() + ".rec";

recording.open(recfile);

if (!recording.is_open())
{
SWSS_LOG_ERROR("failed to open recording file %s: %s", recfile.c_str(), strerror(errno));
return;
}

recordLine("#,recording on: " + recfile);

SWSS_LOG_NOTICE("started recording: %s", recfile.c_str());
}

void stopRecording()
{
SWSS_LOG_ENTER();

if (recording.is_open())
{
recording.close();

SWSS_LOG_NOTICE("stopped recording: %s", recfile.c_str());
}
}

void setRecording(bool record)
{
SWSS_LOG_ENTER();

g_record = record;

stopRecording();

if (record)
{
startRecording();
}
}

std::string joinFieldValues(
_In_ const std::vector<swss::FieldValueTuple> &values)
{
SWSS_LOG_ENTER();

std::stringstream ss;

for (size_t i = 0; i < values.size(); ++i)
{
const std::string &str_attr_id = fvField(values[i]);
const std::string &str_attr_value = fvValue(values[i]);

if(i != 0)
{
ss << ",";
}

ss << str_attr_id << "=" << str_attr_value;
}

return ss.str();
}
16 changes: 16 additions & 0 deletions lib/src/sai_redis_switch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

// TODO it may be needed to obtain SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP object id

// temporary until new SAI headers
#ifndef SAI_SWITCH_ATTR_CUSTOM_RANGE_START
#define SAI_SWITCH_ATTR_CUSTOM_RANGE_START 0x10000000
#endif

// if we will not get response in 60 seconds when
// notify syncd to compile new state or to switch
// to compiled state, then there is something wrong
Expand Down Expand Up @@ -221,6 +226,8 @@ sai_status_t redis_initialize_switch(

g_run = true;

setRecording(g_record);

SWSS_LOG_DEBUG("creating notification thread");

notification_thread = std::make_shared<std::thread>(std::thread(ntf_thread));
Expand Down Expand Up @@ -337,6 +344,15 @@ sai_status_t redis_set_switch_attribute(

SWSS_LOG_ENTER();

if (attr != NULL)
{
if (attr->id == SAI_SWITCH_ATTR_CUSTOM_RANGE_START + 1)
{
setRecording(attr->value.booldata);
return SAI_STATUS_SUCCESS;
}
}

return meta_sai_set_switch(
attr,
&redis_generic_set_switch);
Expand Down
8 changes: 2 additions & 6 deletions syncd/syncd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,12 +346,10 @@ void internal_syncd_get_send(

// since we have only one get at a time, we don't have to serialize
// object type and object id, only get status is required
// get response will not put any data to table only queue is used
getResponse->set(key, entry, "getresponse");
getResponse->del(key, "delgetresponse");
}


swss::ConsumerTable *getRequest = NULL;
swss::ProducerTable *getResponse = NULL;
swss::NotificationProducer *notifications = NULL;

Expand Down Expand Up @@ -1278,7 +1276,6 @@ int main(int argc, char **argv)
// at the end we cant use producer consumer concept since
// if one proces will restart there may be something in the queue
// also "remove" from response queue will also trigger another "response"
getRequest = new swss::ConsumerTable(db, "GETREQUEST");
getResponse = new swss::ProducerTable(db, "GETRESPONSE");
notifications = new swss::NotificationProducer(dbNtf, "NOTIFICATIONS");
notifySyncdResponse = new swss::NotificationProducer(db, "NOTIFYSYNCDRESPONSE");
Expand Down Expand Up @@ -1364,14 +1361,13 @@ int main(int argc, char **argv)

swss::Select s;

s.addSelectable(getRequest);
s.addSelectable(asicState);
s.addSelectable(notifySyncdQuery);
s.addSelectable(restartQuery);

while(true)
{
swss::Selectable *sel;
swss::Selectable *sel = NULL;

int fd;

Expand Down
1 change: 0 additions & 1 deletion syncd/syncd.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ sai_object_id_t redisGetDefaultTrapGroupId();
void redisClearVidToRidMap();
void redisClearRidToVidMap();

extern swss::ConsumerTable *getRequest;
extern swss::ProducerTable *getResponse;
extern swss::NotificationProducer *notifications;

Expand Down

0 comments on commit 5372d8d

Please sign in to comment.