Skip to content

Commit

Permalink
Add support for fdb flush in sairedis (sonic-net#288)
Browse files Browse the repository at this point in the history
  • Loading branch information
kcudnik authored Jan 24, 2018
1 parent 2f2a2dd commit f8b9385
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/inc/sai_redis.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void check_notifications_pointers(
// there is something wrong and we should fail
#define GET_RESPONSE_TIMEOUT (6*60*1000)

extern std::string getSelectResultAsString(int result);
extern void clear_local_state();
extern void setRecording(bool record);
extern sai_status_t setRecordingOutputDir(
Expand Down
102 changes: 101 additions & 1 deletion lib/src/sai_redis_fdb.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,101 @@
#include "sai_redis.h"
#include "meta/saiserialize.h"
#include "meta/saiattributelist.h"

sai_status_t internal_redis_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();

std::vector<swss::FieldValueTuple> entry = SaiAttributeList::serialize_attr_list(
SAI_OBJECT_TYPE_FDB_FLUSH,
attr_count,
attr_list,
false);

std::string str_object_type = sai_serialize_object_type(SAI_OBJECT_TYPE_FDB_FLUSH);

std::string key = str_object_type + ":" + sai_serialize_object_id(switch_id);

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

if (g_record)
{
recordLine("f|" + key + "|" + joinFieldValues(entry));
}

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

// wait for response

swss::Select s;

// get consumer will be reused for flush

s.addSelectable(g_redisGetConsumer.get());

while (true)
{
SWSS_LOG_DEBUG("wait for response");

swss::Selectable *sel;

int fd;

int result = s.select(&sel, &fd, GET_RESPONSE_TIMEOUT);

if (result == swss::Select::OBJECT)
{
swss::KeyOpFieldsValuesTuple kco;

g_redisGetConsumer->pop(kco);

const std::string &op = kfvOp(kco);
const std::string &opkey = kfvKey(kco);

SWSS_LOG_DEBUG("response: op = %s, key = %s", opkey.c_str(), op.c_str());

if (op != "flushresponse") // ignore non response messages
{
continue;
}

std::string str_sai_status = opkey;

sai_status_t status;

sai_deserialize_status(str_sai_status, status);

if (g_record)
{
const std::string &str_status = kfvKey(kco);

// first serialized is status
recordLine("F|" + str_status);
}

SWSS_LOG_DEBUG("flush status: %d", status);

return status;
}

SWSS_LOG_ERROR("flush failed due to SELECT operation result: %s", getSelectResultAsString(result).c_str());
break;
}

if (g_record)
{
recordLine("F|SAI_STATUS_FAILURE");
}

SWSS_LOG_ERROR("flush failed to get response");

return SAI_STATUS_FAILURE;
}

sai_status_t redis_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
Expand All @@ -10,7 +106,11 @@ sai_status_t redis_flush_fdb_entries(

SWSS_LOG_ENTER();

return SAI_STATUS_NOT_IMPLEMENTED;
return meta_sai_flush_fdb_entries(
switch_id,
attr_count,
attr_list,
internal_redis_flush_fdb_entries);
}

REDIS_GENERIC_QUAD_ENTRY(FDB_ENTRY,fdb_entry);
Expand Down
151 changes: 151 additions & 0 deletions meta/sai_meta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4737,3 +4737,154 @@ void meta_sai_on_fdb_event(
meta_sai_on_fdb_event_single(data[i]);
}
}

// FDB FLUSH

sai_status_t meta_sai_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list,
_In_ sai_flush_fdb_entries_fn flush_fdb_entries)
{
SWSS_LOG_ENTER();

if (flush_fdb_entries == NULL)
{
SWSS_LOG_ERROR("function pointer is NULL");

return SAI_STATUS_INVALID_PARAMETER;
}

if (attr_count > MAX_LIST_COUNT)
{
SWSS_LOG_ERROR("create attribute count is too large %u > then max list count %u", attr_count, MAX_LIST_COUNT);

return SAI_STATUS_INVALID_PARAMETER;
}

if (attr_count != 0 && attr_list == NULL)
{
SWSS_LOG_ERROR("attribute list is NULL");

return SAI_STATUS_INVALID_PARAMETER;
}

sai_object_type_t swot = sai_object_type_query(switch_id);

if (swot != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_ERROR("object type for switch_id %s is %s",
sai_serialize_object_id(switch_id).c_str(),
sai_serialize_object_type(swot).c_str());

return SAI_STATUS_INVALID_PARAMETER;
}

if (!object_reference_exists(switch_id))
{
SWSS_LOG_ERROR("switch id %s don't exists",
sai_serialize_object_id(switch_id).c_str());

return SAI_STATUS_INVALID_PARAMETER;
}

// validate attributes
// - attribute list can be empty
// - validation is similar to "create" action but there is no
// post create step and no references are updated
// - fdb entries are updated in fdb notification

std::unordered_map<sai_attr_id_t, const sai_attribute_t*> attrs;

SWSS_LOG_DEBUG("attr count = %u", attr_count);

for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t* attr = &attr_list[idx];

auto mdp = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_FDB_FLUSH, attr->id);

if (mdp == NULL)
{
SWSS_LOG_ERROR("unable to find attribute metadata SAI_OBJECT_TYPE_FDB_FLUSH:%d", attr->id);

return SAI_STATUS_INVALID_PARAMETER;
}

const sai_attribute_value_t& value = attr->value;

const sai_attr_metadata_t& md = *mdp;

META_LOG_DEBUG(md, "(fdbflush)");

if (attrs.find(attr->id) != attrs.end())
{
META_LOG_ERROR(md, "attribute id (%u) is defined on attr list multiple times", attr->id);

return SAI_STATUS_INVALID_PARAMETER;
}

attrs[attr->id] = attr;

if (md.flags != SAI_ATTR_FLAGS_CREATE_ONLY)
{
META_LOG_ERROR(md, "attr is expected to be marked as CREATE_ONLY");

return SAI_STATUS_INVALID_PARAMETER;
}

if (md.isconditional || md.validonlylength > 0)
{
META_LOG_ERROR(md, "attr should not be conditional or validonly");

return SAI_STATUS_INVALID_PARAMETER;
}

switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_UINT16:

if (md.isvlan && (value.u16 >= 0xFFF || value.u16 == 0))
{
META_LOG_ERROR(md, "is vlan id but has invalid id %u", value.u16);

return SAI_STATUS_INVALID_PARAMETER;
}

break;

case SAI_ATTR_VALUE_TYPE_INT32:

if (md.isenum && !sai_metadata_is_allowed_enum_value(&md, value.s32))
{
META_LOG_ERROR(md, "is enum, but value %d not found on allowed values list", value.s32);

return SAI_STATUS_INVALID_PARAMETER;
}

break;

case SAI_ATTR_VALUE_TYPE_OBJECT_ID:

{
sai_status_t status = meta_generic_validation_objlist(md, switch_id, 1, &value.oid);

if (status != SAI_STATUS_SUCCESS)
{
return status;
}

break;
}

default:

META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
}

// there are no mandatory attributes
// there are no conditional attributes

return flush_fdb_entries(switch_id, attr_count, attr_list);
}
8 changes: 8 additions & 0 deletions meta/sai_meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ extern void meta_sai_on_fdb_event(
_In_ uint32_t count,
_In_ sai_fdb_event_notification_data_t *data);

// FDB FLUSH

extern sai_status_t meta_sai_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list,
_In_ sai_flush_fdb_entries_fn flush_fdb_entries);

// UNIT TESTS HELPERS

/**
Expand Down
47 changes: 47 additions & 0 deletions syncd/syncd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2259,6 +2259,49 @@ sai_status_t processBulkEvent(
return status;
}

sai_status_t processFdbFlush(
_In_ const swss::KeyOpFieldsValuesTuple &kco)
{
SWSS_LOG_ENTER();

const std::string &key = kfvKey(kco);
const std::string &str_object_type = key.substr(0, key.find(":"));
const std::string &str_object_id = key.substr(key.find(":") + 1);

sai_object_id_t switch_vid;

sai_deserialize_object_id(str_object_id, switch_vid);

sai_object_id_t switch_rid = translate_vid_to_rid(switch_vid);

const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);

for (const auto &v: values)
{
SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str());
}

SaiAttributeList list(SAI_OBJECT_TYPE_FDB_FLUSH, values, false);

/*
* Attribute list can't be const since we will use it to translate VID to
* RID inplace.
*/

sai_attribute_t *attr_list = list.get_attr_list();
uint32_t attr_count = list.get_attr_count();

translate_vid_to_rid_list(SAI_OBJECT_TYPE_FDB_FLUSH, attr_count, attr_list);

sai_status_t status = sai_metadata_sai_fdb_api->flush_fdb_entries(switch_rid, attr_count, attr_list);

std::vector<swss::FieldValueTuple> en;

getResponse->set(sai_serialize_status(status), en, "flushresponse");

return status;
}

sai_status_t processEvent(
_In_ swss::ConsumerTable &consumer)
{
Expand Down Expand Up @@ -2330,6 +2373,10 @@ sai_status_t processEvent(
{
return processGetStatsEvent(kco);
}
else if (op == "flush")
{
return processFdbFlush(kco);
}
else
{
SWSS_LOG_THROW("api '%s' is not implemented", op.c_str());
Expand Down
21 changes: 20 additions & 1 deletion vslib/src/sai_vs_fdb.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
#include "sai_vs.h"
#include "sai_vs_internal.h"

sai_status_t internal_vs_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();

// TODO implement actual flush (9 cases) with ntf generation (queue)
// also update meta db here

SWSS_LOG_ERROR("not implemented");

return SAI_STATUS_NOT_IMPLEMENTED;
}

sai_status_t vs_flush_fdb_entries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
Expand All @@ -10,7 +25,11 @@ sai_status_t vs_flush_fdb_entries(

SWSS_LOG_ENTER();

return SAI_STATUS_NOT_IMPLEMENTED;
return meta_sai_flush_fdb_entries(
switch_id,
attr_count,
attr_list,
internal_vs_flush_fdb_entries);
}

VS_GENERIC_QUAD_ENTRY(FDB_ENTRY,fdb_entry);
Expand Down

0 comments on commit f8b9385

Please sign in to comment.