in meta/Meta.cpp [3226:3991]
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;
}