meta/Meta.cpp (5,039 lines of code) (raw):
#include "Meta.h"
#include "swss/logger.h"
#include "sai_serialize.h"
#include "Globals.h"
#include "SaiAttributeList.h"
#include <inttypes.h>
#include <set>
// TODO add validation for all oids belong to the same switch
#define MAX_LIST_COUNT 0x1000
#define CHECK_STATUS_SUCCESS(s) { if ((s) != SAI_STATUS_SUCCESS) return (s); }
#define VALIDATION_LIST(md,vlist) \
{ \
auto _status = meta_genetic_validation_list(md,vlist.count,vlist.list); \
if (_status != SAI_STATUS_SUCCESS) \
{ \
return _status; \
} \
}
#define VALIDATION_STATS_LIST(cnt,lst) \
{ \
if ((cnt > MAX_LIST_COUNT) || ((cnt == 0) && (lst != NULL)) || ((cnt > 0) && (lst == NULL)))\
{ \
SWSS_LOG_ERROR("Invalid list and list-count"); \
return SAI_STATUS_INVALID_PARAMETER; \
} \
}
#define VALIDATION_LIST_GET(md, list) \
{ \
if (list.count > MAX_LIST_COUNT) \
{ \
META_LOG_ERROR(md, "list count %u > max list count %u", list.count, MAX_LIST_COUNT);\
} \
}
#define META_LOG_STATUS(status,msg) \
if ((status) == SAI_STATUS_SUCCESS) \
{ SWSS_LOG_DEBUG(msg " status: %s", sai_serialize_status(status).c_str()); } \
else { SWSS_LOG_ERROR(msg " status: %s", sai_serialize_status(status).c_str()); }
#define DECLARE_CREATE_ENTRY(OT,ot) \
sai_status_t Meta::create( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ uint32_t attr_count, \
_In_ const sai_attribute_t *attr_list) \
{ \
SWSS_LOG_ENTER(); \
sai_status_t status = meta_sai_validate_ ## ot (ot, true); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = *ot } } }; \
status = meta_generic_validation_create(meta_key, ot->switch_id, \
attr_count, attr_list); \
CHECK_STATUS_SUCCESS(status); \
status = m_implementation->create(ot, attr_count, attr_list); \
META_LOG_STATUS(status, "create"); \
if (status == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_create(meta_key, ot->switch_id, \
attr_count, attr_list); \
} \
return status; \
}
#define DECLARE_REMOVE_ENTRY(OT,ot) \
sai_status_t Meta::remove( \
_In_ const sai_ ## ot ## _t* ot) \
{ \
SWSS_LOG_ENTER(); \
sai_status_t status = meta_sai_validate_ ## ot (ot, false); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = *ot } } \
}; \
status = meta_generic_validation_remove(meta_key); \
CHECK_STATUS_SUCCESS(status); \
status = m_implementation->remove(ot); \
META_LOG_STATUS(status, "remove"); \
if (status == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_remove(meta_key); \
} \
return status; \
}
#define DECLARE_SET_ENTRY(OT,ot) \
sai_status_t Meta::set( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ const sai_attribute_t *attr) \
{ \
SWSS_LOG_ENTER(); \
sai_status_t status = meta_sai_validate_ ## ot (ot, false); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = *ot } } }; \
status = meta_generic_validation_set(meta_key, attr); \
CHECK_STATUS_SUCCESS(status); \
status = m_implementation->set(ot, attr); \
META_LOG_STATUS(status, "set"); \
if (status == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_set(meta_key, attr); \
} \
return status; \
}
#define DECLARE_GET_ENTRY(OT,ot) \
sai_status_t Meta::get( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ uint32_t attr_count, \
_Inout_ sai_attribute_t *attr_list) \
{ \
SWSS_LOG_ENTER(); \
sai_status_t status = meta_sai_validate_ ## ot (ot, false, true); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = *ot } } }; \
status = meta_generic_validation_get(meta_key, attr_count, attr_list); \
CHECK_STATUS_SUCCESS(status); \
status = m_implementation->get(ot, attr_count, attr_list); \
if (status == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_get(meta_key, ot->switch_id, \
attr_count, attr_list); \
} \
return status; \
}
using namespace saimeta;
Meta::Meta(
_In_ std::shared_ptr<sairedis::SaiInterface> impl):
m_implementation(impl)
{
SWSS_LOG_ENTER();
m_unittestsEnabled = false;
// TODO if metadata supports multiple switches
// then warm boot must be per each switch
m_warmBoot = false;
}
sai_status_t Meta::apiInitialize(
_In_ uint64_t flags,
_In_ const sai_service_method_table_t *service_method_table)
{
SWSS_LOG_ENTER();
return m_implementation->apiInitialize(flags, service_method_table);
}
sai_status_t Meta::apiUninitialize(void)
{
SWSS_LOG_ENTER();
return m_implementation->apiUninitialize();
}
void Meta::meta_warm_boot_notify()
{
SWSS_LOG_ENTER();
m_warmBoot = true;
SWSS_LOG_NOTICE("warmBoot = true");
}
void Meta::meta_init_db()
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("begin");
/*
* This DB will contain objects from all switches.
*
* TODO: later on we will have separate bases for each switch. This way
* should be easier to manage, on remove switch we will just clear that db,
* instead of checking all objects.
*/
m_oids.clear();
m_saiObjectCollection.clear();
m_attrKeys.clear();
m_portRelatedSet.clear();
// m_meta_unittests_set_readonly_set.clear();
// m_unittestsEnabled = false
m_warmBoot = false;
SWSS_LOG_NOTICE("end");
}
bool Meta::isEmpty() const
{
SWSS_LOG_ENTER();
return m_portRelatedSet.getAllPorts().empty()
&& m_oids.getAllOids().empty()
&& m_attrKeys.getAllKeys().empty()
&& m_saiObjectCollection.getAllKeys().empty();
}
void Meta::dump() const
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("portRelatedSet: %zu", m_portRelatedSet.getAllPorts().size());
SWSS_LOG_NOTICE("oids: %zu", m_oids.getAllOids().size());
SWSS_LOG_NOTICE("attrKeys: %zu", m_attrKeys.getAllKeys().size());
SWSS_LOG_NOTICE("saiObjectCollection: %zu", m_saiObjectCollection.getAllKeys().size());
for (auto &oid: m_oids.getAllReferences())
{
SWSS_LOG_NOTICE("oid: %s: count: %u",
sai_serialize_object_id(oid.first).c_str(),
oid.second);
}
for (auto &mk: m_saiObjectCollection.getAllKeys())
{
SWSS_LOG_NOTICE("objcollection: %s", sai_serialize_object_meta_key(mk).c_str());
}
}
sai_status_t Meta::remove(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id)
{
SWSS_LOG_ENTER();
sai_status_t status = meta_sai_validate_oid(object_type, &object_id, SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status)
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id } } };
status = meta_generic_validation_remove(meta_key);
CHECK_STATUS_SUCCESS(status)
status = m_implementation->remove(object_type, object_id);
META_LOG_STATUS(status, "remove");
if (status == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_remove(meta_key);
}
return status;
}
sai_status_t Meta::create(
_In_ sai_object_type_t object_type,
_Out_ sai_object_id_t* object_id,
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
sai_status_t status = meta_sai_validate_oid(object_type, object_id, switch_id, true);
CHECK_STATUS_SUCCESS(status)
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = SAI_NULL_OBJECT_ID } } };
status = meta_generic_validation_create(meta_key, switch_id, attr_count, attr_list);
CHECK_STATUS_SUCCESS(status)
status = m_implementation->create(object_type, object_id, switch_id, attr_count, attr_list);
META_LOG_STATUS(status, "create");
if (status == SAI_STATUS_SUCCESS)
{
meta_key.objectkey.key.object_id = *object_id;
if (meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
/*
* We are creating switch object, so switch id must be the same as
* just created object. We could use SAI_NULL_OBJECT_ID in that
* case and do special switch inside post_create method.
*/
switch_id = *object_id;
}
meta_generic_validation_post_create(meta_key, switch_id, attr_count, attr_list);
}
return status;
}
sai_status_t Meta::set(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ const sai_attribute_t *attr)
{
SWSS_LOG_ENTER();
sai_object_id_t switch_id = switchIdQuery(object_id);
if (!m_oids.objectReferenceExists(switch_id))
{
SWSS_LOG_ERROR("switch id %s doesn't exist",
sai_serialize_object_id(switch_id).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
sai_status_t status = meta_sai_validate_oid(object_type, &object_id, SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status)
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id } } };
status = meta_generic_validation_set(meta_key, attr);
CHECK_STATUS_SUCCESS(status)
status = m_implementation->set(object_type, object_id, attr);
META_LOG_STATUS(status, "set");
if (status == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_set(meta_key, attr);
}
return status;
}
sai_status_t Meta::get(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t attr_count,
_Inout_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
sai_object_id_t switch_id = switchIdQuery(object_id);
sai_status_t status = meta_sai_validate_oid(object_type, &object_id, SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status)
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id } } };
status = meta_generic_validation_get(meta_key, attr_count, attr_list);
CHECK_STATUS_SUCCESS(status)
status = m_implementation->get(object_type, object_id, attr_count, attr_list);
if (status == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_get(meta_key, switch_id, attr_count, attr_list);
}
return status;
}
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_REMOVE_ENTRY);
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_CREATE_ENTRY);
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_SET_ENTRY);
SAIREDIS_DECLARE_EVERY_ENTRY(DECLARE_GET_ENTRY);
sai_status_t Meta::flushFdbEntries(
_In_ sai_object_id_t switch_id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
if (attr_count > MAX_LIST_COUNT)
{
SWSS_LOG_ERROR("create attribute count %u > 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 = objectTypeQuery(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 (!m_oids.objectReferenceExists(switch_id))
{
SWSS_LOG_ERROR("switch id %s doesn't exist",
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;
// SAI metadata checks if
// - attribute is create only
// - is not conditional
// - is not valid only
switch (md.attrvaluetype)
{
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);
CHECK_STATUS_SUCCESS(status)
break;
}
default:
META_LOG_THROW(md, "value type %s is not supported yet, FIXME",
sai_serialize_attr_value_type(md.attrvaluetype).c_str());
}
}
// there are no mandatory attributes
// there are no conditional attributes
auto status = m_implementation->flushFdbEntries(switch_id, attr_count, attr_list);
if (status == SAI_STATUS_SUCCESS)
{
// use same logic as notification, so create notification event
std::vector<int32_t> types;
auto *et = sai_metadata_get_attr_by_id(SAI_FDB_FLUSH_ATTR_ENTRY_TYPE, attr_count, attr_list);
if (et)
{
switch (et->value.s32)
{
case SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC:
types.push_back(SAI_FDB_ENTRY_TYPE_DYNAMIC);
break;
case SAI_FDB_FLUSH_ENTRY_TYPE_STATIC:
types.push_back(SAI_FDB_ENTRY_TYPE_STATIC);
break;
default:
types.push_back(SAI_FDB_ENTRY_TYPE_DYNAMIC);
types.push_back(SAI_FDB_ENTRY_TYPE_STATIC);
break;
}
}
else
{
// no type specified so we need to flush dynamic only
types.push_back(SAI_FDB_ENTRY_TYPE_DYNAMIC);
}
for (auto type: types)
{
sai_fdb_event_notification_data_t data = {};
auto *bv_id = sai_metadata_get_attr_by_id(SAI_FDB_FLUSH_ATTR_BV_ID, attr_count, attr_list);
auto *bp_id = sai_metadata_get_attr_by_id(SAI_FDB_FLUSH_ATTR_BRIDGE_PORT_ID, attr_count, attr_list);
sai_attribute_t list[2];
list[0].id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID;
list[0].value.oid = bp_id ? bp_id->value.oid : SAI_NULL_OBJECT_ID;
list[1].id = SAI_FDB_ENTRY_ATTR_TYPE;
list[1].value.s32 = type;
data.event_type = SAI_FDB_EVENT_FLUSHED;
data.fdb_entry.switch_id = switch_id;
data.fdb_entry.bv_id = (bv_id) ? bv_id->value.oid : SAI_NULL_OBJECT_ID;
data.attr_count = 2;
data.attr = list;
meta_sai_on_fdb_flush_event_consolidated(data);
}
}
return status;
}
#define PARAMETER_CHECK_IF_NOT_NULL(param) { \
if ((param) == nullptr) { \
SWSS_LOG_ERROR("parameter " # param " is NULL"); \
return SAI_STATUS_INVALID_PARAMETER; } }
#define PARAMETER_CHECK_OID_OBJECT_TYPE(param, OT) { \
sai_object_type_t _ot = objectTypeQuery(param); \
if (_ot != (OT)) { \
SWSS_LOG_ERROR("parameter " # param " %s object type is %s, but expected %s", \
sai_serialize_object_id(param).c_str(), \
sai_serialize_object_type(_ot).c_str(), \
sai_serialize_object_type(OT).c_str()); \
return SAI_STATUS_INVALID_PARAMETER; } }
#define PARAMETER_CHECK_OBJECT_TYPE_VALID(ot) { \
if (!sai_metadata_is_object_type_valid(ot)) { \
SWSS_LOG_ERROR("parameter " # ot " object type %d is invalid", (ot)); \
return SAI_STATUS_INVALID_PARAMETER; } }
#define PARAMETER_CHECK_POSITIVE(param) { \
if ((param) <= 0) { \
SWSS_LOG_ERROR("parameter " #param " must be positive"); \
return SAI_STATUS_INVALID_PARAMETER; } }
#define PARAMETER_CHECK_OID_EXISTS(oid, OT) { \
sai_object_meta_key_t _key = { \
.objecttype = (OT), .objectkey = { .key = { .object_id = (oid) } } }; \
if (!m_saiObjectCollection.objectExists(_key)) { \
SWSS_LOG_ERROR("object %s don't exists", sai_serialize_object_id(oid).c_str()); } }
#define DECLARE_BULK_CREATE_ENTRY(OT,ot) \
sai_status_t Meta::bulkCreate( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *ot, \
_In_ const uint32_t *attr_count, \
_In_ const sai_attribute_t **attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
SWSS_LOG_ENTER(); \
PARAMETER_CHECK_IF_NOT_NULL(object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED; \
} \
PARAMETER_CHECK_POSITIVE(object_count); \
PARAMETER_CHECK_IF_NOT_NULL(ot); \
PARAMETER_CHECK_IF_NOT_NULL(attr_count); \
PARAMETER_CHECK_IF_NOT_NULL(attr_list); \
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr) \
{ \
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name); \
return SAI_STATUS_INVALID_PARAMETER; \
} \
std::vector<sai_object_meta_key_t> vmk; \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
sai_status_t status = meta_sai_validate_ ##ot (&ot[idx], true); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = ot[idx] } } \
}; \
vmk.push_back(meta_key); \
status = meta_generic_validation_create(meta_key, ot[idx].switch_id, attr_count[idx], attr_list[idx]); \
CHECK_STATUS_SUCCESS(status); \
} \
auto status = m_implementation->bulkCreate(object_count, ot, attr_count, attr_list, mode, object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
if (object_statuses[idx] == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_create(vmk[idx], ot[idx].switch_id, attr_count[idx], attr_list[idx]); \
} \
} \
return status; \
}
#define DECLARE_BULK_REMOVE_ENTRY(OT,ot) \
sai_status_t Meta::bulkRemove( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *ot, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
SWSS_LOG_ENTER(); \
PARAMETER_CHECK_IF_NOT_NULL(object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED; \
} \
PARAMETER_CHECK_POSITIVE(object_count); \
PARAMETER_CHECK_IF_NOT_NULL(ot); \
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr) \
{ \
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name); \
return SAI_STATUS_INVALID_PARAMETER; \
} \
std::vector<sai_object_meta_key_t> vmk; \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
sai_status_t status = meta_sai_validate_ ##ot (&ot[idx], false); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = ot[idx] } } \
}; \
vmk.push_back(meta_key); \
status = meta_generic_validation_remove(meta_key); \
CHECK_STATUS_SUCCESS(status); \
} \
auto status = m_implementation->bulkRemove(object_count, ot, mode, object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
if (object_statuses[idx] == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_remove(vmk[idx]); \
} \
} \
return status; \
}
#define DECLARE_BULK_SET_ENTRY(OT,ot) \
sai_status_t Meta::bulkSet( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *ot, \
_In_ const sai_attribute_t *attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
SWSS_LOG_ENTER(); \
PARAMETER_CHECK_IF_NOT_NULL(object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED; \
} \
PARAMETER_CHECK_POSITIVE(object_count); \
PARAMETER_CHECK_IF_NOT_NULL(ot); \
PARAMETER_CHECK_IF_NOT_NULL(attr_list); \
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr) \
{ \
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name); \
return SAI_STATUS_INVALID_PARAMETER; \
} \
std::vector<sai_object_meta_key_t> vmk; \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
sai_status_t status = meta_sai_validate_ ##ot (&ot[idx], false); \
CHECK_STATUS_SUCCESS(status); \
sai_object_meta_key_t meta_key = { \
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ ## OT, \
.objectkey = { .key = { .ot = ot[idx] } } \
}; \
vmk.push_back(meta_key); \
status = meta_generic_validation_set(meta_key, &attr_list[idx]); \
CHECK_STATUS_SUCCESS(status); \
} \
auto status = m_implementation->bulkSet(object_count, ot, attr_list, mode, object_statuses); \
for (uint32_t idx = 0; idx < object_count; idx++) \
{ \
if (object_statuses[idx] == SAI_STATUS_SUCCESS) \
{ \
meta_generic_validation_post_set(vmk[idx], &attr_list[idx]); \
} \
} \
return status; \
}
// BULK GET
#define DECLARE_BULK_GET_ENTRY(OT,ot) \
sai_status_t Meta::bulkGet( \
_In_ uint32_t object_count, \
_In_ const sai_ ## ot ## _t *ot, \
_In_ const uint32_t *attr_count, \
_Inout_ sai_attribute_t **attr_list, \
_In_ sai_bulk_op_error_mode_t mode, \
_Out_ sai_status_t *object_statuses) \
{ \
SWSS_LOG_ENTER(); \
SWSS_LOG_ERROR("FIXME not implemented"); \
return SAI_STATUS_NOT_IMPLEMENTED; \
}
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_CREATE_ENTRY);
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_REMOVE_ENTRY);
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_SET_ENTRY);
SAIREDIS_DECLARE_EVERY_BULK_ENTRY(DECLARE_BULK_GET_ENTRY);
sai_status_t Meta::objectTypeGetAvailability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t *attrList,
_Out_ uint64_t *count)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType);
// When checking availability of a resource solely based on OBJECT_TYPE, attrCount is 0
if (attrCount)
{
PARAMETER_CHECK_IF_NOT_NULL(attrList);
}
PARAMETER_CHECK_IF_NOT_NULL(count);
auto info = sai_metadata_get_object_type_info(objectType);
PARAMETER_CHECK_IF_NOT_NULL(info);
std::set<sai_attr_id_t> attrs;
for (uint32_t idx = 0; idx < attrCount; idx++)
{
auto id = attrList[idx].id;
auto mdp = sai_metadata_get_attr_metadata(objectType, id);
if (mdp == nullptr)
{
SWSS_LOG_ERROR("can't find attribute %s:%d",
info->objecttypename,
attrList[idx].id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (attrs.find(id) != attrs.end())
{
SWSS_LOG_ERROR("attr %s already defined on list", mdp->attridname);
return SAI_STATUS_INVALID_PARAMETER;
}
attrs.insert(id);
if (!mdp->isresourcetype)
{
SWSS_LOG_ERROR("attr %s is not resource type", mdp->attridname);
return SAI_STATUS_INVALID_PARAMETER;
}
switch (mdp->attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_INT32:
if (mdp->isenum && !sai_metadata_is_allowed_enum_value(mdp, attrList[idx].value.s32))
{
SWSS_LOG_ERROR("%s is enum, but value %d not found on allowed values list",
mdp->attridname,
attrList[idx].value.s32);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
{
sai_object_type_t ot = objectTypeQuery(attrList[idx].value.oid);
PARAMETER_CHECK_OBJECT_TYPE_VALID(ot);
PARAMETER_CHECK_OID_EXISTS(attrList[idx].value.oid, ot);
break;
}
default:
META_LOG_THROW(*mdp, "value type %s not supported yet, FIXME!",
sai_serialize_attr_value_type(mdp->attrvaluetype).c_str());
}
}
auto status = m_implementation->objectTypeGetAvailability(switchId, objectType, attrCount, attrList, count);
// no post validation required
return status;
}
sai_status_t Meta::queryAttributeCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_Out_ sai_attr_capability_t *capability)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType);
auto mdp = sai_metadata_get_attr_metadata(objectType, attrId);
if (!mdp)
{
SWSS_LOG_ERROR("unable to find attribute: %s:%d",
sai_serialize_object_type(objectType).c_str(),
attrId);
return SAI_STATUS_INVALID_PARAMETER;
}
PARAMETER_CHECK_IF_NOT_NULL(capability);
auto status = m_implementation->queryAttributeCapability(switchId, objectType, attrId, capability);
// no post validation required
return status;
}
sai_status_t Meta::queryAttributeEnumValuesCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_Inout_ sai_s32_list_t *enumValuesCapability)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType);
auto mdp = sai_metadata_get_attr_metadata(objectType, attrId);
if (!mdp)
{
SWSS_LOG_ERROR("unable to find attribute: %s:%d",
sai_serialize_object_type(objectType).c_str(),
attrId);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!mdp->isenum && !mdp->isenumlist)
{
SWSS_LOG_ERROR("%s is not enum/enum list", mdp->attridname);
return SAI_STATUS_INVALID_PARAMETER;
}
PARAMETER_CHECK_IF_NOT_NULL(enumValuesCapability);
if (meta_genetic_validation_list(*mdp, enumValuesCapability->count, enumValuesCapability->list)
!= SAI_STATUS_SUCCESS)
{
return SAI_STATUS_INVALID_PARAMETER;
}
auto status = m_implementation->queryAttributeEnumValuesCapability(switchId, objectType, attrId, enumValuesCapability);
if (status == SAI_STATUS_SUCCESS)
{
if (enumValuesCapability->list)
{
// check if all returned values are members of defined enum
for (uint32_t idx = 0; idx < enumValuesCapability->count; idx++)
{
int val = enumValuesCapability->list[idx];
if (!sai_metadata_is_allowed_enum_value(mdp, val))
{
SWSS_LOG_ERROR("returned value %d is not allowed on %s", val, mdp->attridname);
}
}
}
}
return status;
}
#define META_COUNTERS_COUNT_MSB (0x80000000)
sai_status_t Meta::meta_validate_stats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_Out_ uint64_t *counters,
_In_ sai_stats_mode_t mode)
{
SWSS_LOG_ENTER();
/*
* If last bit of counters count is set to high, and unittests are enabled,
* then this api can be used to SET counter values by user for debugging purposes.
*/
if (m_unittestsEnabled)
{
number_of_counters &= ~(META_COUNTERS_COUNT_MSB);
}
PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type);
PARAMETER_CHECK_OID_OBJECT_TYPE(object_id, object_type);
PARAMETER_CHECK_OID_EXISTS(object_id, object_type);
PARAMETER_CHECK_POSITIVE(number_of_counters);
PARAMETER_CHECK_IF_NOT_NULL(counter_ids);
PARAMETER_CHECK_IF_NOT_NULL(counters);
sai_object_id_t switch_id = switchIdQuery(object_id);
// checks also if object type is OID
sai_status_t status = meta_sai_validate_oid(object_type, &object_id, switch_id, false);
CHECK_STATUS_SUCCESS(status);
auto info = sai_metadata_get_object_type_info(object_type);
PARAMETER_CHECK_IF_NOT_NULL(info);
if (info->statenum == nullptr)
{
SWSS_LOG_ERROR("%s does not support stats", info->objecttypename);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if all counter ids are in enum range
for (uint32_t idx = 0; idx < number_of_counters; idx++)
{
if (sai_metadata_get_enum_value_name(info->statenum, counter_ids[idx]) == nullptr)
{
SWSS_LOG_ERROR("value %d is not in range on %s", counter_ids[idx], info->statenum->name);
return SAI_STATUS_INVALID_PARAMETER;
}
}
// check mode
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_stats_mode_t, mode) == nullptr)
{
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_stats_mode_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::getStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_Out_ uint64_t *counters)
{
SWSS_LOG_ENTER();
auto status = meta_validate_stats(object_type, object_id, number_of_counters, counter_ids, counters, SAI_STATS_MODE_READ);
CHECK_STATUS_SUCCESS(status);
status = m_implementation->getStats(object_type, object_id, number_of_counters, counter_ids, counters);
// no post validation required
return status;
}
sai_status_t Meta::queryStatsCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_capability_list_t *stats_capability)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType);
PARAMETER_CHECK_IF_NOT_NULL(stats_capability);
VALIDATION_STATS_LIST(stats_capability->count, stats_capability->list);
auto info = sai_metadata_get_object_type_info(objectType);
PARAMETER_CHECK_IF_NOT_NULL(info);
if (info->statenum == nullptr)
{
SWSS_LOG_ERROR("%s does not support stats", info->objecttypename);
return SAI_STATUS_INVALID_PARAMETER;
}
auto status = m_implementation->queryStatsCapability(switchId, objectType, stats_capability);
// no post validation required
return status;
}
sai_status_t Meta::queryStatsStCapability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_Inout_ sai_stat_st_capability_list_t *stats_capability)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType);
PARAMETER_CHECK_IF_NOT_NULL(stats_capability);
VALIDATION_STATS_LIST(stats_capability->count, stats_capability->list);
auto info = sai_metadata_get_object_type_info(objectType);
PARAMETER_CHECK_IF_NOT_NULL(info);
if (info->statenum == nullptr)
{
SWSS_LOG_ERROR("%s does not support stats", info->objecttypename);
return SAI_STATUS_INVALID_PARAMETER;
}
auto status = m_implementation->queryStatsStCapability(switchId, objectType, stats_capability);
// no post validation required
return status;
}
sai_status_t Meta::getStatsExt(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Out_ uint64_t *counters)
{
SWSS_LOG_ENTER();
auto status = meta_validate_stats(object_type, object_id, number_of_counters, counter_ids, counters, mode);
CHECK_STATUS_SUCCESS(status);
status = m_implementation->getStatsExt(object_type, object_id, number_of_counters, counter_ids, mode, counters);
// no post validation required
return status;
}
sai_status_t Meta::clearStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids)
{
SWSS_LOG_ENTER();
uint64_t counters;
auto status = meta_validate_stats(object_type, object_id, number_of_counters, counter_ids, &counters, SAI_STATS_MODE_READ);
CHECK_STATUS_SUCCESS(status);
status = m_implementation->clearStats(object_type, object_id, number_of_counters, counter_ids);
// no post validation required
return status;
}
sai_status_t Meta::bulkGetStats(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_key_t *object_key,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Inout_ sai_status_t *object_statuses,
_Out_ uint64_t *counters)
{
SWSS_LOG_ENTER();
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Meta::bulkClearStats(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_key_t *object_key,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids,
_In_ sai_stats_mode_t mode,
_Inout_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
return SAI_STATUS_NOT_IMPLEMENTED;
}
// for bulk operations actually we could make copy of current db and actually
// execute to see if all will succeed
sai_status_t Meta::bulkRemove(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
// all objects must be same type and come from the same switch
// TODO check multiple switches
PARAMETER_CHECK_IF_NOT_NULL(object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED;
}
PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type);
PARAMETER_CHECK_POSITIVE(object_count);
PARAMETER_CHECK_IF_NOT_NULL(object_id);
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr)
{
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
std::vector<sai_object_meta_key_t> vmk;
for (uint32_t idx = 0; idx < object_count; idx++)
{
sai_status_t status = meta_sai_validate_oid(object_type, &object_id[idx], SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status);
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id[idx] } } };
vmk.push_back(meta_key);
status = meta_generic_validation_remove(meta_key);
CHECK_STATUS_SUCCESS(status);
}
auto status = m_implementation->bulkRemove(object_type, object_count, object_id, mode, object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
if (object_statuses[idx] == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_remove(vmk[idx]);
}
}
return status;
}
sai_status_t Meta::bulkSet(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ const sai_attribute_t *attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
// all objects must be same type and come from the same switch
// TODO check multiple switches
PARAMETER_CHECK_IF_NOT_NULL(object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED;
}
PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type);
PARAMETER_CHECK_POSITIVE(object_count);
PARAMETER_CHECK_IF_NOT_NULL(object_id);
PARAMETER_CHECK_IF_NOT_NULL(attr_list);
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr)
{
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
std::vector<sai_object_meta_key_t> vmk;
for (uint32_t idx = 0; idx < object_count; idx++)
{
sai_status_t status = meta_sai_validate_oid(object_type, &object_id[idx], SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status);
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id[idx] } } };
vmk.push_back(meta_key);
status = meta_generic_validation_set(meta_key, &attr_list[idx]);
CHECK_STATUS_SUCCESS(status);
}
auto status = m_implementation->bulkSet(object_type, object_count, object_id, attr_list, mode, object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
if (object_statuses[idx] == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_set(vmk[idx], &attr_list[idx]);
}
}
return status;
}
sai_status_t Meta::bulkGet(
_In_ sai_object_type_t object_type,
_In_ uint32_t object_count,
_In_ const sai_object_id_t *object_id,
_In_ const uint32_t *attr_count,
_Inout_ sai_attribute_t **attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_IF_NOT_NULL(object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED;
}
PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type);
PARAMETER_CHECK_POSITIVE(object_count);
PARAMETER_CHECK_IF_NOT_NULL(attr_count);
PARAMETER_CHECK_IF_NOT_NULL(attr_list);
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr)
{
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
std::vector<sai_object_meta_key_t> vmk;
for (uint32_t idx = 0; idx < object_count; idx++)
{
sai_status_t status = meta_sai_validate_oid(object_type, &object_id[idx], SAI_NULL_OBJECT_ID, false);
CHECK_STATUS_SUCCESS(status);
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = object_id[idx] } } };
vmk.push_back(meta_key);
status = meta_generic_validation_get(meta_key, attr_count[idx], attr_list[idx]);
// FIXME: This macro returns on failure.
// When mode is SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR we should continue instead of return.
// This issue exists for all bulk operations.
CHECK_STATUS_SUCCESS(status);
}
auto status = m_implementation->bulkGet(object_type, object_count, object_id, attr_count, attr_list, mode, object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
if (object_statuses[idx] == SAI_STATUS_SUCCESS)
{
sai_object_id_t switch_id = switchIdQuery(object_id[idx]);
meta_generic_validation_post_get(vmk[idx], switch_id, attr_count[idx], attr_list[idx]);
}
}
return status;
}
sai_status_t Meta::bulkCreate(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t switchId,
_In_ uint32_t object_count,
_In_ const uint32_t *attr_count,
_In_ const sai_attribute_t **attr_list,
_In_ sai_bulk_op_error_mode_t mode,
_Out_ sai_object_id_t *object_id,
_Out_ sai_status_t *object_statuses)
{
SWSS_LOG_ENTER();
// all objects must be same type and come from the same switch
// TODO check multiple switches
PARAMETER_CHECK_IF_NOT_NULL(object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
object_statuses[idx] = SAI_STATUS_NOT_EXECUTED;
}
PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type);
PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH);
PARAMETER_CHECK_POSITIVE(object_count);
PARAMETER_CHECK_IF_NOT_NULL(attr_count);
PARAMETER_CHECK_IF_NOT_NULL(attr_list);
for (uint32_t idx = 0; idx < object_count; idx++)
{
if (attr_list[idx] == nullptr)
{
SWSS_LOG_ERROR("pointer to attribute list at index %u is NULL", idx);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type == SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_THROW("create bulk switch not supported");
}
}
PARAMETER_CHECK_IF_NOT_NULL(object_id);
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_bulk_op_error_mode_t, mode) == nullptr)
{
SWSS_LOG_ERROR("mode value %d is not in range on %s", mode, sai_metadata_enum_sai_bulk_op_error_mode_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
std::vector<sai_object_meta_key_t> vmk;
for (uint32_t idx = 0; idx < object_count; idx++)
{
sai_status_t status = meta_sai_validate_oid(object_type, &object_id[idx], switchId, true);
CHECK_STATUS_SUCCESS(status);
// this is create, oid's don't exist yet
sai_object_meta_key_t meta_key = { .objecttype = object_type, .objectkey = { .key = { .object_id = SAI_NULL_OBJECT_ID } } };
vmk.push_back(meta_key);
status = meta_generic_validation_create(meta_key, switchId, attr_count[idx], attr_list[idx]);
CHECK_STATUS_SUCCESS(status);
}
auto status = m_implementation->bulkCreate(object_type, switchId, object_count, attr_count, attr_list, mode, object_id, object_statuses);
for (uint32_t idx = 0; idx < object_count; idx++)
{
if (object_statuses[idx] == SAI_STATUS_SUCCESS)
{
vmk[idx].objectkey.key.object_id = object_id[idx]; // assign new created object id
meta_generic_validation_post_create(vmk[idx], switchId, attr_count[idx], attr_list[idx]);
}
}
return status;
}
sai_object_type_t Meta::objectTypeQuery(
_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
return m_implementation->objectTypeQuery(objectId);
}
sai_object_id_t Meta::switchIdQuery(
_In_ sai_object_id_t objectId)
{
SWSS_LOG_ENTER();
return m_implementation->switchIdQuery(objectId);
}
sai_status_t Meta::logSet(
_In_ sai_api_t api,
_In_ sai_log_level_t log_level)
{
SWSS_LOG_ENTER();
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_api_t, api) == nullptr)
{
SWSS_LOG_ERROR("api value %d is not in range on %s", api, sai_metadata_enum_sai_api_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
if (sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_log_level_t, log_level) == nullptr)
{
SWSS_LOG_ERROR("log level value %d is not in range on %s", log_level, sai_metadata_enum_sai_log_level_t.name);
return SAI_STATUS_INVALID_PARAMETER;
}
return m_implementation->logSet(api, log_level);
}
sai_status_t Meta::queryApiVersion(
_Out_ sai_api_version_t *version)
{
SWSS_LOG_ENTER();
PARAMETER_CHECK_IF_NOT_NULL(version);
return m_implementation->queryApiVersion(version);
}
void Meta::clean_after_switch_remove(
_In_ sai_object_id_t switchId)
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("cleaning metadata for switch: %s",
sai_serialize_object_id(switchId).c_str());
if (objectTypeQuery(switchId) != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_THROW("oid %s is not SWITCH!",
sai_serialize_object_id(switchId).c_str());
}
// clear port related objects
for (auto port: m_portRelatedSet.getAllPorts())
{
if (switchIdQuery(port) == switchId)
{
m_portRelatedSet.removePort(port);
}
}
// clear oid references
for (auto oid: m_oids.getAllOids())
{
if (switchIdQuery(oid) == switchId)
{
m_oids.objectReferenceClear(oid);
}
}
// clear attr keys
for (auto& key: m_attrKeys.getAllKeys())
{
sai_object_meta_key_t mk;
sai_deserialize_object_meta_key(key, mk);
// we guarantee that switch_id is first in the key structure so we can
// use that as object_id as well
if (switchIdQuery(mk.objectkey.key.object_id) == switchId)
{
m_attrKeys.eraseMetaKey(key);
}
}
for (auto& mk: m_saiObjectCollection.getAllKeys())
{
// we guarantee that switch_id is first in the key structure so we can
// use that as object_id as well
if (switchIdQuery(mk.objectkey.key.object_id) == switchId)
{
m_saiObjectCollection.removeObject(mk);
}
}
SWSS_LOG_NOTICE("removed all objects related to switch %s",
sai_serialize_object_id(switchId).c_str());
}
sai_status_t Meta::meta_generic_validation_remove(
_In_ const sai_object_meta_key_t& meta_key)
{
SWSS_LOG_ENTER();
if (!m_saiObjectCollection.objectExists(meta_key))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
// we don't keep reference of those since those are leafs
return SAI_STATUS_SUCCESS;
}
// for OID objects check oid value
sai_object_id_t oid = meta_key.objectkey.key.object_id;
if (oid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("can't remove null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(oid);
if (object_type == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " is not valid, returned null object id", oid);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != meta_key.objecttype)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " type %d is not accepted, expected object type %d", oid, object_type, meta_key.objecttype);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!m_oids.objectReferenceExists(oid))
{
SWSS_LOG_ERROR("object 0x%" PRIx64 " reference doesn't exist", oid);
return SAI_STATUS_INVALID_PARAMETER;
}
int count = m_oids.getObjectReferenceCount(oid);
if (count != 0)
{
if (object_type == SAI_OBJECT_TYPE_SWITCH)
{
/*
* We allow to remove switch object even if there are ROUTE_ENTRY
* created and referencing this switch, since remove could be used
* in WARM boot scenario.
*/
SWSS_LOG_WARN("removing switch object 0x%" PRIx64 " reference count is %d, removing all objects from meta DB", oid, count);
return SAI_STATUS_SUCCESS;
}
SWSS_LOG_ERROR("object 0x%" PRIx64 " reference count is %d, can't remove", oid, count);
return SAI_STATUS_OBJECT_IN_USE;
}
if (meta_key.objecttype == SAI_OBJECT_TYPE_PORT)
{
return meta_port_remove_validation(meta_key);
}
// should be safe to remove
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_port_remove_validation(
_In_ const sai_object_meta_key_t& meta_key)
{
SWSS_LOG_ENTER();
sai_object_id_t port_id = meta_key.objectkey.key.object_id;
auto relatedObjects = m_portRelatedSet.getPortRelatedObjects(port_id);
if (relatedObjects.size() == 0)
{
// user didn't query any queues, ipgs or scheduler groups
// for this port, then we can just skip this
return SAI_STATUS_SUCCESS;
}
if (!meta_is_object_in_default_state(port_id))
{
SWSS_LOG_ERROR("port %s is not in default state, can't remove",
sai_serialize_object_id(port_id).c_str());
return SAI_STATUS_OBJECT_IN_USE;
}
for (auto oid: relatedObjects)
{
if (m_oids.getObjectReferenceCount(oid) != 0)
{
SWSS_LOG_ERROR("port %s related object %s reference count is not zero, can't remove",
sai_serialize_object_id(port_id).c_str(),
sai_serialize_object_id(oid).c_str());
return SAI_STATUS_OBJECT_IN_USE;
}
if (!meta_is_object_in_default_state(oid))
{
SWSS_LOG_ERROR("port related object %s is not in default state, can't remove",
sai_serialize_object_id(oid).c_str());
return SAI_STATUS_OBJECT_IN_USE;
}
}
SWSS_LOG_NOTICE("all objects related to port %s are in default state, can be remove",
sai_serialize_object_id(port_id).c_str());
return SAI_STATUS_SUCCESS;
}
bool Meta::meta_is_object_in_default_state(
_In_ sai_object_id_t oid)
{
SWSS_LOG_ENTER();
if (oid == SAI_NULL_OBJECT_ID)
SWSS_LOG_THROW("not expected NULL object id");
if (!m_oids.objectReferenceExists(oid))
{
SWSS_LOG_WARN("object %s reference not exists, bug!",
sai_serialize_object_id(oid).c_str());
return false;
}
sai_object_meta_key_t meta_key;
meta_key.objecttype = objectTypeQuery(oid);
meta_key.objectkey.key.object_id = oid;
if (!m_saiObjectCollection.objectExists(meta_key))
{
SWSS_LOG_WARN("object %s don't exists in local database, bug!",
sai_serialize_object_id(oid).c_str());
return false;
}
auto attrs = m_saiObjectCollection.getObject(meta_key)->getAttributes();
for (const auto& attr: attrs)
{
auto &md = *attr->getSaiAttrMetadata();
auto *a = attr->getSaiAttr();
if (md.isreadonly)
continue;
if (!md.isoidattribute)
continue;
if (md.attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
if (a->value.oid != SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("object %s has non default state on %s: %s, expected NULL",
sai_serialize_object_id(oid).c_str(),
md.attridname,
sai_serialize_object_id(a->value.oid).c_str());
return false;
}
}
else if (md.attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_LIST)
{
for (uint32_t i = 0; i < a->value.objlist.count; i++)
{
if (a->value.objlist.list[i] != SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("object %s has non default state on %s[%u]: %s, expected NULL",
sai_serialize_object_id(oid).c_str(),
md.attridname,
i,
sai_serialize_object_id(a->value.objlist.list[i]).c_str());
return false;
}
}
}
else
{
// unable to check whether object is in default state, need fix
SWSS_LOG_ERROR("unsupported oid attribute: %s, FIX ME!", md.attridname);
return false;
}
}
return true;
}
sai_status_t Meta::meta_sai_validate_oid(
_In_ sai_object_type_t object_type,
_In_ const sai_object_id_t* object_id,
_In_ sai_object_id_t switch_id,
_In_ bool create)
{
SWSS_LOG_ENTER();
auto info = sai_metadata_get_object_type_info(object_type);
if (!info)
{
SWSS_LOG_ERROR("invalid object type specified: %d, FIXME", object_type);
return SAI_STATUS_INVALID_PARAMETER;
}
const char* otname = info->objecttypename;
if (info->isnonobjectid)
{
SWSS_LOG_THROW("invalid object type (%s) specified as generic, FIXME", otname);
}
SWSS_LOG_DEBUG("generic object type: %s", otname);
if (object_id == NULL)
{
SWSS_LOG_ERROR("oid pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
if (create)
{
return SAI_STATUS_SUCCESS;
}
sai_object_id_t oid = *object_id;
if (oid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("oid is set to null object id on %s", otname);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t ot = objectTypeQuery(oid);
if (ot == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("%s oid 0x%" PRIx64 " is not valid object type, returned null object type", otname, oid);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t expected = object_type;
if (ot != expected)
{
SWSS_LOG_ERROR("%s oid 0x%" PRIx64 " type %d is wrong type, expected object type %d", otname, oid, ot, expected);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if object exists
sai_object_meta_key_t meta_key_oid = { .objecttype = expected, .objectkey = { .key = { .object_id = oid } } };
if (!m_saiObjectCollection.objectExists(meta_key_oid))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_oid).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
void Meta::meta_generic_validation_post_remove(
_In_ const sai_object_meta_key_t& meta_key)
{
SWSS_LOG_ENTER();
if (meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
/*
* If switch object was removed then meta db was cleared and there are
* no other attributes, no need for reference counting.
*/
clean_after_switch_remove(meta_key.objectkey.key.object_id);
return;
}
// get all attributes that was set
for (auto&it: m_saiObjectCollection.getObject(meta_key)->getAttributes())
{
const sai_attribute_t* attr = it->getSaiAttr();
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
// decrease reference on object id types
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_CHARDATA:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
case SAI_ATTR_VALUE_TYPE_POINTER:
// primitives, ok
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
m_oids.objectReferenceDecrement(value.oid);
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
m_oids.objectReferenceDecrement(value.objlist);
break;
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT64:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (value.aclfield.enable)
{
m_oids.objectReferenceDecrement(value.aclfield.data.oid);
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (value.aclfield.enable)
{
m_oids.objectReferenceDecrement(value.aclfield.data.objlist);
}
break;
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (value.aclaction.enable)
{
m_oids.objectReferenceDecrement(value.aclaction.parameter.oid);
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (value.aclaction.enable)
{
m_oids.objectReferenceDecrement(value.aclaction.parameter.objlist);
}
break;
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
case SAI_ATTR_VALUE_TYPE_JSON:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_MACSEC_SAK:
case SAI_ATTR_VALUE_TYPE_MACSEC_AUTH_KEY:
case SAI_ATTR_VALUE_TYPE_MACSEC_SALT:
case SAI_ATTR_VALUE_TYPE_MACSEC_SCI:
case SAI_ATTR_VALUE_TYPE_MACSEC_SSCI:
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
// no special action required
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
}
// we don't keep track of fdb, neighbor, route since
// those are safe to remove any time (leafs)
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
/*
* Decrease object reference count for all object ids in non object id
* members.
*/
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
m_oids.objectReferenceDecrement(m->getoid(&meta_key));
}
}
else
{
m_oids.objectReferenceRemove(meta_key.objectkey.key.object_id);
}
m_saiObjectCollection.removeObject(meta_key);
std::string metaKey = sai_serialize_object_meta_key(meta_key);
m_attrKeys.eraseMetaKey(metaKey);
if (meta_key.objecttype == SAI_OBJECT_TYPE_PORT)
{
post_port_remove(meta_key);
}
}
void Meta::post_port_remove(
_In_ const sai_object_meta_key_t& meta_key)
{
SWSS_LOG_ENTER();
sai_object_id_t port_id = meta_key.objectkey.key.object_id;
auto relatedObjects = m_portRelatedSet.getPortRelatedObjects(port_id);
if (relatedObjects.size() == 0)
{
// user didn't query any queues, ipgs or scheduler groups
// for this port, then we can just skip this
return;
}
for (auto oid: relatedObjects)
{
// to remove existing objects, let's just call post remove for them
// and metadata will take the rest
sai_object_meta_key_t meta;
meta.objecttype = objectTypeQuery(oid);
meta.objectkey.key.object_id = oid;
SWSS_LOG_INFO("attempt to remove port related object: %s: %s",
sai_serialize_object_type(meta.objecttype).c_str(),
sai_serialize_object_id(oid).c_str());
meta_generic_validation_post_remove(meta);
}
// all related objects were removed, we need to clear current state
m_portRelatedSet.removePort(port_id);
SWSS_LOG_NOTICE("success executing post port remove actions: %s",
sai_serialize_object_id(port_id).c_str());
}
sai_status_t Meta::meta_sai_validate_fdb_entry(
_In_ const sai_fdb_entry_t* fdb_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (create && get)
{
SWSS_LOG_THROW("can't be create and get at the same time");
}
if (fdb_entry == NULL)
{
SWSS_LOG_ERROR("fdb_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
// check if fdb entry exists
sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = *fdb_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_fdb) && !get)
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// fdb entry is valid
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_mcast_fdb_entry(
_In_ const sai_mcast_fdb_entry_t* mcast_fdb_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (mcast_fdb_entry == NULL)
{
SWSS_LOG_ERROR("mcast_fdb_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t bv_id = mcast_fdb_entry->bv_id;
if (bv_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("bv_id set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(bv_id);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("bv_id oid 0x%" PRIx64 " is not valid object type, returned null object type", bv_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != SAI_OBJECT_TYPE_BRIDGE && object_type != SAI_OBJECT_TYPE_VLAN)
{
SWSS_LOG_ERROR("bv_id oid 0x%" PRIx64 " type %d is wrong type, expected BRIDGE or VLAN", bv_id, object_type);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if bv_id exists
sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = bv_id } } };
if (!m_saiObjectCollection.objectExists(meta_key_bv))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_bv).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if fdb entry exists
sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_MCAST_FDB_ENTRY, .objectkey = { .key = { .mcast_fdb_entry = *mcast_fdb_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_fdb) && !get)
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// fdb entry is valid
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_neighbor_entry(
_In_ const sai_neighbor_entry_t* neighbor_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (neighbor_entry == NULL)
{
SWSS_LOG_ERROR("neighbor_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
switch (neighbor_entry->ip_address.addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid address family: %d", neighbor_entry->ip_address.addr_family);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t rif = neighbor_entry->rif_id;
if (rif == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("router interface is set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(rif);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("router interface oid 0x%" PRIx64 " is not valid object type, returned null object type", rif);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t expected = SAI_OBJECT_TYPE_ROUTER_INTERFACE;
if (object_type != expected)
{
SWSS_LOG_ERROR("router interface oid 0x%" PRIx64 " type %d is wrong type, expected object type %d", rif, object_type, expected);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if router interface exists
sai_object_meta_key_t meta_key_rif = { .objecttype = expected, .objectkey = { .key = { .object_id = rif } } };
if (!m_saiObjectCollection.objectExists(meta_key_rif))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_rif).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
sai_object_meta_key_t meta_key_neighbor = { .objecttype = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, .objectkey = { .key = { .neighbor_entry = *neighbor_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_neighbor))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_neighbor).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_neighbor))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_neighbor).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// neighbor entry is valid
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_route_entry(
_In_ const sai_route_entry_t* route_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (route_entry == NULL)
{
SWSS_LOG_ERROR("route_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
auto family = route_entry->destination.addr_family;
switch (family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
break;
case SAI_IP_ADDR_FAMILY_IPV6:
if (!is_ipv6_mask_valid(route_entry->destination.mask.ip6))
{
SWSS_LOG_ERROR("invalid ipv6 mask: %s", sai_serialize_ipv6(route_entry->destination.mask.ip6).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
break;
default:
SWSS_LOG_ERROR("invalid prefix family: %d", family);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t vr = route_entry->vr_id;
if (vr == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("virtual router is set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(vr);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " is not valid object type, returned null object type", vr);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t expected = SAI_OBJECT_TYPE_VIRTUAL_ROUTER;
if (object_type != expected)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " type %d is wrong type, expected object type %d", vr, object_type, expected);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if virtual router exists
sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } };
if (!m_saiObjectCollection.objectExists(meta_key_vr))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_vr).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if route entry exists
sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_ROUTE_ENTRY, .objectkey = { .key = { .route_entry = *route_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_l2mc_entry(
_In_ const sai_l2mc_entry_t* l2mc_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (l2mc_entry == NULL)
{
SWSS_LOG_ERROR("l2mc_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
switch (l2mc_entry->type)
{
case SAI_L2MC_ENTRY_TYPE_SG:
case SAI_L2MC_ENTRY_TYPE_XG:
break;
default:
SWSS_LOG_ERROR("invalid l2mc_entry type: %d", l2mc_entry->type);
return SAI_STATUS_INVALID_PARAMETER;
}
auto family = l2mc_entry->destination.addr_family;
switch (family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid destination family: %d", family);
return SAI_STATUS_INVALID_PARAMETER;
}
family = l2mc_entry->source.addr_family;
switch (family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid source family: %d", family);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t bv_id = l2mc_entry->bv_id;
if (bv_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("bv_id set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(bv_id);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("bv_id oid 0x%" PRIx64 " is not valid object type, returned null object type", bv_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != SAI_OBJECT_TYPE_BRIDGE && object_type != SAI_OBJECT_TYPE_VLAN)
{
SWSS_LOG_ERROR("bv_id oid 0x%" PRIx64 " type %d is wrong type, expected BRIDGE or VLAN", bv_id, object_type);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if bv_id exists
sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = bv_id } } };
if (!m_saiObjectCollection.objectExists(meta_key_bv))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_bv).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if l2mc entry exists
sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_L2MC_ENTRY, .objectkey = { .key = { .l2mc_entry = *l2mc_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_ipmc_entry(
_In_ const sai_ipmc_entry_t* ipmc_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (ipmc_entry == NULL)
{
SWSS_LOG_ERROR("ipmc_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
switch (ipmc_entry->type)
{
case SAI_IPMC_ENTRY_TYPE_SG:
case SAI_IPMC_ENTRY_TYPE_XG:
break;
default:
SWSS_LOG_ERROR("invalid ipmc_entry type: %d", ipmc_entry->type);
return SAI_STATUS_INVALID_PARAMETER;
}
auto family = ipmc_entry->destination.addr_family;
switch (family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid destination family: %d", family);
return SAI_STATUS_INVALID_PARAMETER;
}
family = ipmc_entry->source.addr_family;
switch (family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid source family: %d", family);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t vr_id = ipmc_entry->vr_id;
if (vr_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("vr_id set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(vr_id);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("vr_id oid 0x%" PRIx64 " is not valid object type, returned null object type", vr_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != SAI_OBJECT_TYPE_VIRTUAL_ROUTER)
{
SWSS_LOG_ERROR("vr_id oid 0x%" PRIx64 " type %d is wrong type, expected VIRTUAL_ROUTER", vr_id, object_type);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if vr_id exists
sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = vr_id } } };
if (!m_saiObjectCollection.objectExists(meta_key_bv))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_bv).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if ipmc entry exists
sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_IPMC_ENTRY, .objectkey = { .key = { .ipmc_entry = *ipmc_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_route))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_route).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_nat_entry(
_In_ const sai_nat_entry_t* nat_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (nat_entry == NULL)
{
SWSS_LOG_ERROR("nat_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t vr = nat_entry->vr_id;
if (vr == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("virtual router is set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(vr);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " is not valid object type, "
"returned null object type", vr);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t expected = SAI_OBJECT_TYPE_VIRTUAL_ROUTER;
if (object_type != expected)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " type %d is wrong type, "
"expected object type %d", vr, object_type, expected);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if virtual router exists
sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } };
if (!m_saiObjectCollection.objectExists(meta_key_vr))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_vr).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if NAT entry exists
sai_object_meta_key_t meta_key_nat = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_nat))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_nat).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_nat))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_nat).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_inseg_entry(
_In_ const sai_inseg_entry_t* inseg_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (inseg_entry == NULL)
{
SWSS_LOG_ERROR("inseg_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
// validate mpls label
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_my_sid_entry(
_In_ const sai_my_sid_entry_t* my_sid_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (my_sid_entry == NULL)
{
SWSS_LOG_ERROR("my_sid_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t vr = my_sid_entry->vr_id;
if (vr == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("virtual router is set to null object id");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t object_type = objectTypeQuery(vr);
if (object_type == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " is not valid object type, "
"returned null object type", vr);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t expected = SAI_OBJECT_TYPE_VIRTUAL_ROUTER;
if (object_type != expected)
{
SWSS_LOG_ERROR("virtual router oid 0x%" PRIx64 " type %d is wrong type, "
"expected object type %d", vr, object_type, expected);
return SAI_STATUS_INVALID_PARAMETER;
}
// check if virtual router exists
sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } };
if (!m_saiObjectCollection.objectExists(meta_key_vr))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_vr).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// check if my_sid_entry exists
sai_object_meta_key_t meta_key_my_sid_entry = { .objecttype = SAI_OBJECT_TYPE_MY_SID_ENTRY, .objectkey = { .key = { .my_sid_entry = *my_sid_entry } } };
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_my_sid_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_my_sid_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_my_sid_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_my_sid_entry).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_direction_lookup_entry(
_In_ const sai_direction_lookup_entry_t* direction_lookup_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (direction_lookup_entry == NULL)
{
SWSS_LOG_ERROR("direction_lookup_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_direction_lookup_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_DIRECTION_LOOKUP_ENTRY,
.objectkey = {
.key = { .direction_lookup_entry = *direction_lookup_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_direction_lookup_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_direction_lookup_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_direction_lookup_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_direction_lookup_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_eni_ether_address_map_entry(
_In_ const sai_eni_ether_address_map_entry_t* eni_ether_address_map_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (eni_ether_address_map_entry == NULL)
{
SWSS_LOG_ERROR("eni_ether_address_map_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_eni_ether_address_map_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_ENI_ETHER_ADDRESS_MAP_ENTRY,
.objectkey = {
.key = { .eni_ether_address_map_entry = *eni_ether_address_map_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_eni_ether_address_map_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_eni_ether_address_map_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_eni_ether_address_map_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_eni_ether_address_map_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_vip_entry(
_In_ const sai_vip_entry_t* vip_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (vip_entry == NULL)
{
SWSS_LOG_ERROR("vip_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_vip_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_VIP_ENTRY,
.objectkey = {
.key = { .vip_entry = *vip_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_vip_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_vip_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_vip_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_vip_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_inbound_routing_entry(
_In_ const sai_inbound_routing_entry_t* inbound_routing_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (inbound_routing_entry == NULL)
{
SWSS_LOG_ERROR("inbound_routing_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_inbound_routing_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_INBOUND_ROUTING_ENTRY,
.objectkey = {
.key = { .inbound_routing_entry = *inbound_routing_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_inbound_routing_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_inbound_routing_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_inbound_routing_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_inbound_routing_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_pa_validation_entry(
_In_ const sai_pa_validation_entry_t* pa_validation_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (pa_validation_entry == NULL)
{
SWSS_LOG_ERROR("pa_validation_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_pa_validation_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_PA_VALIDATION_ENTRY,
.objectkey = {
.key = { .pa_validation_entry = *pa_validation_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_pa_validation_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_pa_validation_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_pa_validation_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_pa_validation_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_outbound_routing_entry(
_In_ const sai_outbound_routing_entry_t* outbound_routing_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (outbound_routing_entry == NULL)
{
SWSS_LOG_ERROR("outbound_routing_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_outbound_routing_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_OUTBOUND_ROUTING_ENTRY,
.objectkey = {
.key = { .outbound_routing_entry = *outbound_routing_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_outbound_routing_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_outbound_routing_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_outbound_routing_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_outbound_routing_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_outbound_ca_to_pa_entry(
_In_ const sai_outbound_ca_to_pa_entry_t* outbound_ca_to_pa_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (outbound_ca_to_pa_entry == NULL)
{
SWSS_LOG_ERROR("outbound_ca_to_pa_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_meta_key_t meta_key_outbound_ca_to_pa_entry = {
.objecttype = (sai_object_type_t)SAI_OBJECT_TYPE_OUTBOUND_CA_TO_PA_ENTRY,
.objectkey = {
.key = { .outbound_ca_to_pa_entry = *outbound_ca_to_pa_entry }
}
};
if (create)
{
if (m_saiObjectCollection.objectExists(meta_key_outbound_ca_to_pa_entry))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key_outbound_ca_to_pa_entry).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
return SAI_STATUS_SUCCESS;
}
// set, get, remove
if (!m_saiObjectCollection.objectExists(meta_key_outbound_ca_to_pa_entry))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key_outbound_ca_to_pa_entry).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_sai_validate_flow_entry(
_In_ const sai_flow_entry_t* flow_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (flow_entry == NULL)
{
SWSS_LOG_ERROR("flow_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
// TODO FIX ME
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Meta::meta_sai_validate_meter_bucket_entry(
_In_ const sai_meter_bucket_entry_t* meter_bucket_entry,
_In_ bool create,
_In_ bool get)
{
SWSS_LOG_ENTER();
if (meter_bucket_entry == NULL)
{
SWSS_LOG_ERROR("meter_bucket_entry pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
// TODO FIX ME
return SAI_STATUS_NOT_IMPLEMENTED;
}
sai_status_t Meta::meta_generic_validation_create(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id,
_In_ const uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
if (attr_count > MAX_LIST_COUNT)
{
SWSS_LOG_ERROR("create attribute count %u > max list count %u", attr_count, MAX_LIST_COUNT);
return SAI_STATUS_INVALID_PARAMETER;
}
if (attr_count > 0 && attr_list == NULL)
{
SWSS_LOG_ERROR("attr count is %u but attribute list pointer is NULL", attr_count);
return SAI_STATUS_INVALID_PARAMETER;
}
bool switchcreate = meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH;
if (switchcreate)
{
// we are creating switch
switch_id = SAI_NULL_OBJECT_ID;
/*
* Creating switch can't have any object attributes set on it, OID
* attributes must be applied on switch using SET API.
*/
for (uint32_t i = 0; i < attr_count; ++i)
{
auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_SWITCH, attr_list[i].id);
if (meta == NULL)
{
SWSS_LOG_ERROR("attribute %d not found", attr_list[i].id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (meta->isoidattribute)
{
SWSS_LOG_ERROR("%s is OID attribute, not allowed on create switch", meta->attridname);
return SAI_STATUS_INVALID_PARAMETER;
}
}
}
else
{
/*
* Non switch object case (also non object id)
*
* NOTE: this is a lot of checks for each create
*/
switch_id = meta_extract_switch_id(meta_key, switch_id);
if (switch_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("switch id is NULL for %s", sai_serialize_object_type(meta_key.objecttype).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t sw_type = objectTypeQuery(switch_id);
if (sw_type != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " type is %s, expected SWITCH", switch_id, sai_serialize_object_type(sw_type).c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
// check if switch exists
sai_object_meta_key_t switch_meta_key = { .objecttype = SAI_OBJECT_TYPE_SWITCH, .objectkey = { .key = { .object_id = switch_id } } };
if (!m_saiObjectCollection.objectExists(switch_meta_key))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist yet", switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!m_oids.objectReferenceExists(switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist yet", switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
// ok
}
sai_status_t status = meta_generic_validate_non_object_on_create(meta_key, switch_id);
CHECK_STATUS_SUCCESS(status)
std::unordered_map<sai_attr_id_t, const sai_attribute_t*> attrs;
SWSS_LOG_DEBUG("attr count = %u", attr_count);
bool haskeys = false;
// check each attribute separately
for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t* attr = &attr_list[idx];
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
if (mdp == NULL)
{
SWSS_LOG_ERROR("unable to find attribute metadata %s:%d",
sai_serialize_object_type(meta_key.objecttype).c_str(),
attr->id);
return SAI_STATUS_FAILURE;
}
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
META_LOG_DEBUG(md, "(create)");
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 (SAI_HAS_FLAG_READ_ONLY(md.flags))
{
META_LOG_ERROR(md, "attr is read only and cannot be created");
return SAI_STATUS_INVALID_PARAMETER;
}
if (SAI_HAS_FLAG_KEY(md.flags))
{
haskeys = true;
META_LOG_DEBUG(md, "attr is key");
}
// if we set OID check if exists and if type is correct
// and it belongs to the same switch id
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_CHARDATA:
{
const char* chardata = value.chardata;
size_t len = strnlen(chardata, SAI_HOSTIF_NAME_SIZE);
if (len == SAI_HOSTIF_NAME_SIZE)
{
META_LOG_ERROR(md, "host interface name is too long");
return SAI_STATUS_INVALID_PARAMETER;
}
if (len == 0)
{
META_LOG_ERROR(md, "host interface name is zero");
return SAI_STATUS_INVALID_PARAMETER;
}
for (size_t i = 0; i < len; ++i)
{
char c = chardata[i];
if (c < 0x20 || c > 0x7e)
{
META_LOG_ERROR(md, "interface name contains invalid character 0x%02x", c);
return SAI_STATUS_INVALID_PARAMETER;
}
}
// TODO check whether name is not used by other host interface
break;
}
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_POINTER:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
{
switch (value.ipaddr.addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid address family: %d", value.ipaddr.addr_family);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
}
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
{
status = meta_generic_validation_objlist(md, switch_id, 1, &value.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
{
status = meta_generic_validation_objlist(md, switch_id, value.objlist.count, value.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT64:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
{
if (!value.aclfield.enable)
{
break;
}
status = meta_generic_validation_objlist(md, switch_id, 1, &value.aclfield.data.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
{
if (!value.aclfield.enable)
{
break;
}
status = meta_generic_validation_objlist(md, switch_id, value.aclfield.data.objlist.count, value.aclfield.data.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
{
if (!value.aclaction.enable)
{
break;
}
status = meta_generic_validation_objlist(md, switch_id, 1, &value.aclaction.parameter.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
{
if (!value.aclaction.enable)
{
break;
}
status = meta_generic_validation_objlist(md, switch_id, value.aclaction.parameter.objlist.count, value.aclaction.parameter.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
VALIDATION_LIST(md, value.u8list);
break;
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
VALIDATION_LIST(md, value.s8list);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
VALIDATION_LIST(md, value.u16list);
break;
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
VALIDATION_LIST(md, value.s16list);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
VALIDATION_LIST(md, value.u32list);
break;
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
VALIDATION_LIST(md, value.s32list);
break;
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
VALIDATION_LIST(md, value.qosmap);
break;
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
VALIDATION_LIST(md, value.maplist);
break;
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
VALIDATION_LIST(md, value.aclresource);
break;
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
VALIDATION_LIST(md, value.ipaddrlist);
break;
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
VALIDATION_LIST(md, value.segmentlist);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
VALIDATION_LIST(md, value.u16rangelist);
for (uint32_t i = 0; i < value.u16rangelist.count; i++) {
if (value.u16rangelist.list[i].min > value.u16rangelist.list[i].max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u16rangelist.list[i].min, value.u16rangelist.list[i].max);
return SAI_STATUS_INVALID_PARAMETER;
}
}
break;
case SAI_ATTR_VALUE_TYPE_JSON:
VALIDATION_LIST(md, value.json.json);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
if (value.u32range.min > value.u32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u32range.min, value.u32range.max);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
if (value.s32range.min > value.s32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.s32range.min, value.s32range.max);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
{
switch (value.ipprefix.addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid address family: %d", value.ipprefix.addr_family);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
}
case SAI_ATTR_VALUE_TYPE_MACSEC_SAK:
case SAI_ATTR_VALUE_TYPE_MACSEC_AUTH_KEY:
case SAI_ATTR_VALUE_TYPE_MACSEC_SALT:
case SAI_ATTR_VALUE_TYPE_MACSEC_SCI:
case SAI_ATTR_VALUE_TYPE_MACSEC_SSCI:
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
VALIDATION_LIST(md, value.sysportconfiglist);
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
VALIDATION_LIST(md, value.ipprefixlist);
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
if (md.isenum)
{
int32_t val = value.s32;
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
val = value.aclfield.data.s32;
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
val = value.aclaction.parameter.s32;
break;
default:
val = value.s32;
break;
}
if (!sai_metadata_is_allowed_enum_value(&md, val))
{
META_LOG_ERROR(md, "is enum, but value %d not found on allowed values list", val);
return SAI_STATUS_INVALID_PARAMETER;
}
}
if (md.isenumlist)
{
// we allow repeats on enum list
if (value.s32list.count != 0 && value.s32list.list == NULL)
{
META_LOG_ERROR(md, "enum list is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
for (uint32_t i = value.s32list.count; i < value.s32list.count; ++i)
{
int32_t s32 = value.s32list.list[i];
if (!sai_metadata_is_allowed_enum_value(&md, s32))
{
META_LOG_ERROR(md, "is enum list, but value %d not found on allowed values list", s32);
return SAI_STATUS_INVALID_PARAMETER;
}
}
}
// conditions are checked later on
}
// we are creating object, no need for check if exists (only key values needs to be checked)
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
// just sanity check if object already exists
if (m_saiObjectCollection.objectExists(meta_key))
{
SWSS_LOG_ERROR("object key %s already exists",
sai_serialize_object_meta_key(meta_key).c_str());
return SAI_STATUS_ITEM_ALREADY_EXISTS;
}
}
else
{
/*
* We are creating OID object, and we don't have it's value yet so we
* can't do any check on it.
*/
}
const auto& metadata = get_attributes_metadata(meta_key.objecttype);
if (metadata.empty())
{
SWSS_LOG_ERROR("get attributes metadata returned empty list for object type: %d", meta_key.objecttype);
return SAI_STATUS_FAILURE;
}
// check if all mandatory attributes were passed
for (auto mdp: metadata)
{
const sai_attr_metadata_t& md = *mdp;
if (!SAI_HAS_FLAG_MANDATORY_ON_CREATE(md.flags))
{
continue;
}
if (md.isconditional)
{
// skip conditional attributes for now
continue;
}
const auto &it = attrs.find(md.attrid);
if (it == attrs.end())
{
/*
* Buffer profile shared static/dynamic is special case since it's
* mandatory on create but condition is on
* SAI_BUFFER_PROFILE_ATTR_POOL_ID attribute (see file saibuffer.h).
*/
if (md.objecttype == SAI_OBJECT_TYPE_BUFFER_PROFILE &&
(md.attrid == SAI_BUFFER_PROFILE_ATTR_SHARED_DYNAMIC_TH ||
(md.attrid == SAI_BUFFER_PROFILE_ATTR_SHARED_STATIC_TH)))
{
auto pool_id_attr = sai_metadata_get_attr_by_id(SAI_BUFFER_PROFILE_ATTR_POOL_ID, attr_count, attr_list);
if (pool_id_attr == NULL)
{
META_LOG_ERROR(md, "buffer pool ID is not passed when creating buffer profile, attr is mandatory");
return SAI_STATUS_MANDATORY_ATTRIBUTE_MISSING;
}
sai_object_id_t pool_id = pool_id_attr->value.oid;
if (pool_id == SAI_NULL_OBJECT_ID)
{
/* attribute allows null */
continue;
}
/*
* Object type pool_id is correct since previous loop checked that.
* Now extract SAI_BUFFER_POOL_THRESHOLD_MODE attribute
*/
sai_object_meta_key_t mk = { .objecttype = SAI_OBJECT_TYPE_BUFFER_POOL, .objectkey = { .key = { .object_id = pool_id } } };
auto pool_md = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_BUFFER_POOL, SAI_BUFFER_POOL_ATTR_THRESHOLD_MODE);
auto prev = get_object_previous_attr(mk, *pool_md);
sai_buffer_pool_threshold_mode_t mode;
if (prev == NULL)
{
mode = (sai_buffer_pool_threshold_mode_t)pool_md->defaultvalue->s32;
}
else
{
mode = (sai_buffer_pool_threshold_mode_t)prev->getSaiAttr()->value.s32;
}
if ((mode == SAI_BUFFER_POOL_THRESHOLD_MODE_DYNAMIC && md.attrid == SAI_BUFFER_PROFILE_ATTR_SHARED_DYNAMIC_TH) ||
(mode == SAI_BUFFER_POOL_THRESHOLD_MODE_STATIC && md.attrid == SAI_BUFFER_PROFILE_ATTR_SHARED_STATIC_TH))
{
/* attribute is mandatory */
}
else
{
/* in this case attribute is not mandatory */
META_LOG_INFO(md, "not mandatory");
continue;
}
}
if (md.attrid == SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE && md.objecttype == SAI_OBJECT_TYPE_ACL_TABLE)
{
/*
* TODO Remove in future. Workaround for range type which in
* headers was marked as mandatory by mistake, and we need to
* wait for next SAI integration to pull this change in.
*/
META_LOG_WARN(md, "Workaround: attribute is mandatory but not passed in attr list, REMOVE ME");
continue;
}
META_LOG_ERROR(md, "attribute is mandatory but not passed in attr list");
return SAI_STATUS_MANDATORY_ATTRIBUTE_MISSING;
}
}
// check if we need any conditional attributes
for (auto mdp: metadata)
{
const sai_attr_metadata_t& md = *mdp;
if (!md.isconditional)
{
continue;
}
// this is conditional attribute, check if it's required
bool any = false;
for (size_t index = 0; md.conditions[index] != NULL; index++)
{
const auto& c = *md.conditions[index];
// conditions may only be on the same object type
const auto& cmd = *sai_metadata_get_attr_metadata(meta_key.objecttype, c.attrid);
const sai_attribute_value_t* cvalue = cmd.defaultvalue;
const sai_attribute_t *cattr = sai_metadata_get_attr_by_id(c.attrid, attr_count, attr_list);
if (cattr != NULL)
{
META_LOG_DEBUG(md, "condition attr %d was passed, using it's value", c.attrid);
cvalue = &cattr->value;
}
if (cmd.attrvaluetype == SAI_ATTR_VALUE_TYPE_BOOL)
{
if (c.condition.booldata == cvalue->booldata)
{
META_LOG_DEBUG(md, "bool condition was met on attr %d = %d", cmd.attrid, c.condition.booldata);
any = true;
break;
}
}
else // enum condition
{
int32_t val = cvalue->s32;
switch (cmd.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
val = cvalue->aclfield.data.s32;
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
val = cvalue->aclaction.parameter.s32;
break;
default:
val = cvalue->s32;
break;
}
if (c.condition.s32 == val)
{
META_LOG_DEBUG(md, "enum condition was met on attr id %d, val = %d", cmd.attrid, val);
any = true;
break;
}
}
}
if (!any)
{
// maybe we can let it go here?
if (attrs.find(md.attrid) != attrs.end())
{
if (md.isconditionrelaxed)
{
META_LOG_WARN(md, "conditional, but condition was not met, this attribute is not required, but passed (relaxed condition)");
continue;
}
META_LOG_ERROR(md, "conditional, but condition was not met, this attribute is not required, but passed");
return SAI_STATUS_INVALID_PARAMETER;
}
continue;
}
// is required, check if user passed it
const auto &it = attrs.find(md.attrid);
if (it == attrs.end())
{
META_LOG_ERROR(md, "attribute is conditional and is mandatory but not passed in attr list");
return SAI_STATUS_MANDATORY_ATTRIBUTE_MISSING;
}
}
if (haskeys)
{
std::string key = AttrKeyMap::constructKey(switch_id, meta_key, attr_count, attr_list);
// since we didn't created oid yet, we don't know if attribute key exists, check all
if (m_attrKeys.attrKeyExists(key))
{
SWSS_LOG_ERROR("attribute key %s already exists, can't create", key.c_str());
return SAI_STATUS_INVALID_PARAMETER;
}
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_generic_validation_set(
_In_ const sai_object_meta_key_t& meta_key,
_In_ const sai_attribute_t *attr)
{
SWSS_LOG_ENTER();
if (attr == NULL)
{
SWSS_LOG_ERROR("attribute pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
if (mdp == NULL)
{
SWSS_LOG_ERROR("unable to find attribute metadata %s:%d",
sai_serialize_object_type(meta_key.objecttype).c_str(),
attr->id);
return SAI_STATUS_FAILURE;
}
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
META_LOG_DEBUG(md, "(set)");
if (SAI_HAS_FLAG_READ_ONLY(md.flags))
{
if (meta_unittests_get_and_erase_set_readonly_flag(md))
{
META_LOG_NOTICE(md, "readonly attribute is allowed to be set (unittests enabled)");
}
else
{
META_LOG_ERROR(md, "attr is read only and cannot be modified");
return SAI_STATUS_INVALID_PARAMETER;
}
}
if (SAI_HAS_FLAG_CREATE_ONLY(md.flags))
{
META_LOG_ERROR(md, "attr is create only and cannot be modified");
return SAI_STATUS_INVALID_PARAMETER;
}
if (SAI_HAS_FLAG_KEY(md.flags))
{
META_LOG_ERROR(md, "attr is key and cannot be modified");
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t switch_id = SAI_NULL_OBJECT_ID;
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (!info->isnonobjectid)
{
switch_id = switchIdQuery(meta_key.objectkey.key.object_id);
if (!m_oids.objectReferenceExists(switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist", switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
}
switch_id = meta_extract_switch_id(meta_key, switch_id);
// if we set OID check if exists and if type is correct
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_POINTER:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_CHARDATA:
{
size_t len = strnlen(value.chardata, sizeof(sai_attribute_value_t::chardata)/sizeof(char));
// for some attributes, length can be zero
for (size_t i = 0; i < len; ++i)
{
char c = value.chardata[i];
if (c < 0x20 || c > 0x7e)
{
META_LOG_ERROR(md, "invalid character 0x%02x in chardata", c);
return SAI_STATUS_INVALID_PARAMETER;
}
}
break;
}
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
{
switch (value.ipaddr.addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid address family: %d", value.ipaddr.addr_family);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
}
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
{
if (md.objecttype == SAI_OBJECT_TYPE_SCHEDULER_GROUP &&
md.attrid == SAI_SCHEDULER_GROUP_ATTR_SCHEDULER_PROFILE_ID &&
value.oid == SAI_NULL_OBJECT_ID)
{
// XXX workaround, since this profile can't be NULL according to metadata,
// but currently on mlnx2700 null can be set, need verify and fix
break;
}
sai_status_t status = meta_generic_validation_objlist(md, switch_id, 1, &value.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
{
sai_status_t status = meta_generic_validation_objlist(md, switch_id, value.objlist.count, value.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
{
if (!value.aclfield.enable)
{
break;
}
sai_status_t status = meta_generic_validation_objlist(md, switch_id, 1, &value.aclfield.data.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
{
if (!value.aclfield.enable)
{
break;
}
sai_status_t status = meta_generic_validation_objlist(md, switch_id, value.aclfield.data.objlist.count, value.aclfield.data.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
{
if (!value.aclaction.enable)
{
break;
}
sai_status_t status = meta_generic_validation_objlist(md, switch_id, 1, &value.aclaction.parameter.oid);
CHECK_STATUS_SUCCESS(status)
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
{
if (!value.aclaction.enable)
{
break;
}
sai_status_t status = meta_generic_validation_objlist(md, switch_id, value.aclaction.parameter.objlist.count, value.aclaction.parameter.objlist.list);
CHECK_STATUS_SUCCESS(status)
break;
}
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
VALIDATION_LIST(md, value.u8list);
break;
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
VALIDATION_LIST(md, value.s8list);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
VALIDATION_LIST(md, value.u16list);
break;
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
VALIDATION_LIST(md, value.s16list);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
VALIDATION_LIST(md, value.u32list);
break;
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
VALIDATION_LIST(md, value.s32list);
break;
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
VALIDATION_LIST(md, value.qosmap);
break;
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
VALIDATION_LIST(md, value.maplist);
break;
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
VALIDATION_LIST(md, value.aclresource);
break;
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
VALIDATION_LIST(md, value.ipaddrlist);
break;
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
VALIDATION_LIST(md, value.segmentlist);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
VALIDATION_LIST(md, value.u16rangelist);
for (uint32_t i = 0; i < value.u16rangelist.count; i++) {
if (value.u16rangelist.list[i].min > value.u16rangelist.list[i].max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u16rangelist.list[i].min, value.u16rangelist.list[i].max);
return SAI_STATUS_INVALID_PARAMETER;
}
}
break;
case SAI_ATTR_VALUE_TYPE_JSON:
VALIDATION_LIST(md, value.json.json);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
if (value.u32range.min > value.u32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u32range.min, value.u32range.max);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
if (value.s32range.min > value.s32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.s32range.min, value.s32range.max);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
{
switch (value.ipprefix.addr_family)
{
case SAI_IP_ADDR_FAMILY_IPV4:
case SAI_IP_ADDR_FAMILY_IPV6:
break;
default:
SWSS_LOG_ERROR("invalid address family: %d", value.ipprefix.addr_family);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY:
VALIDATION_LIST(md, value.aclcapability.action_list);
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
VALIDATION_LIST(md, value.sysportconfiglist);
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
VALIDATION_LIST(md, value.ipprefixlist);
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
if (md.isenum)
{
int32_t val = value.s32;
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
val = value.aclfield.data.s32;
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
val = value.aclaction.parameter.s32;
break;
default:
val = value.s32;
break;
}
if (!sai_metadata_is_allowed_enum_value(&md, val))
{
META_LOG_ERROR(md, "is enum, but value %d not found on allowed values list", val);
return SAI_STATUS_INVALID_PARAMETER;
}
}
if (md.isenumlist)
{
// we allow repeats on enum list
if (value.s32list.count != 0 && value.s32list.list == NULL)
{
META_LOG_ERROR(md, "enum list is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
for (uint32_t i = value.s32list.count; i < value.s32list.count; ++i)
{
int32_t s32 = value.s32list.list[i];
if (!sai_metadata_is_allowed_enum_value(&md, s32))
{
SWSS_LOG_ERROR("is enum list, but value %d not found on allowed values list", s32);
return SAI_STATUS_INVALID_PARAMETER;
}
}
}
if (md.isconditional)
{
// check if it was set on local DB
// (this will not respect create_only with default)
if (get_object_previous_attr(meta_key, md) == NULL)
{
META_LOG_WARN(md, "set for conditional, but not found in local db, object %s created on switch ?",
sai_serialize_object_meta_key(meta_key).c_str());
}
else
{
META_LOG_DEBUG(md, "conditional attr found in local db");
}
META_LOG_DEBUG(md, "conditional attr found in local db");
}
// check if object on which we perform operation exists
if (!m_saiObjectCollection.objectExists(meta_key))
{
META_LOG_ERROR(md, "object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
// object exists in DB so we can do "set" operation
if (info->isnonobjectid)
{
SWSS_LOG_DEBUG("object key exists: %s",
sai_serialize_object_meta_key(meta_key).c_str());
}
else
{
/*
* Check if object we are calling SET is the same object type as the
* type of SET function.
*/
sai_object_id_t oid = meta_key.objectkey.key.object_id;
sai_object_type_t object_type = objectTypeQuery(oid);
if (object_type == SAI_NULL_OBJECT_ID)
{
META_LOG_ERROR(md, "oid 0x%" PRIx64 " is not valid, returned null object id", oid);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != meta_key.objecttype)
{
META_LOG_ERROR(md, "oid 0x%" PRIx64 " type %d is not accepted, expected object type %d", oid, object_type, meta_key.objecttype);
return SAI_STATUS_INVALID_PARAMETER;
}
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_generic_validation_get(
_In_ const sai_object_meta_key_t& meta_key,
_In_ const uint32_t attr_count,
_In_ sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
if (attr_count < 1)
{
SWSS_LOG_ERROR("expected at least 1 attribute when calling get, zero given");
return SAI_STATUS_INVALID_PARAMETER;
}
if (attr_count > MAX_LIST_COUNT)
{
SWSS_LOG_ERROR("get attribute count %u > max list count %u", attr_count, MAX_LIST_COUNT);
return SAI_STATUS_INVALID_PARAMETER;
}
if (attr_list == NULL)
{
SWSS_LOG_ERROR("attribute list pointer is NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
SWSS_LOG_DEBUG("attr count = %u", attr_count);
for (uint32_t i = 0; i < attr_count; ++i)
{
const sai_attribute_t* attr = &attr_list[i];
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
if (mdp == NULL)
{
SWSS_LOG_ERROR("unable to find attribute metadata %s:%d",
sai_serialize_object_type(meta_key.objecttype).c_str(),
attr->id);
return SAI_STATUS_FAILURE;
}
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
META_LOG_DEBUG(md, "(get)");
if (md.isconditional)
{
/*
* XXX workaround
*
* TODO If object was created internally by switch (like bridge
* port) then current db will not have previous value of this
* attribute (like SAI_BRIDGE_PORT_ATTR_PORT_ID) or even other oid.
* This can lead to inconsistency, that we queried one oid, and its
* attribute also oid, and then did a "set" on that value, and now
* reference is not decreased since previous oid was not snooped.
*
* TODO This concern all attributes not only conditionals
*
* If attribute is conditional, we need to check if condition is
* met, if not then this attribute is not mandatory so we can
* return fail in that case, for that we need all internal
* switch objects after create.
*/
// check if it was set on local DB
// (this will not respect create_only with default)
if (get_object_previous_attr(meta_key, md) == NULL)
{
// XXX produces too much noise
// META_LOG_WARN(md, "get for conditional, but not found in local db, object %s created on switch ?",
// sai_serialize_object_meta_key(meta_key).c_str());
}
else
{
META_LOG_DEBUG(md, "conditional attr found in local db");
}
}
/*
* When GET api is performed, later on same methods serialize/deserialize
* are used for create/set/get apis. User may not clear input attributes
* buffer (since it is in/out for example for lists) and in case of
* values that are validated like "enum" it will try to find best
* match for enum, and if not found, it will print warning message.
*
* In this place we can clear user buffer, so when it will go to
* serialize method it will pick first enum on the list.
*
* For primitive attributes we could just set entire attribute value to zero.
*/
if (md.isenum)
{
attr_list[i].value.s32 = 0;
}
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_CHARDATA:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
case SAI_ATTR_VALUE_TYPE_POINTER:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
VALIDATION_LIST(md, value.objlist);
break;
case SAI_ATTR_VALUE_TYPE_VLAN_LIST:
{
if (value.vlanlist.count == 0 && value.vlanlist.list != NULL)
{
META_LOG_ERROR(md, "vlan list count is zero, but list not NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
if (value.vlanlist.count != 0 && value.vlanlist.list == NULL)
{
META_LOG_ERROR(md, "vlan list count is %u, but list is NULL", value.vlanlist.count);
return SAI_STATUS_INVALID_PARAMETER;
}
if (value.vlanlist.count > MAXIMUM_VLAN_NUMBER)
{
META_LOG_ERROR(md, "vlan count is too big %u > %u", value.vlanlist.count, MAXIMUM_VLAN_NUMBER);
return SAI_STATUS_INVALID_PARAMETER;
}
break;
}
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
VALIDATION_LIST(md, value.aclfield.data.objlist);
break;
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
VALIDATION_LIST(md, value.aclaction.parameter.objlist);
break;
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
VALIDATION_LIST(md, value.u8list);
break;
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
VALIDATION_LIST(md, value.s8list);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
VALIDATION_LIST(md, value.u16list);
break;
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
VALIDATION_LIST(md, value.s16list);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
VALIDATION_LIST(md, value.u32list);
break;
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
VALIDATION_LIST(md, value.s32list);
break;
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
VALIDATION_LIST(md, value.qosmap);
break;
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
VALIDATION_LIST(md, value.maplist);
break;
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
VALIDATION_LIST(md, value.aclresource);
break;
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
VALIDATION_LIST(md, value.ipaddrlist);
break;
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
VALIDATION_LIST(md, value.segmentlist);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
VALIDATION_LIST(md, value.u16rangelist);
break;
case SAI_ATTR_VALUE_TYPE_JSON:
VALIDATION_LIST(md, value.json.json);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY:
VALIDATION_LIST(md, value.aclcapability.action_list);
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
VALIDATION_LIST(md, value.sysportconfiglist);
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
VALIDATION_LIST(md, value.ipprefixlist);
break;
default:
// acl capability will is more complex since is in/out we need to check stage
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
}
if (!m_saiObjectCollection.objectExists(meta_key))
{
SWSS_LOG_ERROR("object key %s doesn't exist",
sai_serialize_object_meta_key(meta_key).c_str());
return SAI_STATUS_ITEM_NOT_FOUND;
}
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
SWSS_LOG_DEBUG("object key exists: %s",
sai_serialize_object_meta_key(meta_key).c_str());
}
else
{
/*
* Check if object we are calling GET is the same object type as the
* type of GET function.
*/
sai_object_id_t oid = meta_key.objectkey.key.object_id;
sai_object_type_t object_type = objectTypeQuery(oid);
if (object_type == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " is not valid, returned null object id", oid);
return SAI_STATUS_INVALID_PARAMETER;
}
if (object_type != meta_key.objecttype)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " type %d is not accepted, expected object type %d", oid, object_type, meta_key.objecttype);
return SAI_STATUS_INVALID_PARAMETER;
}
}
// object exists in DB so we can do "get" operation
return SAI_STATUS_SUCCESS;
}
void Meta::meta_generic_validation_post_get(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id,
_In_ const uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
switch_id = meta_extract_switch_id(meta_key, switch_id);
/*
* TODO We should snoop attributes retrieved from switch and put them to
* local db if they don't exist since if attr is oid it may lead to
* inconsistency when counting reference
*/
for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t* attr = &attr_list[idx];
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_CHARDATA:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_POINTER:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
// primitives, ok
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, 1, &value.oid);
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, value.objlist.count, value.objlist.list);
break;
case SAI_ATTR_VALUE_TYPE_VLAN_LIST:
{
uint32_t count = value.vlanlist.count;
if (count > MAXIMUM_VLAN_NUMBER)
{
META_LOG_ERROR(md, "too many vlans returned on vlan list (vendor bug?)");
}
if (value.vlanlist.list == NULL)
{
break;
}
for (uint32_t i = 0; i < count; ++i)
{
uint16_t vlanid = value.vlanlist.list[i];
if (vlanid < MINIMUM_VLAN_NUMBER || vlanid > MAXIMUM_VLAN_NUMBER)
{
META_LOG_ERROR(md, "vlan id %u is outside range, but returned on list [%u]", vlanid, i);
}
}
break;
}
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (value.aclfield.enable)
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, 1, &value.aclfield.data.oid);
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (value.aclfield.enable)
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, value.aclfield.data.objlist.count, value.aclfield.data.objlist.list);
break;
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST: (2 lists)
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (value.aclaction.enable)
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, 1, &value.aclaction.parameter.oid);
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (value.aclaction.enable)
meta_generic_validation_post_get_objlist(meta_key, md, switch_id, value.aclaction.parameter.objlist.count, value.aclaction.parameter.objlist.list);
break;
case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY:
VALIDATION_LIST_GET(md, value.aclcapability.action_list);
break;
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
VALIDATION_LIST_GET(md, value.u8list);
break;
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
VALIDATION_LIST_GET(md, value.s8list);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
VALIDATION_LIST_GET(md, value.u16list);
break;
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
VALIDATION_LIST_GET(md, value.s16list);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
VALIDATION_LIST_GET(md, value.u32list);
break;
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
VALIDATION_LIST_GET(md, value.s32list);
break;
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
VALIDATION_LIST_GET(md, value.qosmap);
break;
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
VALIDATION_LIST_GET(md, value.maplist);
break;
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
VALIDATION_LIST_GET(md, value.aclresource);
break;
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
VALIDATION_LIST_GET(md, value.ipaddrlist);
break;
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
VALIDATION_LIST_GET(md, value.segmentlist);
break;
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
VALIDATION_LIST_GET(md, value.u16rangelist);
for (uint32_t i = 0; i < value.u16rangelist.count; i++) {
if (value.u16rangelist.list[i].min > value.u16rangelist.list[i].max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u16rangelist.list[i].min, value.u16rangelist.list[i].max);
}
}
break;
case SAI_ATTR_VALUE_TYPE_JSON:
VALIDATION_LIST_GET(md, value.json.json);
break;
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
if (value.u32range.min > value.u32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.u32range.min, value.u32range.max);
}
break;
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
if (value.s32range.min > value.s32range.max)
{
META_LOG_ERROR(md, "invalid range %u .. %u", value.s32range.min, value.s32range.max);
}
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
VALIDATION_LIST_GET(md, value.sysportconfiglist);
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
VALIDATION_LIST_GET(md, value.ipprefixlist);
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
if (md.isenum)
{
int32_t val = value.s32;
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
val = value.aclfield.data.s32;
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
val = value.aclaction.parameter.s32;
break;
default:
val = value.s32;
break;
}
if (!sai_metadata_is_allowed_enum_value(&md, val))
{
META_LOG_ERROR(md, "is enum, but value %d not found on allowed values list", val);
continue;
}
}
if (md.isenumlist)
{
if (value.s32list.list == NULL)
{
continue;
}
for (uint32_t i = value.s32list.count; i < value.s32list.count; ++i)
{
int32_t s32 = value.s32list.list[i];
if (!sai_metadata_is_allowed_enum_value(&md, s32))
{
META_LOG_ERROR(md, "is enum list, but value %d not found on allowed values list", s32);
}
}
}
}
if (meta_key.objecttype == SAI_OBJECT_TYPE_PORT)
{
meta_post_port_get(meta_key, switch_id, attr_count, attr_list);
}
}
sai_status_t Meta::meta_generic_validation_objlist(
_In_ const sai_attr_metadata_t& md,
_In_ sai_object_id_t switch_id,
_In_ uint32_t count,
_In_ const sai_object_id_t* list)
{
SWSS_LOG_ENTER();
if (count > MAX_LIST_COUNT)
{
META_LOG_ERROR(md, "object list count %u > max list count %u", count, MAX_LIST_COUNT);
return SAI_STATUS_INVALID_PARAMETER;
}
if (list == NULL)
{
if (count == 0)
{
return SAI_STATUS_SUCCESS;
}
META_LOG_ERROR(md, "object list is null, but count is %u", count);
return SAI_STATUS_INVALID_PARAMETER;
}
/*
* We need oids set and object type to check whether oids are not repeated
* on list and whether all oids are same object type.
*/
std::set<sai_object_id_t> oids;
sai_object_type_t object_type = SAI_OBJECT_TYPE_NULL;
for (uint32_t i = 0; i < count; ++i)
{
sai_object_id_t oid = list[i];
if (oids.find(oid) != oids.end())
{
META_LOG_ERROR(md, "object on list [%u] oid 0x%" PRIx64 " is duplicated, but not allowed", i, oid);
return SAI_STATUS_INVALID_PARAMETER;
}
if (oid == SAI_NULL_OBJECT_ID)
{
if (md.allownullobjectid)
{
// ok, null object is allowed
continue;
}
META_LOG_ERROR(md, "object on list [%u] is NULL, but not allowed", i);
return SAI_STATUS_INVALID_PARAMETER;
}
oids.insert(oid);
sai_object_type_t ot = objectTypeQuery(oid);
if (ot == SAI_NULL_OBJECT_ID)
{
META_LOG_ERROR(md, "object on list [%u] oid 0x%" PRIx64 " is not valid, returned null object id", i, oid);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!sai_metadata_is_allowed_object_type(&md, ot))
{
META_LOG_ERROR(md, "object on list [%u] oid 0x%" PRIx64 " object type %d is not allowed on this attribute", i, oid, ot);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!m_oids.objectReferenceExists(oid))
{
META_LOG_ERROR(md, "object on list [%u] oid 0x%" PRIx64 " object type %d does not exists in local DB", i, oid, ot);
return SAI_STATUS_INVALID_PARAMETER;
}
if (i > 1)
{
/*
* Currently all objects on list must be the same type.
*/
if (object_type != ot)
{
META_LOG_ERROR(md, "object list contain's mixed object types: %d vs %d, not allowed", object_type, ot);
return SAI_STATUS_INVALID_PARAMETER;
}
}
sai_object_id_t query_switch_id = switchIdQuery(oid);
if (!m_oids.objectReferenceExists(query_switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist", query_switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (query_switch_id != switch_id)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " is from switch 0x%" PRIx64 " but expected switch 0x%" PRIx64 "", oid, query_switch_id, switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
object_type = ot;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_genetic_validation_list(
_In_ const sai_attr_metadata_t& md,
_In_ uint32_t count,
_In_ const void* list)
{
SWSS_LOG_ENTER();
if (count > MAX_LIST_COUNT)
{
META_LOG_ERROR(md, "list count %u > max list count %u", count, MAX_LIST_COUNT);
return SAI_STATUS_INVALID_PARAMETER;
}
if (count == 0 && list != NULL)
{
META_LOG_ERROR(md, "when count is zero, list must be NULL");
return SAI_STATUS_INVALID_PARAMETER;
}
if (list == NULL)
{
if (count == 0)
{
return SAI_STATUS_SUCCESS;
}
META_LOG_ERROR(md, "list is null, but count is %u", count);
return SAI_STATUS_INVALID_PARAMETER;
}
return SAI_STATUS_SUCCESS;
}
sai_status_t Meta::meta_generic_validate_non_object_on_create(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id)
{
SWSS_LOG_ENTER();
/*
* Since non object id objects can contain several object id's inside
* object id structure, we need to check whether they all belong to the
* same switch (sine multiple switches can be present and whether all those
* objects are allowed respectively on their members.
*
* This check is required only on creation, since on set/get/remove we
* check in object hash whether this object exists.
*/
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (!info->isnonobjectid)
{
return SAI_STATUS_SUCCESS;
}
/*
* This will be most utilized for creating route entries.
*/
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
sai_object_id_t oid = m->getoid(&meta_key);
if (oid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("oid on %s on struct member %s is NULL",
sai_serialize_object_type(meta_key.objecttype).c_str(),
m->membername);
return SAI_STATUS_INVALID_PARAMETER;
}
if (!m_oids.objectReferenceExists(oid))
{
SWSS_LOG_ERROR("object don't exist %s (%s)",
sai_serialize_object_id(oid).c_str(),
m->membername);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_type_t ot = objectTypeQuery(oid);
/*
* No need for checking null here, since metadata don't allow
* NULL in allowed objects list.
*/
bool allowed = false;
for (size_t k = 0 ; k < m->allowedobjecttypeslength; k++)
{
if (ot == m->allowedobjecttypes[k])
{
allowed = true;
break;
}
}
if (!allowed)
{
SWSS_LOG_ERROR("object id 0x%" PRIx64 " is %s, but it's not allowed on member %s",
oid, sai_serialize_object_type(ot).c_str(), m->membername);
return SAI_STATUS_INVALID_PARAMETER;
}
sai_object_id_t oid_switch_id = switchIdQuery(oid);
if (!m_oids.objectReferenceExists(oid_switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist", oid_switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
if (switch_id != oid_switch_id)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " is on switch 0x%" PRIx64 " but required switch is 0x%" PRIx64 "", oid, oid_switch_id, switch_id);
return SAI_STATUS_INVALID_PARAMETER;
}
}
return SAI_STATUS_SUCCESS;
}
sai_object_id_t Meta::meta_extract_switch_id(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id)
{
SWSS_LOG_ENTER();
/*
* We assume here that objecttype in meta key is in valid range.
*/
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
/*
* Since object is non object id, we are sure via sanity check that
* struct member contains switch_id, we need to extract it here.
*
* NOTE: we could have this in metadata predefined for all non object ids.
*
* NOTE: first field in every entry is switch id
*/
return meta_key.objectkey.key.object_id;
}
else
{
// NOTE: maybe we should extract switch from oid?
return switch_id;
}
}
std::shared_ptr<SaiAttrWrapper> Meta::get_object_previous_attr(
_In_ const sai_object_meta_key_t& metaKey,
_In_ const sai_attr_metadata_t& md)
{
SWSS_LOG_ENTER();
return m_saiObjectCollection.getObjectAttr(metaKey, md.attrid);
}
std::vector<const sai_attr_metadata_t*> Meta::get_attributes_metadata(
_In_ sai_object_type_t objecttype)
{
SWSS_LOG_ENTER();
SWSS_LOG_DEBUG("objecttype: %s", sai_serialize_object_type(objecttype).c_str());
auto meta = sai_metadata_get_object_type_info(objecttype)->attrmetadata;
std::vector<const sai_attr_metadata_t*> attrs;
for (size_t index = 0; meta[index] != NULL; ++index)
{
attrs.push_back(meta[index]);
}
return attrs;
}
void Meta::meta_post_port_get(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id,
_In_ const uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
/*
* User may or may not query one of below attributes to get some port
* objects, and those objects are special since when user decide to remove
* port, then those object will be removed automatically by vendor SAI, and
* this action needs to be reflected here too, so if user will remove port,
* those objects would need to be remove from local database too.
*
* TODO: There will be issue here, since we need to know which of those
* objects are user created, for example if user will create some extra
* queues with specific port, and then query queues list, those extra
* queues would need to be explicitly removed first by user, otherwise this
* logic here will also consider those user created queues as switch
* default, and it will remove them when port will be removed. Such action
* should be prevented.
*/
const sai_object_id_t port_id = meta_key.objectkey.key.object_id;
for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t& attr = attr_list[idx];
auto& md = *sai_metadata_get_attr_metadata(meta_key.objecttype, attr.id);
switch (md.attrid)
{
case SAI_PORT_ATTR_QOS_QUEUE_LIST:
case SAI_PORT_ATTR_QOS_SCHEDULER_GROUP_LIST:
case SAI_PORT_ATTR_INGRESS_PRIORITY_GROUP_LIST:
meta_add_port_to_related_map(port_id, attr.value.objlist);
break;
default:
break;
}
}
}
void Meta::meta_add_port_to_related_map(
_In_ sai_object_id_t port_id,
_In_ const sai_object_list_t& list)
{
SWSS_LOG_ENTER();
for (uint32_t i = 0; i < list.count; i++)
{
sai_object_id_t rel = list.list[i];
if (rel == SAI_NULL_OBJECT_ID)
SWSS_LOG_THROW("not expected NULL oid on the list");
m_portRelatedSet.insert(port_id, rel);
}
}
void Meta::meta_generic_validation_post_get_objlist(
_In_ const sai_object_meta_key_t& meta_key,
_In_ const sai_attr_metadata_t& md,
_In_ sai_object_id_t switch_id,
_In_ uint32_t count,
_In_ const sai_object_id_t* list)
{
SWSS_LOG_ENTER();
/*
* TODO This is not good enough when object was created by switch
* internally and it have oid attributes, we need to insert them to local
* db and increase reference count if object don't exist.
*
* Also this function maybe not best place to do it since it's not executed
* when we doing get on acl field/action. But none of those are created
* internally by switch.
*
* TODO Similar stuff is with SET, when we will set oid object on existing
* switch object, but we will not have it's previous value. We can check
* whether default value is present and it's const NULL.
*/
if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.isoidattribute)
{
if (get_object_previous_attr(meta_key, md) == NULL)
{
// XXX produces too much noise
// META_LOG_WARN(md, "post get, not in local db, FIX snoop!: %s",
// sai_serialize_object_meta_key(meta_key).c_str());
}
}
if (count > MAX_LIST_COUNT)
{
META_LOG_ERROR(md, "returned get object list count %u > max list count %u", count, MAX_LIST_COUNT);
}
if (list == NULL)
{
// query was for length
return;
}
std::set<sai_object_id_t> oids;
for (uint32_t i = 0; i < count; ++i)
{
sai_object_id_t oid = list[i];
if (oids.find(oid) != oids.end())
{
META_LOG_ERROR(md, "returned get object on list [%u] is duplicated, but not allowed", i);
continue;
}
oids.insert(oid);
if (oid == SAI_NULL_OBJECT_ID)
{
if (md.allownullobjectid)
{
// ok, null object is allowed
continue;
}
META_LOG_ERROR(md, "returned get object on list [%u] is NULL, but not allowed", i);
continue;
}
sai_object_type_t ot = objectTypeQuery(oid);
if (ot == SAI_OBJECT_TYPE_NULL)
{
META_LOG_ERROR(md, "returned get object on list [%u] oid 0x%" PRIx64 " is not valid, returned null object type", i, oid);
continue;
}
if (!sai_metadata_is_allowed_object_type(&md, ot))
{
META_LOG_ERROR(md, "returned get object on list [%u] oid 0x%" PRIx64 " object type %d is not allowed on this attribute", i, oid, ot);
}
if (!m_oids.objectReferenceExists(oid))
{
// NOTE: there may happen that user will request multiple object lists
// and first list was retrieved ok, but second failed with overflow
// then we may forget to snoop
META_LOG_INFO(md, "returned get object on list [%u] oid 0x%" PRIx64 " object type %d does not exists in local DB (snoop)", i, oid, ot);
sai_object_meta_key_t key = { .objecttype = ot, .objectkey = { .key = { .object_id = oid } } };
m_oids.objectReferenceInsert(oid);
if (!m_saiObjectCollection.objectExists(key))
{
m_saiObjectCollection.createObject(key);
// TODO on post get on attribute, if snoop should we increase reference if not read_only ?
}
}
sai_object_id_t query_switch_id = switchIdQuery(oid);
if (!m_oids.objectReferenceExists(query_switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist", query_switch_id);
}
if (query_switch_id != switch_id)
{
SWSS_LOG_ERROR("oid 0x%" PRIx64 " is from switch 0x%" PRIx64 " but expected switch 0x%" PRIx64 "", oid, query_switch_id, switch_id);
}
}
}
// TODO move to metadata utils
bool Meta::is_ipv6_mask_valid(
_In_ const uint8_t* mask)
{
SWSS_LOG_ENTER();
if (mask == NULL)
{
SWSS_LOG_ERROR("mask is null");
return false;
}
int ones = 0;
bool zeros = false;
for (uint8_t i = 0; i < 128; i++)
{
bool bit = mask[i/8] & (1 << (7 - (i%8)));
if (zeros && bit)
{
return false;
}
zeros |= !bit;
if (bit)
{
ones++;
}
}
return true;
}
void Meta::meta_generic_validation_post_create(
_In_ const sai_object_meta_key_t& meta_key,
_In_ sai_object_id_t switch_id,
_In_ const uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
SWSS_LOG_ENTER();
bool connectToSwitch = false;
if (meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
auto attr = sai_metadata_get_attr_by_id(SAI_SWITCH_ATTR_INIT_SWITCH, attr_count, attr_list);
if (attr && attr->value.booldata == false)
{
SWSS_LOG_NOTICE("connecting to existing switch %s",
sai_serialize_object_id(switch_id).c_str());
connectToSwitch = true;
}
}
if (m_saiObjectCollection.objectExists(meta_key))
{
if (m_warmBoot && meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_NOTICE("post switch create after WARM BOOT");
}
else if (connectToSwitch)
{
// ok, object already exists since we are connecting to existing switch
}
else
{
SWSS_LOG_ERROR("object key %s already exists (vendor bug?)",
sai_serialize_object_meta_key(meta_key).c_str());
// this may produce inconsistency
}
}
if (m_warmBoot && meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_NOTICE("skipping create switch on WARM BOOT since it was already created");
}
else if (connectToSwitch)
{
// don't create object, since it already exists and we are connecting to existing switch
}
else
{
m_saiObjectCollection.createObject(meta_key);
}
auto info = sai_metadata_get_object_type_info(meta_key.objecttype);
if (info->isnonobjectid)
{
/*
* Increase object reference count for all object ids in non object id
* members.
*/
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
m_oids.objectReferenceIncrement(m->getoid(&meta_key));
}
}
else
{
/*
* Check if object created was expected type as the type of CRATE
* function.
*/
do
{
sai_object_id_t oid = meta_key.objectkey.key.object_id;
if (oid == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("created oid is null object id (vendor bug?)");
break;
}
sai_object_type_t object_type = objectTypeQuery(oid);
if (object_type == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("created oid 0x%" PRIx64 " is not valid object type after create (null) (vendor bug?)", oid);
break;
}
if (object_type != meta_key.objecttype)
{
SWSS_LOG_ERROR("created oid 0x%" PRIx64 " type %s, expected %s (vendor bug?)",
oid,
sai_serialize_object_type(object_type).c_str(),
sai_serialize_object_type(meta_key.objecttype).c_str());
break;
}
if (meta_key.objecttype != SAI_OBJECT_TYPE_SWITCH)
{
/*
* Check if created object switch is the same as input switch.
*/
sai_object_id_t query_switch_id = switchIdQuery(meta_key.objectkey.key.object_id);
if (!m_oids.objectReferenceExists(query_switch_id))
{
SWSS_LOG_ERROR("switch id 0x%" PRIx64 " doesn't exist", query_switch_id);
break;
}
if (switch_id != query_switch_id)
{
SWSS_LOG_ERROR("created oid 0x%" PRIx64 " switch id 0x%" PRIx64 " is different than requested 0x%" PRIx64 "",
oid, query_switch_id, switch_id);
break;
}
}
if (m_warmBoot && meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_NOTICE("skip insert switch reference insert in WARM_BOOT");
}
else if (connectToSwitch)
{
// don't create object reference, since we are connecting to existing switch
}
else
{
m_oids.objectReferenceInsert(oid);
}
} while (false);
}
if (m_warmBoot)
{
SWSS_LOG_NOTICE("m_warmBoot = false");
m_warmBoot = false;
}
bool haskeys = false;
for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t* attr = &attr_list[idx];
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
if (SAI_HAS_FLAG_KEY(md.flags))
{
haskeys = true;
META_LOG_DEBUG(md, "attr is key");
}
// increase reference on object id types
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_CHARDATA:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
case SAI_ATTR_VALUE_TYPE_POINTER:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
m_oids.objectReferenceIncrement(value.oid);
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
m_oids.objectReferenceIncrement(value.objlist);
break;
case SAI_ATTR_VALUE_TYPE_VLAN_LIST:
break;
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT64:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (value.aclfield.enable)
{
m_oids.objectReferenceIncrement(value.aclfield.data.oid);
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (value.aclfield.enable)
{
m_oids.objectReferenceIncrement(value.aclfield.data.objlist);
}
break;
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (value.aclaction.enable)
{
m_oids.objectReferenceIncrement(value.aclaction.parameter.oid);
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (value.aclaction.enable)
{
m_oids.objectReferenceIncrement(value.aclaction.parameter.objlist);
}
break;
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
case SAI_ATTR_VALUE_TYPE_JSON:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_MACSEC_SAK:
case SAI_ATTR_VALUE_TYPE_MACSEC_AUTH_KEY:
case SAI_ATTR_VALUE_TYPE_MACSEC_SALT:
case SAI_ATTR_VALUE_TYPE_MACSEC_SCI:
case SAI_ATTR_VALUE_TYPE_MACSEC_SSCI:
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
// no special action required
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
m_saiObjectCollection.setObjectAttr(meta_key, md, attr);
}
if (haskeys)
{
auto mKey = sai_serialize_object_meta_key(meta_key);
auto attrKey = AttrKeyMap::constructKey(switch_id, meta_key, attr_count, attr_list);
m_attrKeys.insert(mKey, attrKey);
}
}
void Meta::meta_generic_validation_post_set(
_In_ const sai_object_meta_key_t& meta_key,
_In_ const sai_attribute_t *attr)
{
SWSS_LOG_ENTER();
auto mdp = sai_metadata_get_attr_metadata(meta_key.objecttype, attr->id);
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
/*
* TODO We need to get previous value and make deal with references, check
* if there is default value and if it's const.
*/
if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.isoidattribute)
{
if ((get_object_previous_attr(meta_key, md) == NULL) &&
(md.defaultvaluetype != SAI_DEFAULT_VALUE_TYPE_CONST &&
md.defaultvaluetype != SAI_DEFAULT_VALUE_TYPE_EMPTY_LIST))
{
/*
* If default value type will be internal then we should warn.
*/
// XXX produces too much noise
// META_LOG_WARN(md, "post set, not in local db, FIX snoop!: %s",
// sai_serialize_object_meta_key(meta_key).c_str());
}
}
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
case SAI_ATTR_VALUE_TYPE_CHARDATA:
case SAI_ATTR_VALUE_TYPE_UINT8:
case SAI_ATTR_VALUE_TYPE_INT8:
case SAI_ATTR_VALUE_TYPE_UINT16:
case SAI_ATTR_VALUE_TYPE_INT16:
case SAI_ATTR_VALUE_TYPE_UINT32:
case SAI_ATTR_VALUE_TYPE_INT32:
case SAI_ATTR_VALUE_TYPE_UINT64:
case SAI_ATTR_VALUE_TYPE_INT64:
case SAI_ATTR_VALUE_TYPE_MAC:
case SAI_ATTR_VALUE_TYPE_IPV4:
case SAI_ATTR_VALUE_TYPE_IPV6:
case SAI_ATTR_VALUE_TYPE_POINTER:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS:
case SAI_ATTR_VALUE_TYPE_IP_PREFIX:
// primitives, ok
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev != NULL)
{
// decrease previous if it was set
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.oid);
}
m_oids.objectReferenceIncrement(value.oid);
break;
}
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev != NULL)
{
// decrease previous if it was set
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.objlist);
}
m_oids.objectReferenceIncrement(value.objlist);
break;
}
// case SAI_ATTR_VALUE_TYPE_VLAN_LIST:
// will require increase vlan references
// ACL FIELD
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6:
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev)
{
// decrease previous if it was set
if (prev->getSaiAttr()->value.aclfield.enable)
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.aclfield.data.oid);
}
if (value.aclfield.enable)
m_oids.objectReferenceIncrement(value.aclfield.data.oid);
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev)
{
// decrease previous if it was set
if (prev->getSaiAttr()->value.aclfield.enable)
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.aclfield.data.objlist);
}
if (value.aclfield.enable)
m_oids.objectReferenceIncrement(value.aclfield.data.objlist);
break;
}
// case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST:
// ACL ACTION
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4:
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6:
// primitives
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev)
{
// decrease previous if it was set
if (prev->getSaiAttr()->value.aclaction.enable)
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.aclaction.parameter.oid);
}
if (value.aclaction.enable)
m_oids.objectReferenceIncrement(value.aclaction.parameter.oid);
break;
}
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
{
auto prev = get_object_previous_attr(meta_key, md);
if (prev)
{
// decrease previous if it was set
if (prev->getSaiAttr()->value.aclaction.enable)
m_oids.objectReferenceDecrement(prev->getSaiAttr()->value.aclaction.parameter.objlist);
}
if (value.aclaction.enable)
m_oids.objectReferenceIncrement(value.aclaction.parameter.objlist);
break;
}
// ACL END
case SAI_ATTR_VALUE_TYPE_UINT8_LIST:
case SAI_ATTR_VALUE_TYPE_INT8_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_LIST:
case SAI_ATTR_VALUE_TYPE_INT16_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_LIST:
case SAI_ATTR_VALUE_TYPE_INT32_LIST:
case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_MAP_LIST:
case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST:
case SAI_ATTR_VALUE_TYPE_UINT32_RANGE:
case SAI_ATTR_VALUE_TYPE_INT32_RANGE:
case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST:
case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY:
case SAI_ATTR_VALUE_TYPE_SEGMENT_LIST:
case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST:
case SAI_ATTR_VALUE_TYPE_JSON:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG:
case SAI_ATTR_VALUE_TYPE_SYSTEM_PORT_CONFIG_LIST:
// no special action required
break;
case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST:
// no special action required
break;
default:
META_LOG_THROW(md, "serialization type is not supported yet FIXME");
}
// only on create we need to increase entry object types members
// save actual attributes and values to local db
m_saiObjectCollection.setObjectAttr(meta_key, md, attr);
}
bool Meta::meta_unittests_get_and_erase_set_readonly_flag(
_In_ const sai_attr_metadata_t& md)
{
SWSS_LOG_ENTER();
if (!m_unittestsEnabled)
{
// explicitly to not produce false alarms
SWSS_LOG_NOTICE("unittests are not enabled");
return false;
}
const auto &it = m_meta_unittests_set_readonly_set.find(md.attridname);
if (it == m_meta_unittests_set_readonly_set.end())
{
SWSS_LOG_ERROR("%s is not present in readonly set", md.attridname);
return false;
}
SWSS_LOG_INFO("%s is present in readonly set, erasing", md.attridname);
m_meta_unittests_set_readonly_set.erase(it);
return true;
}
void Meta::meta_unittests_enable(
_In_ bool enable)
{
SWSS_LOG_ENTER();
m_unittestsEnabled = enable;
}
bool Meta::meta_unittests_enabled()
{
SWSS_LOG_ENTER();
return m_unittestsEnabled;
}
sai_status_t Meta::meta_unittests_allow_readonly_set_once(
_In_ sai_object_type_t object_type,
_In_ int32_t attr_id)
{
SWSS_LOG_ENTER();
if (!m_unittestsEnabled)
{
SWSS_LOG_NOTICE("unittests are not enabled");
return SAI_STATUS_FAILURE;
}
auto *md = sai_metadata_get_attr_metadata(object_type, attr_id);
if (md == NULL)
{
SWSS_LOG_ERROR("failed to get metadata for object type %d and attr id %d", object_type, attr_id);
return SAI_STATUS_FAILURE;
}
if (!SAI_HAS_FLAG_READ_ONLY(md->flags))
{
SWSS_LOG_ERROR("attribute %s is not marked as READ_ONLY", md->attridname);
return SAI_STATUS_FAILURE;
}
m_meta_unittests_set_readonly_set.insert(md->attridname);
SWSS_LOG_INFO("enabling SET for readonly attribute: %s", md->attridname);
return SAI_STATUS_SUCCESS;
}
static const sai_mac_t zero_mac = { 0, 0, 0, 0, 0, 0 };
void Meta::meta_sai_on_fdb_flush_event_consolidated(
_In_ const sai_fdb_event_notification_data_t& data)
{
SWSS_LOG_ENTER();
SWSS_LOG_TIMER("fdb flush");
// since we don't keep objects by type, we need to scan via all objects
// and find fdb entries
// TODO on flush we need to respect switch id, and remove fdb entries only
// from selected switch when adding multiple switch support
auto bpid = sai_metadata_get_attr_by_id(SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID, data.attr_count, data.attr);
auto type = sai_metadata_get_attr_by_id(SAI_FDB_ENTRY_ATTR_TYPE, data.attr_count, data.attr);
if (type == NULL)
{
SWSS_LOG_ERROR("FATAL: fdb flush notification don't contain SAI_FDB_ENTRY_ATTR_TYPE attribute! bug!, no entries were flushed in local DB!");
return;
}
SWSS_LOG_NOTICE("processing consolidated fdb flush event of type: %s",
sai_metadata_get_fdb_entry_type_name((sai_fdb_entry_type_t)type->value.s32));
std::vector<sai_object_meta_key_t> toremove;
auto fdbEntries = m_saiObjectCollection.getObjectsByObjectType(SAI_OBJECT_TYPE_FDB_ENTRY);
for (auto& fdb: fdbEntries)
{
auto fdbTypeAttr = fdb->getAttr(SAI_FDB_ENTRY_ATTR_TYPE);
if (!fdbTypeAttr)
{
SWSS_LOG_ERROR("FATAL: missing SAI_FDB_ENTRY_ATTR_TYPE on %s! bug! skipping flush",
sai_serialize_object_meta_key(fdb->getMetaKey()).c_str());
continue;
}
if (fdbTypeAttr->getSaiAttr()->value.s32 != type->value.s32)
{
// entry type is not matching on this fdb entry
continue;
}
// only consider bridge port id if it's defined and value is not NULL
// since vendor can add this attribute to fdb_entry with NULL value
if (bpid != NULL && bpid->value.oid != SAI_NULL_OBJECT_ID)
{
auto bpidAttr = fdb->getAttr(SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID);
if (!bpidAttr)
{
// port is not defined for this fdb entry
continue;
}
if (bpidAttr->getSaiAttr()->value.oid != bpid->value.oid)
{
// bridge port is not matching this fdb entry
continue;
}
}
auto& meta_key_fdb = fdb->getMetaKey();
if (data.fdb_entry.bv_id != SAI_NULL_OBJECT_ID)
{
if (data.fdb_entry.bv_id != meta_key_fdb.objectkey.key.fdb_entry.bv_id)
{
// vlan/bridge id is not matching on this fdb entry
continue;
}
}
// this fdb entry is matching, removing
SWSS_LOG_INFO("removing %s", sai_serialize_object_meta_key(meta_key_fdb).c_str());
// since meta_generic_validation_post_remove also modifies m_saiObjectCollection
// we need to push this to a vector and remove in next loop
toremove.push_back(meta_key_fdb);
}
for (auto it = toremove.begin(); it != toremove.end(); ++it)
{
// remove selected objects
meta_generic_validation_post_remove(*it);
}
}
void Meta::meta_fdb_event_snoop_oid(
_In_ sai_object_id_t oid)
{
SWSS_LOG_ENTER();
if (oid == SAI_NULL_OBJECT_ID)
return;
if (m_oids.objectReferenceExists(oid))
return;
sai_object_type_t ot = objectTypeQuery(oid);
if (ot == SAI_OBJECT_TYPE_NULL)
{
SWSS_LOG_ERROR("failed to get object type on fdb_event oid: 0x%" PRIx64 "", oid);
return;
}
sai_object_meta_key_t key = { .objecttype = ot, .objectkey = { .key = { .object_id = oid } } };
m_oids.objectReferenceInsert(oid);
if (!m_saiObjectCollection.objectExists(key))
m_saiObjectCollection.createObject(key);
/*
* In normal operation orch agent should query or create all bridge, vlan
* and bridge port, so we should not get this message. Let's put it as
* warning for better visibility. Most likely if this happen there is a
* vendor bug in SAI and we should also see warnings or errors reported
* from syncd in logs.
*/
SWSS_LOG_WARN("fdb_entry oid (snoop): %s: %s",
sai_serialize_object_type(ot).c_str(),
sai_serialize_object_id(oid).c_str());
}
void Meta::meta_sai_on_fdb_event_single(
_In_ const sai_fdb_event_notification_data_t& data)
{
SWSS_LOG_ENTER();
const sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = data.fdb_entry } } };
/*
* Because we could receive fdb event's before orch agent will query or
* create bridge/vlan/bridge port we should snoop here new OIDs and put
* them in local DB.
*
* Unfortunately we don't have a way to check whether those OIDs are correct
* or whether there maybe some bug in vendor SAI and for example is sending
* invalid OIDs in those event's. Also objectTypeQuery can return
* valid object type for OID, but this does not guarantee that this OID is
* valid, for example one of existing bridge ports that orch agent didn't
* query yet.
*/
meta_fdb_event_snoop_oid(data.fdb_entry.bv_id);
for (uint32_t i = 0; i < data.attr_count; i++)
{
auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_FDB_ENTRY, data.attr[i].id);
if (meta == NULL)
{
SWSS_LOG_ERROR("failed to get metadata for fdb_entry attr.id = %d", data.attr[i].id);
continue;
}
if (meta->attrvaluetype == SAI_ATTR_VALUE_TYPE_OBJECT_ID)
meta_fdb_event_snoop_oid(data.attr[i].value.oid);
}
switch (data.event_type)
{
case SAI_FDB_EVENT_LEARNED:
if (m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_WARN("object key %s already exists, but received LEARNED event",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
break;
}
{
sai_attribute_t *list = data.attr;
uint32_t count = data.attr_count;
sai_attribute_t local[2]; // 2 for port id and type
if (count == 1)
{
// workaround for missing "TYPE" attribute on notification
local[0] = data.attr[0]; // copy 1st attr
local[1].id = SAI_FDB_ENTRY_ATTR_TYPE;
local[1].value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; // assume learned entries are always dynamic
list = local;
count = 2; // now we added type
}
sai_status_t status = meta_generic_validation_create(meta_key_fdb, data.fdb_entry.switch_id, count, list);
if (status == SAI_STATUS_SUCCESS)
{
meta_generic_validation_post_create(meta_key_fdb, data.fdb_entry.switch_id, count, list);
}
else
{
SWSS_LOG_ERROR("failed to insert %s received in notification: %s",
sai_serialize_object_meta_key(meta_key_fdb).c_str(),
sai_serialize_status(status).c_str());
}
}
break;
case SAI_FDB_EVENT_AGED:
if (!m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_WARN("object key %s doesn't exist but received AGED event",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
break;
}
meta_generic_validation_post_remove(meta_key_fdb);
break;
case SAI_FDB_EVENT_FLUSHED:
if (memcmp(data.fdb_entry.mac_address, zero_mac, sizeof(zero_mac)) == 0)
{
meta_sai_on_fdb_flush_event_consolidated(data);
break;
}
if (!m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_WARN("object key %s doesn't exist but received FLUSHED event",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
break;
}
meta_generic_validation_post_remove(meta_key_fdb);
break;
case SAI_FDB_EVENT_MOVE:
if (!m_saiObjectCollection.objectExists(meta_key_fdb))
{
SWSS_LOG_WARN("object key %s doesn't exist but received FDB MOVE event",
sai_serialize_object_meta_key(meta_key_fdb).c_str());
break;
}
// on MOVE event, just update attributes on existing entry
for (uint32_t i = 0; i < data.attr_count; i++)
{
const sai_attribute_t& attr = data.attr[i];
sai_status_t status = meta_generic_validation_set(meta_key_fdb, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("object key %s FDB MOVE event, SET validation failed on attr.id = %d",
sai_serialize_object_meta_key(meta_key_fdb).c_str(),
attr.id);
continue;
}
meta_generic_validation_post_set(meta_key_fdb, &attr);
}
break;
default:
SWSS_LOG_ERROR("got FDB_ENTRY notification with unknown event_type %d, bug?", data.event_type);
break;
}
}
void Meta::meta_sai_on_fdb_event(
_In_ uint32_t count,
_In_ const sai_fdb_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("fdb_event_notification_data pointer is NULL when count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_fdb_event_single(data[i]);
}
}
void Meta::meta_sai_on_nat_event_single(
_In_ const sai_nat_event_notification_data_t& data)
{
SWSS_LOG_ENTER();
const sai_object_meta_key_t meta_key_nat = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = data.nat_entry } } };
switch (data.event_type)
{
case SAI_NAT_EVENT_AGED:
if (!m_saiObjectCollection.objectExists(meta_key_nat))
{
SWSS_LOG_WARN("object key %s doesn't exist but received AGED event",
sai_serialize_object_meta_key(meta_key_nat).c_str());
break;
}
// meta_generic_validation_post_remove is not done at this point
// as Nat-orch will be performing the cleanup for both Aging and
// Hit-bit implementations.
break;
case SAI_NAT_EVENT_NONE:
default:
SWSS_LOG_ERROR("got NAT_ENTRY notification with unknown event_type %d, bug?", data.event_type);
break;
}
}
void Meta::meta_sai_on_nat_event(
_In_ uint32_t count,
_In_ const sai_nat_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("nat_event_notification_data pointer is NULL when count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_nat_event_single(data[i]);
}
}
void Meta::meta_sai_on_port_host_tx_ready_change(
_In_ sai_object_id_t port_id,
_In_ sai_object_id_t switch_id,
_In_ sai_port_host_tx_ready_status_t host_tx_ready_status)
{
SWSS_LOG_ENTER();
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_port_host_tx_ready_status_t,
host_tx_ready_status))
{
SWSS_LOG_WARN("port host_tx_ready value (%d) not found in sai_port_host_tx_ready_status_t. Dropping the notification",
host_tx_ready_status);
return;
}
auto ot = objectTypeQuery(port_id);
if (ot != SAI_OBJECT_TYPE_PORT)
{
SWSS_LOG_ERROR("port_id %s has unexpected type: %s, expected PORT",
sai_serialize_object_id(port_id).c_str(),
sai_serialize_object_type(ot).c_str());
return;
}
if (!m_oids.objectReferenceExists(port_id))
{
SWSS_LOG_NOTICE("port_id new object spotted %s not present in local DB (snoop!)",
sai_serialize_object_id(port_id).c_str());
sai_object_meta_key_t host_tx_ready_key = { .objecttype = ot, .objectkey = { .key = { .object_id = port_id } } };
m_oids.objectReferenceInsert(port_id);
if (!m_saiObjectCollection.objectExists(host_tx_ready_key))
{
m_saiObjectCollection.createObject(host_tx_ready_key);
}
}
}
void Meta::meta_sai_on_switch_state_change(
_In_ sai_object_id_t switch_id,
_In_ sai_switch_oper_status_t switch_oper_status)
{
SWSS_LOG_ENTER();
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_switch_oper_status_t,
switch_oper_status))
{
SWSS_LOG_WARN("switch oper status value (%d) not found in sai_switch_oper_status_t",
switch_oper_status);
}
auto ot = objectTypeQuery(switch_id);
if (ot != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_WARN("switch_id %s is of type %s, but expected SAI_OBJECT_TYPE_SWITCH",
sai_serialize_object_id(switch_id).c_str(),
sai_serialize_object_type(ot).c_str());
return;
}
sai_object_meta_key_t switch_meta_key = { .objecttype = ot , .objectkey = { .key = { .object_id = switch_id } } };
if (!m_saiObjectCollection.objectExists(switch_meta_key))
{
SWSS_LOG_ERROR("switch_id %s don't exists in local database",
sai_serialize_object_id(switch_id).c_str());
}
// we should not snoop switch_id, since switch id should be created directly by user
}
void Meta::meta_sai_on_switch_asic_sdk_health_event(
_In_ sai_object_id_t switch_id,
_In_ sai_switch_asic_sdk_health_severity_t severity,
_In_ sai_timespec_t timestamp,
_In_ sai_switch_asic_sdk_health_category_t category,
_In_ sai_switch_health_data_t data,
_In_ const sai_u8_list_t description)
{
SWSS_LOG_ENTER();
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_switch_asic_sdk_health_severity_t,
severity))
{
SWSS_LOG_WARN("Switch ASIC/SDK health event severity value (%d) not found in sai_switch_asic_sdk_health_severity_t",
severity);
}
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_switch_asic_sdk_health_category_t,
category))
{
SWSS_LOG_WARN("Switch ASIC/SDK health event category value (%d) not found in sai_switch_asic_sdk_health_severity_t",
category);
}
auto ot = objectTypeQuery(switch_id);
if (ot != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_WARN("switch_id %s is of type %s, but expected SAI_OBJECT_TYPE_SWITCH",
sai_serialize_object_id(switch_id).c_str(),
sai_serialize_object_type(ot).c_str());
return;
}
sai_object_meta_key_t switch_meta_key = { .objecttype = ot , .objectkey = { .key = { .object_id = switch_id } } };
if (!m_saiObjectCollection.objectExists(switch_meta_key))
{
SWSS_LOG_ERROR("switch_id %s don't exists in local database",
sai_serialize_object_id(switch_id).c_str());
}
// we should not snoop switch_id, since switch id should be created directly by user
}
void Meta::meta_sai_on_switch_shutdown_request(
_In_ sai_object_id_t switch_id)
{
SWSS_LOG_ENTER();
auto ot = objectTypeQuery(switch_id);
if (ot != SAI_OBJECT_TYPE_SWITCH)
{
SWSS_LOG_WARN("switch_id %s is of type %s, but expected SAI_OBJECT_TYPE_SWITCH",
sai_serialize_object_id(switch_id).c_str(),
sai_serialize_object_type(ot).c_str());
return;
}
sai_object_meta_key_t switch_meta_key = { .objecttype = ot , .objectkey = { .key = { .object_id = switch_id } } };
if (!m_saiObjectCollection.objectExists(switch_meta_key))
{
SWSS_LOG_ERROR("switch_id %s don't exists in local database",
sai_serialize_object_id(switch_id).c_str());
}
// we should not snoop switch_id, since switch id should be created directly by user
}
void Meta::meta_sai_on_port_state_change_single(
_In_ const sai_port_oper_status_notification_t& data)
{
SWSS_LOG_ENTER();
auto ot = objectTypeQuery(data.port_id);
bool valid = false;
switch (ot)
{
// TODO hardcoded types, must advance SAI repository commit to get metadata for this
case SAI_OBJECT_TYPE_PORT:
case SAI_OBJECT_TYPE_BRIDGE_PORT:
case SAI_OBJECT_TYPE_LAG:
valid = true;
break;
default:
SWSS_LOG_ERROR("data.port_id %s has unexpected type: %s, expected PORT, BRIDGE_PORT or LAG",
sai_serialize_object_id(data.port_id).c_str(),
sai_serialize_object_type(ot).c_str());
break;
}
if (valid && !m_oids.objectReferenceExists(data.port_id))
{
SWSS_LOG_NOTICE("data.port_id new object spotted %s not present in local DB (snoop!)",
sai_serialize_object_id(data.port_id).c_str());
sai_object_meta_key_t key = { .objecttype = ot, .objectkey = { .key = { .object_id = data.port_id } } };
m_oids.objectReferenceInsert(data.port_id);
if (!m_saiObjectCollection.objectExists(key))
{
m_saiObjectCollection.createObject(key);
}
}
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_port_oper_status_t,
data.port_state))
{
SWSS_LOG_WARN("port_state value (%d) not found in sai_port_oper_status_t",
data.port_state);
}
}
void Meta::meta_sai_on_port_state_change(
_In_ uint32_t count,
_In_ const sai_port_oper_status_notification_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("port_oper_status_notification pointer is NULL but count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_port_state_change_single(data[i]);
}
}
void Meta::meta_sai_on_queue_pfc_deadlock_notification_single(
_In_ const sai_queue_deadlock_notification_data_t& data)
{
SWSS_LOG_ENTER();
auto ot = objectTypeQuery(data.queue_id);
bool valid = false;
switch (ot)
{
// TODO hardcoded types, must advance SAI repository commit to get metadata for this
case SAI_OBJECT_TYPE_QUEUE:
valid = true;
break;
default:
SWSS_LOG_ERROR("data.queue_id %s has unexpected type: %s, expected PORT, BRIDGE_PORT or LAG",
sai_serialize_object_id(data.queue_id).c_str(),
sai_serialize_object_type(ot).c_str());
break;
}
SWSS_LOG_WARN("data.queue_id has invalid type, skip snoop");
if (valid && !m_oids.objectReferenceExists(data.queue_id))
{
SWSS_LOG_NOTICE("data.queue_id new object spotted %s not present in local DB (snoop!)",
sai_serialize_object_id(data.queue_id).c_str());
sai_object_meta_key_t key = { .objecttype = ot, .objectkey = { .key = { .object_id = data.queue_id } } };
m_oids.objectReferenceInsert(data.queue_id);
if (!m_saiObjectCollection.objectExists(key))
{
m_saiObjectCollection.createObject(key);
}
}
}
void Meta::meta_sai_on_queue_pfc_deadlock_notification(
_In_ uint32_t count,
_In_ const sai_queue_deadlock_notification_data_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("queue_deadlock_notification_data pointer is NULL but count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_queue_pfc_deadlock_notification_single(data[i]);
}
}
void Meta::meta_sai_on_bfd_session_state_change_single(
_In_ const sai_bfd_session_state_notification_t& data)
{
SWSS_LOG_ENTER();
auto ot = objectTypeQuery(data.bfd_session_id);
bool valid = false;
switch (ot)
{
// TODO hardcoded types, must advance SAI repository commit to get metadata for this
case SAI_OBJECT_TYPE_BFD_SESSION:
valid = true;
break;
default:
SWSS_LOG_ERROR("data.bfd_session_id %s has unexpected type: %s, expected BFD_SESSION",
sai_serialize_object_id(data.bfd_session_id).c_str(),
sai_serialize_object_type(ot).c_str());
break;
}
if (valid && !m_oids.objectReferenceExists(data.bfd_session_id))
{
SWSS_LOG_NOTICE("data.bfd_session_id new object spotted %s not present in local DB (snoop!)",
sai_serialize_object_id(data.bfd_session_id).c_str());
sai_object_meta_key_t key = { .objecttype = ot, .objectkey = { .key = { .object_id = data.bfd_session_id } } };
m_oids.objectReferenceInsert(data.bfd_session_id);
if (!m_saiObjectCollection.objectExists(key))
{
m_saiObjectCollection.createObject(key);
}
}
}
void Meta::meta_sai_on_bfd_session_state_change(
_In_ uint32_t count,
_In_ const sai_bfd_session_state_notification_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("sai_bfd_session_state_notification_t pointer is NULL but count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_bfd_session_state_change_single(data[i]);
}
}
void Meta::meta_sai_on_twamp_session_event_single(
_In_ const sai_twamp_session_event_notification_data_t& data)
{
SWSS_LOG_ENTER();
auto ot = objectTypeQuery(data.twamp_session_id);
bool valid = false;
switch (ot)
{
// TODO hardcoded types, must advance SAI repository commit to get metadata for this
case SAI_OBJECT_TYPE_TWAMP_SESSION:
valid = true;
break;
default:
SWSS_LOG_ERROR("data.twamp_session_id %s has unexpected type: %s, expected TWAMP_SESSION",
sai_serialize_object_id(data.twamp_session_id).c_str(),
sai_serialize_object_type(ot).c_str());
break;
}
// check if all counter ids are in enum range
for (uint32_t idx = 0; idx < data.session_stats.number_of_counters; idx++)
{
if (!sai_metadata_get_enum_value_name(&sai_metadata_enum_sai_twamp_session_stat_t, data.session_stats.counters_ids[idx]))
{
SWSS_LOG_ERROR("value %d is not in range on sai_twamp_session_stat_t ", data.session_stats.counters_ids[idx]);
return;
}
}
if (valid && !m_oids.objectReferenceExists(data.twamp_session_id))
{
SWSS_LOG_NOTICE("data.twamp_session_id new object spotted %s not present in local DB (snoop!)",
sai_serialize_object_id(data.twamp_session_id).c_str());
sai_object_meta_key_t key = { .objecttype = (sai_object_type_t)ot, .objectkey = { .key = { .object_id = data.twamp_session_id } } };
m_oids.objectReferenceInsert(data.twamp_session_id);
if (!m_saiObjectCollection.objectExists(key))
{
m_saiObjectCollection.createObject(key);
}
}
if (!sai_metadata_get_enum_value_name(
&sai_metadata_enum_sai_twamp_session_state_t,
data.session_state))
{
SWSS_LOG_WARN("session_state value (%d) not found sai_twamp_session_state_t",
data.session_state);
}
}
void Meta::meta_sai_on_twamp_session_event(
_In_ uint32_t count,
_In_ const sai_twamp_session_event_notification_data_t *data)
{
SWSS_LOG_ENTER();
if (count && data == NULL)
{
SWSS_LOG_ERROR("sai_twamp_session_event_notification_data_t pointer is NULL but count is %u", count);
return;
}
for (uint32_t i = 0; i < count; ++i)
{
meta_sai_on_twamp_session_event_single(data[i]);
}
}
int32_t Meta::getObjectReferenceCount(
_In_ sai_object_id_t oid) const
{
SWSS_LOG_ENTER();
return m_oids.getObjectReferenceCount(oid);
}
bool Meta::objectExists(
_In_ const sai_object_meta_key_t& mk) const
{
SWSS_LOG_ENTER();
return m_saiObjectCollection.objectExists(mk);
}
void Meta::populate(
_In_ const swss::TableDump& dump)
{
SWSS_LOG_ENTER();
SWSS_LOG_TIMER("table dump populate");
// table dump contains only 1 switch the one that user wanted to connect
// using init=false
for (const auto &key: dump)
{
sai_object_meta_key_t mk;
sai_deserialize_object_meta_key(key.first, mk);
std::unordered_map<std::string, std::string> hash;
for (const auto &field: key.second)
{
hash[field.first] = field.second;
}
SaiAttributeList alist(mk.objecttype, hash, false);
auto attr_count = alist.get_attr_count();
auto attr_list = alist.get_attr_list();
// make references and objects from object id
if (!m_saiObjectCollection.objectExists(mk))
m_saiObjectCollection.createObject(mk);
auto info = sai_metadata_get_object_type_info(mk.objecttype);
if (info->isnonobjectid)
{
/*
* Increase object reference count for all object ids in non object id
* members.
*/
for (size_t j = 0; j < info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
if (!m_oids.objectReferenceExists(m->getoid(&mk)))
m_oids.objectReferenceInsert(m->getoid(&mk));
m_oids.objectReferenceIncrement(m->getoid(&mk));
}
}
else
{
if (!m_oids.objectReferenceExists(mk.objectkey.key.object_id))
m_oids.objectReferenceInsert(mk.objectkey.key.object_id);
}
bool haskeys = false;
for (uint32_t idx = 0; idx < attr_count; ++idx)
{
const sai_attribute_t* attr = &attr_list[idx];
auto mdp = sai_metadata_get_attr_metadata(mk.objecttype, attr->id);
const sai_attribute_value_t& value = attr->value;
const sai_attr_metadata_t& md = *mdp;
if (SAI_HAS_FLAG_KEY(md.flags))
{
haskeys = true;
META_LOG_DEBUG(md, "attr is key");
}
// increase reference on object id types
uint32_t count = 0;
const sai_object_id_t *list;
switch (md.attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
count = 1;
list = &value.oid;
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
count = value.objlist.count;
list = value.objlist.list;
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (value.aclfield.enable)
{
count = 1;
list = &value.aclfield.data.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (value.aclfield.enable)
{
count = value.aclfield.data.objlist.count;
list = value.aclfield.data.objlist.list;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (value.aclaction.enable)
{
count = 1;
list = &value.aclaction.parameter.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (value.aclaction.enable)
{
count = value.aclaction.parameter.objlist.count;
list = value.aclaction.parameter.objlist.list;
}
break;
default:
if (md.isoidattribute)
{
META_LOG_THROW(md, "missing process of oid attribute, FIXME");
}
break;
}
for (uint32_t index = 0; index < count; index++)
{
if (!m_oids.objectReferenceExists(list[index]))
m_oids.objectReferenceInsert(list[index]);
m_oids.objectReferenceIncrement(list[index]);
}
m_saiObjectCollection.setObjectAttr(mk, md, attr);
}
if (haskeys)
{
auto mKey = sai_serialize_object_meta_key(mk);
auto switchId = switchIdQuery(mk.objectkey.key.object_id);
auto attrKey = AttrKeyMap::constructKey(switchId, mk, attr_count, attr_list);
m_attrKeys.insert(mKey, attrKey);
}
}
}