meta/saimetadatautils.c (437 lines of code) (raw):
/**
* Copyright (c) 2014 Microsoft Open Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
* LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
* FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
*
* See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* Microsoft would like to thank the following companies for their review and
* assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
* Dell Products, L.P., Facebook, Inc., Marvell International Ltd.
*
* @file saimetadatautils.c
*
* @brief This module defines SAI Metadata Utils
*/
#include <stdio.h>
#include <string.h>
#include <sai.h>
#include "saimetadatautils.h"
#include "saimetadata.h"
bool sai_metadata_is_allowed_object_type(
_In_ const sai_attr_metadata_t* metadata,
_In_ sai_object_type_t object_type)
{
if (metadata == NULL || metadata->allowedobjecttypes == NULL)
{
return false;
}
size_t i = 0;
for (; i < metadata->allowedobjecttypeslength; ++i)
{
if (metadata->allowedobjecttypes[i] == object_type)
{
return true;
}
}
return false;
}
bool sai_metadata_is_allowed_enum_value(
_In_ const sai_attr_metadata_t* metadata,
_In_ int value)
{
if (metadata == NULL || metadata->enummetadata == NULL)
{
return false;
}
size_t i = 0;
const sai_enum_metadata_t *emd = metadata->enummetadata;
for (; i < emd->valuescount; ++i)
{
if (emd->values[i] == value)
{
return true;
}
}
return false;
}
const sai_attr_metadata_t* sai_metadata_get_attr_metadata(
_In_ sai_object_type_t objecttype,
_In_ sai_attr_id_t attrid)
{
const sai_object_type_info_t* oi = sai_metadata_get_object_type_info(objecttype);
if (oi == NULL)
{
return NULL;
}
const sai_attr_metadata_t* const* const md = oi->attrmetadata;
/*
* Most object attributes are not flags, so we can use direct index to
* find attribute metadata, this should speed up search.
*/
if (!oi->enummetadata->containsflags && attrid < oi->attridend)
{
return md[attrid];
}
/* otherwise search one by one */
size_t index = 0;
for (; md[index] != NULL; index++)
{
if (md[index]->attrid == attrid)
{
return md[index];
}
}
return NULL;
}
const sai_attr_metadata_t* sai_metadata_get_attr_metadata_by_attr_id_name(
_In_ const char *attr_id_name)
{
if (attr_id_name == NULL)
{
return NULL;
}
/* use binary search */
ssize_t first = 0;
ssize_t last = (ssize_t)(sai_metadata_attr_sorted_by_id_name_count - 1);
while (first <= last)
{
ssize_t middle = (first + last) / 2;
int res = strcmp(attr_id_name, sai_metadata_attr_sorted_by_id_name[middle]->attridname);
if (res > 0)
{
first = middle + 1;
}
else if (res < 0)
{
last = middle - 1;
}
else
{
/* found */
return sai_metadata_attr_sorted_by_id_name[middle];
}
}
/* not found */
return NULL;
}
static int sai_metadata_attr_id_name_cmp(
_In_ const char * str1,
_In_ const char * str2)
{
char c1 = 0;
char c2 = 0;
while (true)
{
c1 = *str1++;
c2 = *str2++;
if (sai_serialize_is_char_allowed(c1) || sai_serialize_is_char_allowed(c2) || c1 != c2)
{
if (sai_serialize_is_char_allowed(c1))
{
c1 = 0;
}
if (sai_serialize_is_char_allowed(c2))
{
c2 = 0;
}
return c1 - c2;
}
}
}
const sai_attr_metadata_t* sai_metadata_get_attr_metadata_by_attr_id_name_ext(
_In_ const char *attr_id_name)
{
if (attr_id_name == NULL)
{
return NULL;
}
/* use binary search */
ssize_t first = 0;
ssize_t last = (ssize_t)(sai_metadata_attr_sorted_by_id_name_count - 1);
while (first <= last)
{
ssize_t middle = (first + last) / 2;
int res = sai_metadata_attr_id_name_cmp(attr_id_name, sai_metadata_attr_sorted_by_id_name[middle]->attridname);
if (res > 0)
{
first = middle + 1;
}
else if (res < 0)
{
last = middle - 1;
}
else
{
/* found */
return sai_metadata_attr_sorted_by_id_name[middle];
}
}
/* not found */
return NULL;
}
const sai_attr_metadata_t* sai_metadata_get_ignored_attr_metadata_by_attr_id_name(
_In_ const char *attr_id_name)
{
if (attr_id_name == NULL)
{
return NULL;
}
int idx = 1;
/*
* Since we don't have list of ignored attributes, enumerate all objects
* and attribute enums to find ignored values.
*/
for (; sai_metadata_all_object_type_infos[idx]; idx++)
{
const sai_enum_metadata_t* em = sai_metadata_all_object_type_infos[idx]->enummetadata;
if (em->ignorevaluesnames)
{
size_t i;
for (i = 0; em->ignorevaluesnames[i] != NULL; i++)
{
if (strcmp(attr_id_name, em->ignorevaluesnames[i]) == 0)
{
const char* name = sai_metadata_get_enum_value_name(em, em->ignorevalues[i]);
return sai_metadata_get_attr_metadata_by_attr_id_name(name);
}
}
}
}
return NULL;
}
const char* sai_metadata_get_enum_value_name(
_In_ const sai_enum_metadata_t* metadata,
_In_ int value)
{
if (metadata == NULL)
{
return NULL;
}
size_t i = 0;
for (; i < metadata->valuescount; ++i)
{
if (metadata->values[i] == value)
{
return metadata->valuesnames[i];
}
}
return NULL;
}
const char* sai_metadata_get_enum_value_short_name(
_In_ const sai_enum_metadata_t* metadata,
_In_ int value)
{
if (metadata == NULL)
{
return NULL;
}
size_t i = 0;
for (; i < metadata->valuescount; ++i)
{
if (metadata->values[i] == value)
{
return metadata->valuesshortnames[i];
}
}
return NULL;
}
const sai_attribute_t* sai_metadata_get_attr_by_id(
_In_ sai_attr_id_t id,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
if (attr_list == NULL)
{
return NULL;
}
uint32_t i = 0;
for (; i < attr_count; ++i)
{
if (attr_list[i].id == id)
{
return &attr_list[i];
}
}
return NULL;
}
const sai_object_type_info_t* sai_metadata_get_object_type_info(
_In_ sai_object_type_t object_type)
{
if (object_type >= SAI_OBJECT_TYPE_NULL && object_type < SAI_OBJECT_TYPE_MAX)
{
return sai_metadata_all_object_type_infos[object_type];
}
int idx = 1;
for (; sai_metadata_all_object_type_infos[idx]; idx++)
{
if (sai_metadata_all_object_type_infos[idx]->objecttype == object_type)
{
return sai_metadata_all_object_type_infos[idx];
}
}
return NULL;
}
bool sai_metadata_is_object_type_oid(
_In_ sai_object_type_t object_type)
{
const sai_object_type_info_t* oti = sai_metadata_get_object_type_info(object_type);
if (oti != NULL)
{
return oti->isobjectid;
}
return false;
}
bool sai_metadata_is_object_type_valid(
_In_ sai_object_type_t object_type)
{
return sai_metadata_get_object_type_info(object_type) != NULL;
}
static bool sai_metadata_is_condition_value_eq(
_In_ sai_attr_value_type_t attrvaluetype,
_In_ const sai_attribute_value_t* cvalue,
_In_ const sai_attribute_value_t* value)
{
if (cvalue == NULL || value == NULL)
{
return false;
}
switch (attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_BOOL:
return cvalue->booldata == value->booldata;
case SAI_ATTR_VALUE_TYPE_INT8:
return cvalue->s8 == value->s8;
case SAI_ATTR_VALUE_TYPE_INT16:
return cvalue->s16 == value->s16;
case SAI_ATTR_VALUE_TYPE_INT32:
return cvalue->s32 == value->s32;
case SAI_ATTR_VALUE_TYPE_INT64:
return cvalue->s64 == value->s64;
case SAI_ATTR_VALUE_TYPE_UINT8:
return cvalue->u8 == value->u8;
case SAI_ATTR_VALUE_TYPE_UINT16:
return cvalue->u16 == value->u16;
case SAI_ATTR_VALUE_TYPE_UINT32:
return cvalue->u32 == value->u32;
case SAI_ATTR_VALUE_TYPE_UINT64:
return cvalue->u64 == value->u64;
default:
/*
* We should never get here since sanity check tests all
* attributes and all conditions.
*/
SAI_META_LOG_ERROR("condition value type %d is not supported, FIXME", attrvaluetype);
return false;
}
}
static bool sai_metadata_is_single_condition_met(
_In_ sai_object_type_t objecttype,
_In_ const sai_attr_condition_t *condition,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
/*
* Conditions may only be on the same object type.
*
* Default value may not exists if conditional object is marked as
* MANDATORY_ON_CREATE.
*/
const sai_attr_metadata_t *cmd = sai_metadata_get_attr_metadata(objecttype, condition->attrid);
const sai_attribute_t *cattr = sai_metadata_get_attr_by_id(condition->attrid, attr_count, attr_list);
if (cattr == NULL)
{
/*
* User didn't passed conditional attribute, so check if there is
* default value.
*/
return sai_metadata_is_condition_value_eq(cmd->attrvaluetype, &condition->condition, cmd->defaultvalue);
}
else
{
return sai_metadata_is_condition_value_eq(cmd->attrvaluetype, &condition->condition, &cattr->value);
}
}
static bool sai_metadata_is_and_condition_list_met(
_In_ const sai_attr_metadata_t *md,
_In_ size_t length,
_In_ const sai_attr_condition_t* const* list,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
size_t idx = 0;
bool met = length > 0;
for (; idx < length; ++idx)
{
const sai_attr_condition_t *condition = list[idx];
met &= sai_metadata_is_single_condition_met(md->objecttype, condition, attr_count, attr_list);
}
return met;
}
static bool sai_metadata_is_or_condition_list_met(
_In_ const sai_attr_metadata_t *md,
_In_ size_t length,
_In_ const sai_attr_condition_t* const* list,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
size_t idx = 0;
bool met = false;
for (; idx < length; ++idx)
{
const sai_attr_condition_t *condition = list[idx];
met |= sai_metadata_is_single_condition_met(md->objecttype, condition, attr_count, attr_list);
}
return met;
}
#define STACK_PUSH(val) stack[stack_size++] = (val)
#define STACK_POP() stack[--stack_size]
static bool sai_metadata_is_mixed_condition_list_met(
_In_ const sai_attr_metadata_t *md,
_In_ size_t length,
_In_ const sai_attr_condition_t* const* list,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
int stack_size = 0;
bool stack[SAI_METADATA_MAX_CONDITIONS_LEN];
size_t idx = 0;
for (; idx < length; idx++)
{
const sai_attr_condition_t* c = list[idx];
if (c->type == SAI_ATTR_CONDITION_TYPE_NONE)
{
bool value = sai_metadata_is_single_condition_met(md->objecttype, c, attr_count, attr_list);
STACK_PUSH(value);
}
else if (c->type == SAI_ATTR_CONDITION_TYPE_AND)
{
bool a = STACK_POP();
bool b = STACK_POP();
STACK_PUSH(a & b);
}
else if (c->type == SAI_ATTR_CONDITION_TYPE_OR)
{
bool a = STACK_POP();
bool b = STACK_POP();
STACK_PUSH(a | b);
}
else
{
SAI_META_LOG_ERROR("%s: wrong condition type on list: %d", md->attridname, c->type);
return false;
}
}
bool value = STACK_POP();
if (stack_size)
{
SAI_META_LOG_ERROR("FATAL %s: stack not empty after condition list check, RPN condition logic is BROKEN", md->attridname);
return false;
}
return value;
}
bool sai_metadata_is_condition_met(
_In_ const sai_attr_metadata_t *md,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
/* attr list can be NULL, condition could be based on default value */
if (md == NULL || !md->isconditional)
{
return false;
}
switch (md->conditiontype)
{
case SAI_ATTR_CONDITION_TYPE_AND:
return sai_metadata_is_and_condition_list_met(md, md->conditionslength, md->conditions, attr_count, attr_list);
case SAI_ATTR_CONDITION_TYPE_OR:
return sai_metadata_is_or_condition_list_met(md, md->conditionslength, md->conditions, attr_count, attr_list);
case SAI_ATTR_CONDITION_TYPE_MIXED:
return sai_metadata_is_mixed_condition_list_met(md, md->conditionslength, md->conditions, attr_count, attr_list);
default:
SAI_META_LOG_ERROR("condition type %d on %s is not supported yet, FIXME", md->conditiontype, md->attridname);
return false;
}
}
bool sai_metadata_is_validonly_met(
_In_ const sai_attr_metadata_t *md,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list)
{
/* attr list can be NULL, condition could be based on default value */
if (md == NULL || !md->isvalidonly)
{
return false;
}
switch (md->validonlytype)
{
case SAI_ATTR_CONDITION_TYPE_AND:
return sai_metadata_is_and_condition_list_met(md, md->validonlylength, md->validonly, attr_count, attr_list);
case SAI_ATTR_CONDITION_TYPE_OR:
return sai_metadata_is_or_condition_list_met(md, md->validonlylength, md->validonly, attr_count, attr_list);
case SAI_ATTR_CONDITION_TYPE_MIXED:
return sai_metadata_is_mixed_condition_list_met(md, md->validonlylength, md->validonly, attr_count, attr_list);
default:
SAI_META_LOG_ERROR("validonly type %d on %s is not supported yet, FIXME", md->validonlytype, md->attridname);
return false;
}
return false;
}
sai_api_version_t sai_metadata_query_api_version(void)
{
return SAI_API_VERSION;
}