meta: initial TAI metadata implementation

Signed-off-by: Wataru Ishida <ishida@nel-america.com>
This commit is contained in:
Wataru Ishida
2018-09-20 15:16:01 -07:00
committed by Wataru Ishida
parent 85af48f174
commit efadaf9199
14 changed files with 3394 additions and 0 deletions

3
meta/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.so
taimetadata.c
taimetadata.h

5
meta/Dockerfile Normal file
View File

@@ -0,0 +1,5 @@
FROM ubuntu:18.04
RUN apt update
RUN apt install -qy wget python3 python3-pip libclang1-6.0
RUN pip3 install clang jinja2

20
meta/Makefile Normal file
View File

@@ -0,0 +1,20 @@
.PHONY: test
all: taimetadata.c taimetadata.h taiserialize.c taimetadatautils.c
gcc -shared -fPIC -I ../inc taiserialize.c taimetadatautils.c taimetadata.c -o libmetatai.so
taimetadata.c taimetadata.h: main.py
python3 main.py ../inc/tai.h
docker-image:
docker build -t taimeta-builder .
docker:
cd ../; docker run -v `pwd`:/data -w /data -u `id -u`:`id -g` taimeta-builder make -C meta
test:
make -C test
LD_LIBRARY_PATH=. ./test/test
clean:
rm libmetatai.so taimetadata.c taimetadata.h

38
meta/README.md Normal file
View File

@@ -0,0 +1,38 @@
Metadata for TAI
================
Metadata for TAI is a set of auto generated (based on TAI headers) data
and functions which allow TAI attributes serialization and more.
Metadata is generated as ANSI C source and header.
Parser also forces headers to be well formated when adding new code.
As same as TAI itself, TAI metadata is based upon and quite common to the
SAI metadata.
## How to build
### native build
#### prerequisite
- gcc
- python3
- libclang6.0
```sh
$ make
```
### Docker build
#### prerequisite
- docker
```sh
$ make docker-image
$ make docker
```

463
meta/main.py Normal file
View File

@@ -0,0 +1,463 @@
#
# Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import clang.cindex
from clang.cindex import Index
from clang.cindex import Config
from optparse import OptionParser
from enum import Enum
from jinja2 import Environment
class TAIAttributeFlag(Enum):
READ_ONLY = 0
IS_FLAG = 1
CREATE_ONLY = 2
MANDATORY_ON_CREATE = 3
class TAIEnum(object):
def __init__(self, name_node, value_nodes):
self.name_node = name_node
value_nodes.sort(key = lambda l : l.enum_value)
self.value_nodes = value_nodes
# displayname starts with '_'. remove it
self.typename = self.name_node.displayname[1:]
def value_names(self):
return [v.displayname for v in self.value_nodes if not v.displayname.endswith('_START') and not v.displayname.endswith('_END')]
class TAIAttribute(object):
def __init__(self, node, taiobject):
self.node = node
self.id = node.enum_value
self.name = node.displayname
self.taiobject = taiobject
self.object_type = taiobject.object_type
self.object_name = taiobject.name
rm = ' /*'
cmt = [l.strip(rm).split(' ') for l in node.raw_comment.split('\n') if l.strip(rm).startswith('@')] # this omits long description from the comment
s = { l[0][1:]: ' '.join(l[1:]) for l in cmt }
self.cmt = s
flags = self.cmt.get('flags', '').split('|')
if flags[0] != '':
self.flags = set(TAIAttributeFlag[e.strip()] for e in flags)
else:
self.flags = None
t = self.cmt['type']
ts = [v.strip('#') for v in t.split(' ')]
self.enum_type = None
if len(ts) == 1:
self.type = ts[0]
elif len(ts) == 2 and ts[0] == 'tai_s32_list_t':
self.type = ts[0]
self.enum_type = ts[1]
else:
raise Exception("unsupported type format: {}".format(t))
def __str__(self):
return self.name
def __repr__(self):
return '{}[{}:{}]'.format(self.name, self.type, self.flags)
class TAIObject(object):
OBJECT_MAP = {
'module' : 'TAI_OBJECT_TYPE_MODULE',
'host_interface' : 'TAI_OBJECT_TYPE_HOSTIF',
'network_interface': 'TAI_OBJECT_TYPE_NETWORKIF',
}
def __init__(self, name, header):
self.name = name
index = Index.create()
tu = index.parse(header)
self.tu = tu
self.object_type = self.OBJECT_MAP.get(name, None)
self.enum_map = {}
m = {n.displayname:n for n in self.kinds('ENUM_DECL')}
n = {n.displayname:n for n in self.kinds('ENUM_CONSTANT_DECL')}
for k, v in m.items():
prefix = k[1:-2].upper()
l = [vv for vv in n.values() if vv.displayname.startswith(prefix)]
e = TAIEnum(v, l)
self.enum_map[e.typename] = e
v = self.get_name('_tai_attribute_value_t')
m = {}
for f in v.get_children():
# bool needs special handling since its type.spelling appear as 'int'
key = 'bool' if f.displayname == 'booldata' else f.type.spelling
m[key] = f.displayname
enums = set()
a = self.get_enum('tai_{}_attr_t'.format(self.name))
attrs = [ TAIAttribute(e, self) for e in a.value_nodes if not e.displayname.endswith('_START') and not e.displayname.endswith('_END') ]
for attr in attrs:
field = m.get(attr.type, None)
if field:
if getattr(attr, 'enum_type', None):
enum = self.get_enum(attr.enum_type)
if not enum:
raise Exception("{} not found".format(attr.enum_type))
enums.add(attr.enum_type)
attr.value_field = field
else:
enum = self.get_enum(attr.type)
enums.add(attr.type)
if not enum:
raise Exception("{} not found".format(attr.type))
attr.value_field = 's32'
attr.enum_type = attr.type
self.enum_names = enums
self.attrs = attrs
def kinds(self, kind):
node = self.tu.cursor
out = []
self.get_kinds(node, kind, out)
return out
def get_name(self, name):
node = self.tu.cursor
return self._get_name(node, name)
def _get_name(self, node, name):
if node.displayname == name:
return node
for child in node.get_children():
n = self._get_name(child, name)
if n:
return n
return None
def get_kinds(self, node, kind, out=[]):
if node.kind.name == kind:
out.append(node)
return
for child in node.get_children():
self.get_kinds(child, kind, out)
def get_enum(self, name):
return self.enum_map.get(name, None)
def get_enums(self):
return [self.enum_map[n] for n in self.enum_names]
def get_attributes(self):
return self.attrs
class Generator(object):
HEADER_TEMPLATE = ''
def __init__(self, env=Environment()):
self.env = env
def implementation(self):
if not getattr(self, 'env', None):
self.env = Environment()
return self.env.from_string(self.IMPL_TEMPLATE).render(self.data)
def header(self):
if not getattr(self, 'env', None):
self.env = Environment()
return self.env.from_string(self.HEADER_TEMPLATE).render(self.data)
class ObjectMetadataGenerator(Generator):
HEADER_TEMPLATE = '''
extern const tai_object_type_info_t tai_metadata_object_type_info_{{ name }};
'''
IMPL_TEMPLATE = '''
const tai_attr_metadata_t* const tai_metadata_object_type_tai_{{ name }}_attr_t[] = {
{% for a in attrs -%}
&tai_metadata_attr_{{ a }},
{% endfor -%}
NULL
};
const tai_object_type_info_t tai_metadata_object_type_info_{{ name }} = {
.objecttype = {{ object_type }},
.objecttypename = "{{ object_type }}",
.enummetadata = &tai_metadata_enum_tai_{{ name }}_attr_t,
.attrmetadata = tai_metadata_object_type_tai_{{ name }}_attr_t,
.attrmetadatalength = {{ attrs | count }},
};
'''
def __init__(self, obj):
self.data = {'name': obj.name,
'object_type' : obj.object_type,
'attrs': [a.name for a in obj.get_attributes()]}
class AttrMetadataGenerator(Generator):
IMPL_TEMPLATE = '''
const tai_attr_metadata_t tai_metadata_attr_{{ typename }} = {
.objecttype = {{ object }},
.attrid = {{ typename }},
.attridname = "{{ typename }}",
.attridshortname = "{{ shorttypename }}",
.attrvaluetype = {{ attr_type }},
{%- if attr_flags %}
.flags = {{ attr_flags }},
{%- else %}
.flags = 0,
{%- endif %}
.isenum = {{ is_enum }},
{%- if enum_meta_data %}
.enummetadata = &{{ enum_meta_data }},
{%- else %}
.enummetadata = NULL,
{%- endif %}
};
'''
def __init__(self, attr):
obj = attr.object_type
objname = attr.object_name
typename = attr.name
prefix = 'TAI_{}_ATTR_'.format(objname.upper())
if not typename.startswith(prefix):
raise Exception("invalid attr type name: {}, obj: {}".format(typename, obj))
shorttypename = typename[len(prefix):].lower().replace('_', '-')
attr_type = 'TAI_ATTR_VALUE_TYPE_{}'.format(attr.value_field.upper())
is_enum = 'false'
enum_meta_data = None
if attr.enum_type:
is_enum = 'true'
enum_meta_data = 'tai_metadata_enum_{}'.format(attr.enum_type)
attr_flags = None
if attr.flags:
attr_flags = '|'.join('TAI_ATTR_FLAGS_{}'.format(e.name) for e in list(attr.flags))
self.data = {'object': obj,
'typename': typename,
'shorttypename': shorttypename,
'attr_type': attr_type,
'attr_flags': attr_flags,
'is_enum': is_enum,
'enum_meta_data': enum_meta_data}
class EnumMetadataGenerator(Generator):
HEADER_TEMPLATE = '''int tai_serialize_{{ typename | simplify }}( _Out_ char *buffer, _In_ {{ typename }} {{ typename | simplify }}, _In_ const tai_serialize_option_t *option);;
int tai_deserialize_{{ typename | simplify }}( _In_ const char *buffer, _Out_ int32_t *value, _In_ const tai_serialize_option_t *option);
'''
IMPL_TEMPLATE = '''const {{ typename }} tai_metadata_{{ typename }}_enum_values[] = {
{% for t in enums -%}
{{ t }},
{% endfor -%}
-1
};
const char* const tai_metadata_{{ typename }}_enum_values_names[] = {
{% for t in enums -%}
"{{ t }}",
{% endfor -%}
NULL
};
const char* const tai_metadata_{{ typename }}_enum_values_short_names[] = {
{% for t in enums -%}
"{{ t | shorten(typename) }}",
{% endfor -%}
NULL
};
const tai_enum_metadata_t tai_metadata_enum_{{ typename }} = {
.name = "{{ typename }}",
.valuescount = {{ enums | count }},
.values = (const int*)tai_metadata_{{ typename }}_enum_values,
.valuesnames = tai_metadata_{{ typename }}_enum_values_names,
.valuesshortnames = tai_metadata_{{ typename }}_enum_values_short_names,
.containsflags = false,
};
int tai_serialize_{{ typename | simplify }}(
_Out_ char *buffer,
_In_ {{ typename }} {{ typename | simplify }},
_In_ const tai_serialize_option_t *option)
{
return tai_serialize_enum(buffer, &tai_metadata_enum_{{ typename }}, {{ typename | simplify }}, option);
}
int tai_deserialize_{{ typename | simplify }}(
_In_ const char *buffer,
_Out_ int32_t *value,
_In_ const tai_serialize_option_t *option)
{
return tai_deserialize_enum(buffer, &tai_metadata_enum_{{ typename }}, value, option);
}
'''
def __init__(self, enum):
typename = enum.typename
enums = enum.value_names()
env = Environment()
def shorten(v, typename):
if not typename.endswith('_t'):
raise Exception("invalid type name: {}".format(typename))
t = typename[:-1].upper()
if not v.startswith(t):
raise Exception("invalid enum value name: {}".format(v))
return v[len(t):].lower().replace('_', '-')
def simplify(typename):
return typename[4:-2]
env.filters['shorten'] = shorten
env.filters['simplify'] = simplify
super(EnumMetadataGenerator, self).__init__(env)
self.data = {'typename': typename, 'enums': enums}
class TAIMetadataGenerator(Generator):
HEADER_TEMPLATE = '''/* AUTOGENERATED FILE! DO NOT EDIT */
#ifndef __TAI_METADATA_H__
#define __TAI_METADATA_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <tai.h>
#include "taimetadatatypes.h"
#include "taimetadatautils.h"
#include "taimetadatalogger.h"
#include "taiserialize.h"
{% for e in headers -%}
{{ e }}
{% endfor -%}
extern const tai_attr_metadata_t* const* const tai_metadata_attr_by_object_type[];
extern const size_t tai_metadata_attr_by_object_type_count;
/* Object infos table */
extern const tai_object_type_info_t* const tai_metadata_all_object_type_infos[];
/* List of all attributes */
extern const tai_attr_metadata_t* const tai_metadata_attr_sorted_by_id_name[];
extern const size_t tai_metadata_attr_sorted_by_id_name_count;
#ifdef __cplusplus
}
#endif
#endif'''
IMPL_TEMPLATE = '''/* AUTOGENERATED FILE! DO NOT EDIT */
#include <stdio.h>
#include "taimetadata.h"
{% for e in impls -%}
{{ e }}
{% endfor -%}
volatile tai_log_level_t tai_metadata_log_level = TAI_LOG_LEVEL_NOTICE;
volatile tai_metadata_log_fn tai_metadata_log = NULL;
const tai_attr_metadata_t* const* const tai_metadata_attr_by_object_type[] = {
NULL,
{% for o in object_names -%}
tai_metadata_object_type_tai_{{ o }}_attr_t,
{% endfor -%}
NULL
};
const size_t tai_metadata_attr_by_object_type_count = {{ object_names | count }};
const tai_object_type_info_t* const tai_metadata_all_object_type_infos[] = {
NULL,
{% for o in object_names -%}
&tai_metadata_object_type_info_{{ o }},
{% endfor -%}
NULL
};
const tai_attr_metadata_t* const tai_metadata_attr_sorted_by_id_name[] = {
{% for a in attrs -%}
&tai_metadata_attr_{{ a }},
{% endfor -%}
NULL
};
const size_t tai_metadata_attr_sorted_by_id_name_count = {{ attrs | count }};
'''
def __init__(self, objects):
generators = []
all_attrs = []
for obj in objects:
attrs = obj.get_attributes()
enums = obj.get_enums()
for e in enums:
g = EnumMetadataGenerator(e)
generators.append(g)
for a in attrs:
g = AttrMetadataGenerator(a)
generators.append(g)
e = obj.get_enum('tai_{}_attr_t'.format(obj.name))
g = EnumMetadataGenerator(e)
generators.append(g)
g = ObjectMetadataGenerator(obj)
generators.append(g)
all_attrs += [a.name for a in attrs]
self.data = {'impls': [g.implementation() for g in generators],
'headers': [x for x in [g.header() for g in generators] if len(x) > 0],
'object_names': [o.name for o in objects],
'attrs': sorted(all_attrs)}
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('--clang-lib', default='/usr/lib/llvm-6.0/lib/libclang.so.1')
(options, args) = parser.parse_args()
Config.set_library_file(options.clang_lib)
objects = [TAIObject(t, args[0]) for t in TAIObject.OBJECT_MAP.keys()]
g = TAIMetadataGenerator(objects)
with open('taimetadata.h', 'w') as f:
f.write(g.header())
with open('taimetadata.c', 'w') as f:
f.write(g.implementation())

105
meta/taimetadatalogger.h Normal file
View File

@@ -0,0 +1,105 @@
/**
* @file taimetadatalogger.h
*
* @brief This module defines TAI Metadata Logger
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#ifndef __TAIMETADATALOGGER_H_
#define __TAIMETADATALOGGER_H_
/**
* @defgroup TAIMETADATALOGGER TAI - Metadata Logger Definitions
*
* @{
*/
/**
* @brief Log level function definition.
*
* User can specify his own function that will be called when message log level
* will be greater or equal to #tai_metadata_log_level.
*
* @param[in] log_level Log level
* @param[in] file Source file
* @param[in] line Line number in file
* @param[in] function Function name
* @param[in] format Format of logging
* @param[in] ... Variable parameters
*/
typedef void (*tai_metadata_log_fn)(
_In_ tai_log_level_t log_level,
_In_ const char *file,
_In_ int line,
_In_ const char *function,
_In_ const char *format,
_In_ ...);
/**
* @brief User specified log function.
*
* TODO: add a set function to update this?
*/
extern volatile tai_metadata_log_fn tai_metadata_log;
/**
* @brief Log level for TAI metadata macros.
*
* Log level can be changed by user at any time.
*
* TODO: add a set function to update this?
*/
extern volatile tai_log_level_t tai_metadata_log_level;
/**
* @brief Helper log macro definition
*
* If logger function is NULL, stderr is used to print messages. Also, fprintf
* function will validate parameters at compilation time.
*/
#define TAI_META_LOG(loglevel,format,...)\
if (loglevel >= tai_metadata_log_level)\
{\
if (tai_metadata_log == NULL) /* or syslog? */ \
fprintf(stderr, "%s:%d %s: " format "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__);\
else\
tai_metadata_log(loglevel, __FILE__, __LINE__, __func__, format, ##__VA_ARGS__);\
}
/*
* Helper macros.
*/
#define TAI_META_LOG_ENTER() TAI_META_LOG(TAI_LOG_LEVEL_DEBUG, ":> enter");
#define TAI_META_LOG_DEBUG(format,...) TAI_META_LOG(TAI_LOG_LEVEL_DEBUG, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_INFO(format,...) TAI_META_LOG(TAI_LOG_LEVEL_INFO, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_NOTICE(format,...) TAI_META_LOG(TAI_LOG_LEVEL_NOTICE, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_WARN(format,...) TAI_META_LOG(TAI_LOG_LEVEL_WARN, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_ERROR(format,...) TAI_META_LOG(TAI_LOG_LEVEL_ERROR, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_CRITICAL(format,...) TAI_META_LOG(TAI_LOG_LEVEL_CRITICAL, ":- " format, ##__VA_ARGS__)
#define TAI_META_LOG_EXIT() TAI_META_LOG(TAI_LOG_LEVEL_DEBUG, ":< exit");
/**
* @}
*/
#endif /** __TAIMETADATALOGGER_H_ */

914
meta/taimetadatatypes.h Normal file
View File

@@ -0,0 +1,914 @@
/**
* @file taimetadatatypes.h
*
* @brief This module defines TAI Metadata Types
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#ifndef __TAIMETADATATYPES_H_
#define __TAIMETADATATYPES_H_
/**
* @defgroup TAIMETADATATYPES TAI - Metadata Types Definitions
*
* @{
*/
/**
* @def TAI_INVALID_ATTRIBUTE_ID
*/
#define TAI_INVALID_ATTRIBUTE_ID ((tai_attr_id_t)-1)
/**
* @brief Defines attribute value type.
* Can be used when serializing attributes.
*/
typedef enum _tai_attr_value_type_t
{
/**
* @brief Attribute value is bool.
*/
TAI_ATTR_VALUE_TYPE_BOOLDATA,
/**
* @brief Attribute value is char data.
*/
TAI_ATTR_VALUE_TYPE_CHARDATA,
/**
* @brief Attribute value is 8 bit unsigned integer.
*/
TAI_ATTR_VALUE_TYPE_U8,
/**
* @brief Attribute value is 8 bit signed integer.
*/
TAI_ATTR_VALUE_TYPE_S8,
/**
* @brief Attribute value is 16 bit unsigned integer.
*/
TAI_ATTR_VALUE_TYPE_U16,
/**
* @brief Attribute value is 16 bit signed integer.
*/
TAI_ATTR_VALUE_TYPE_S16,
/**
* @brief Attribute value is 32 bit unsigned integer.
*/
TAI_ATTR_VALUE_TYPE_U32,
/**
* @brief Attribute value is 32 bit signed integer.
*/
TAI_ATTR_VALUE_TYPE_S32,
/**
* @brief Attribute value is 64 bit unsigned integer.
*/
TAI_ATTR_VALUE_TYPE_U64,
/**
* @brief Attribute value is 64 bit signed integer.
*/
TAI_ATTR_VALUE_TYPE_S64,
/**
* @brief Attribute value is float.
*/
TAI_ATTR_VALUE_TYPE_FLT,
/**
* @brief Attribute value is pointer address.
*/
TAI_ATTR_VALUE_TYPE_PTR,
/**
* @brief Attribute value is object id.
*/
TAI_ATTR_VALUE_TYPE_OID,
/**
* @brief Attribute value is object list.
*/
TAI_ATTR_VALUE_TYPE_OBJLIST,
/**
* @brief Attribute value is list of char.
*/
TAI_ATTR_VALUE_TYPE_CHARLIST,
/**
* @brief Attribute value is list of 8 bit unsigned integers.
*/
TAI_ATTR_VALUE_TYPE_U8LIST,
/**
* @brief Attribute value is list of 8 bit signed integers.
*/
TAI_ATTR_VALUE_TYPE_S8LIST,
/**
* @brief Attribute value is list of 16 bit unsigned integers.
*/
TAI_ATTR_VALUE_TYPE_U16LIST,
/**
* @brief Attribute value is list of 16 bit signed integers.
*/
TAI_ATTR_VALUE_TYPE_S16LIST,
/**
* @brief Attribute value is list of 32 bit unsigned integers.
*/
TAI_ATTR_VALUE_TYPE_U32LIST,
/**
* @brief Attribute value is list of 32 bit signed integers.
*/
TAI_ATTR_VALUE_TYPE_S32LIST,
/**
* @brief Attribute value is list of float.
*/
TAI_ATTR_VALUE_TYPE_FLOATLIST,
/**
* @brief Attribute value is 32 bit unsigned integer range.
*/
TAI_ATTR_VALUE_TYPE_U32RANGE,
/**
* @brief Attribute value is 32 bit signed integer range.
*/
TAI_ATTR_VALUE_TYPE_S32RANGE,
/**
* @brief Attribute value is object map list.
*/
TAI_ATTR_VALUE_TYPE_OBJMAPLIST,
} tai_attr_value_type_t;
/**
* @brief Attribute flags.
*
* @flags Contains flags
*/
typedef enum _tai_attr_flags_t
{
/**
* @brief Mandatory on create flag.
*
* Attribute with this flag is mandatory when calling CREATE API, unless
* this attribute is marked as conditional. Must be combined with
* CREATE_ONLY or CREATE_AND_SET flag.
*/
TAI_ATTR_FLAGS_MANDATORY_ON_CREATE = (1 << 0),
/**
* @brief Create only flag.
*
* Attribute with this flag can only be created and its value cannot be
* changed by SET API. Can be combined with MANDATORY flag. If
* attribute is not combined with MANDATORY flag then DEFAULT value must be
* provided for this attribute.
*/
TAI_ATTR_FLAGS_CREATE_ONLY = (1 << 1),
/**
* @brief Create and set flag.
*
* Attribute with this flag can be created and after creation value may be
* modified using SET API. Can be combined with MANDATORY flag. If
* attribute is not combined with MANDATORY flag then DEFAULT value must be
* provided for this attribute.
*/
TAI_ATTR_FLAGS_CREATE_AND_SET = (1 << 2),
/**
* @brief Read only flag.
*
* Attribute with this flag can only be read using GET API. Creation and
* modification is not possible. Can be combined with DYNAMIC flag for
* example counter attribute.
*/
TAI_ATTR_FLAGS_READ_ONLY = (1 << 3),
/**
* @brief Key flag.
*
* Attribute with this flag is treated as unique key (can only be combined
* with MANDATORY and CREATE_ONLY flags. This flag will indicate that
* creating new object with the same key will fail (for example VLAN).
* There may be more than one key in attributes when creating object. Key
* should be used only on primitive attribute values (like enum or int).
* In some cases it may be supported on list (for port lanes) but then
* extra logic is needed to compute and handle that key.
*
* If multiple keys are provided, meta key is created as combination of
* keys in order attribute ids are declared (internal details).
*/
TAI_ATTR_FLAGS_KEY = (1 << 4),
/**
* @brief Dynamic flag.
*
* Attribute with this flag indicates that value of the attribute is
* dynamic and can change in time (like an attribute counter value, or port
* operational status). Change may happen independently or when other
* attribute was created or modified (creating vlan member will change vlan
* member list). Can be combined with READ_ONLY flag.
*/
TAI_ATTR_FLAGS_DYNAMIC = (1 << 5),
/**
* @brief Special flag.
*
* Attribute with this flag will indicate that this attribute is special
* and it needs extended logic to be handled. This flag can only be
* standalone.
*/
TAI_ATTR_FLAGS_SPECIAL = (1 << 6),
} tai_attr_flags_t;
/**
* @def Defines helper to check if mandatory on create flag is set.
*/
#define TAI_HAS_FLAG_MANDATORY_ON_CREATE(x) (((x) & TAI_ATTR_FLAGS_MANDATORY_ON_CREATE) == TAI_ATTR_FLAGS_MANDATORY_ON_CREATE)
/**
* @def Defines helper to check if create only flag is set.
*/
#define TAI_HAS_FLAG_CREATE_ONLY(x) (((x) & TAI_ATTR_FLAGS_CREATE_ONLY) == TAI_ATTR_FLAGS_CREATE_ONLY)
/**
* @def Defines helper to check if create and set flag is set.
*/
#define TAI_HAS_FLAG_CREATE_AND_SET(x) (((x) & TAI_ATTR_FLAGS_CREATE_AND_SET) == TAI_ATTR_FLAGS_CREATE_AND_SET)
/**
* @def Defines helper to check if read only flag is set.
*/
#define TAI_HAS_FLAG_READ_ONLY(x) (((x) & TAI_ATTR_FLAGS_READ_ONLY) == TAI_ATTR_FLAGS_READ_ONLY)
/**
* @def Defines helper to check if key flag is set.
*/
#define TAI_HAS_FLAG_KEY(x) (((x) & TAI_ATTR_FLAGS_KEY) == TAI_ATTR_FLAGS_KEY)
/**
* @def Defines helper to check if dynamic flag is set.
*/
#define TAI_HAS_FLAG_DYNAMIC(x) (((x) & TAI_ATTR_FLAGS_DYNAMIC) == TAI_ATTR_FLAGS_DYNAMIC)
/**
* @def Defines helper to check if special flag is set.
*/
#define TAI_HAS_FLAG_SPECIAL(x) (((x) & TAI_ATTR_FLAGS_SPECIAL) == TAI_ATTR_FLAGS_SPECIAL)
/**
* @brief Defines default value type.
*/
typedef enum _tai_default_value_type_t
{
/**
* @brief There is no default value.
*
* This must be assigned on MANDATORY_ON_CREATE
* attributes.
*/
TAI_DEFAULT_VALUE_TYPE_NONE = 0,
/**
* @brief Default value is just a const value.
*/
TAI_DEFAULT_VALUE_TYPE_CONST,
/**
* @brief Value must be in range provided by other attribute.
*
* Usually value is provided by switch object.
* Range can be obtained by GET API.
* Usually default value is minimum of range.
*/
TAI_DEFAULT_VALUE_TYPE_ATTR_RANGE,
/**
* @brief Default value is equal to other attribute value.
*
* Usually value is provided by switch object.
* Can be obtained using GET API.
*/
TAI_DEFAULT_VALUE_TYPE_ATTR_VALUE,
/**
* @brief Default value is just empty list.
*/
TAI_DEFAULT_VALUE_TYPE_EMPTY_LIST,
/**
* @brief Default value is vendor specific.
*
* This value is assigned by switch vendor
* like default switch MAC address.
*
* It can also be default created object
* like default hash.
*
* Vendor specific should be different
* from default objects that are created
* by default.
*/
TAI_DEFAULT_VALUE_TYPE_VENDOR_SPECIFIC,
} tai_default_value_type_t;
/**
* @brief Defines attribute condition type.
*/
typedef enum _tai_attr_condition_type_t
{
/**
* @brief This attribute is not conditional attribute
*/
TAI_ATTR_CONDITION_TYPE_NONE = 0,
/**
* @brief Any condition that will be true will make
* this attribute mandatory.
*/
TAI_ATTR_CONDITION_TYPE_OR,
/**
* @brief All conditions must meet for this attribute
* to be mandatory on create.
*/
TAI_ATTR_CONDITION_TYPE_AND,
} tai_attr_condition_type_t;
/**
* @brief Defines attribute condition.
*/
typedef struct _tai_attr_condition_t
{
/**
* @brief Specifies valid attribute id for this object type.
* Attribute is for the same object type.
*/
tai_attr_id_t attrid;
/**
* @brief Condition value that attribute will be mandatory
* then default value must be provided for attribute.
*/
const tai_attribute_value_t condition;
/*
* In future we can add condition operator like equal, not equal, etc.
*/
} tai_attr_condition_t;
/**
* @brief Defines enum metadata information.
*/
typedef struct _tai_enum_metadata_t
{
#ifdef __cplusplus
_tai_enum_metadata_t(): name(nullptr),
valuescount(0),
values(nullptr),
valuesnames(nullptr),
valuesshortnames(nullptr){}
#endif
/**
* @brief String representation of enum type definition.
*/
const char* const name;
/**
* @brief Values count in enum.
*/
const size_t valuescount;
/**
* @brief Array of enum values.
*/
const int* const values;
/**
* @brief Array of enum values string names.
*/
const char* const* const valuesnames;
/**
* @brief Array of enum values string short names.
*/
const char* const* const valuesshortnames;
/**
* @brief Indicates whether enumeration contains flags.
*
* When set to true numbers of enumeration are not continuous.
*/
bool containsflags;
} tai_enum_metadata_t;
/**
* @brief Defines attribute metadata.
*/
typedef struct _tai_attr_metadata_t
{
/**
* @brief Specifies valid TAI object type.
*/
tai_object_type_t objecttype;
/**
* @brief Specifies valid attribute id for this object type.
*/
tai_attr_id_t attrid;
/**
* @brief Specifies valid attribute id name for this object type.
*/
const char* const attridname;
/**
* @brief Specifies valid short attribute id name for this object type.
*/
const char* const attridshortname;
/**
* @brief Extracted brief description from Doxygen comment.
*/
const char* const brief;
/**
* @brief Specifies attribute value type for this attribute.
*/
tai_attr_value_type_t attrvaluetype;
/**
* @brief Specifies flags for this attribute.
*/
tai_attr_flags_t flags;
/**
* @brief Specified allowed object types.
*
* If object attr value type is OBJECT_ID
* this list specifies what object type can be used.
*/
const tai_object_type_t* const allowedobjecttypes;
/**
* @brief Length of allowed object types.
*/
size_t allowedobjecttypeslength;
/**
* @brief Allows repetitions on object list.
*
* Can be useful when using object id list.
*/
bool allowrepetitiononlist;
/**
* @brief Allows mixed object id types on list
* like port and LAG.
*/
bool allowmixedobjecttypes;
/**
* @brief Allows empty list to be set on list value type.
*/
bool allowemptylist;
/**
* @brief Allows null object id to be passed.
*
* If object attr value type is OBJECT_ID
* it tells whether TAI_NULL_OBJECT_ID can be used
* as actual id.
*/
bool allownullobjectid;
/**
* @brief Determines whether attribute contains OIDs
*/
bool isoidattribute;
/**
* @brief Specifies default value type.
*
* Default value can be a const assigned by switch
* (which is not known at compile), can be obtained
* by GET API, or a min/max value in specific
* range also assigned by switch at run time.
*
* Default value can be also an object id.
*/
const tai_default_value_type_t defaultvaluetype;
/**
* @brief Provides default value.
*
* If creation flag is CREATE_ONLY or CREATE_AND_SET
* then default value must be provided for attribute.
*
* @note Default value may not apply for ACL field
* or ACL entry, need special care.
*/
const tai_attribute_value_t* const defaultvalue;
/**
* @brief Default value object type.
*
* Required when default value type is pointing to
* different object type.
*/
tai_object_type_t defaultvalueobjecttype;
/**
* @brief Default value object id.
*
* Required when default value type is pointing to
* different object attribute.
*/
tai_attr_id_t defaultvalueattrid;
/**
* @brief Indicates whether default value needs to be saved.
*
* When switch is created some objects are created internally like vlan 1,
* vlan members, bridge port, virtual router etc. Some of those objects
* has attributes assigned by vendor like switch MAC address. When user
* changes that value then there is no way to go back and set it's previous
* value if user didn't query it first. This member will indicate whether
* user needs to query it first (and store) before change, if he wants to
* bring original attribute value later.
*
* Some of those attributes can be OID attributes with flags
* MANDATORY_ON_CREATE and CREATE_AND_SET.
*/
bool storedefaultvalue;
/**
* @brief Indicates whether attribute is enum value.
*
* Attribute type must be set as INT32.
*
* @note Could be deduced from enum type string or
* enum vector values and attr value type.
*/
bool isenum;
/**
* @brief Indicates whether attribute is enum list value.
*
* Attribute value must be set INT32 LIST.
*
* @note Could be deduced from enum type string or
* enum vector values and attr value type.
*/
bool isenumlist;
/**
* @brief Provides enum metadata if attribute
* is enum or enum list.
*/
const tai_enum_metadata_t* const enummetadata;
/**
* @brief Specifies condition type of attribute.
*
* @note Currently all conditions are "OR" conditions
* so we can deduce if this is conditional type
* if any conditions are defined.
*/
tai_attr_condition_type_t conditiontype;
/**
* @brief Provide conditions for attribute under
* which this attribute will be mandatory on create.
*/
const tai_attr_condition_t* const* const conditions;
/**
* @brief Length of the conditions.
*/
size_t conditionslength;
/**
* @brief Indicates whether attribute is conditional.
*/
bool isconditional;
/**
* @brief Specifies valid only type of attribute.
*
* @note Currently all valid only are "OR" conditions
* so we can deduce if this is conditional type
* if any conditions are defined.
*/
tai_attr_condition_type_t validonlytype;
/**
* @brief Provides conditions when this attribute is valid.
*
* If conditions are specified (OR condition assumed)
* then this attribute is only valid when different
* attribute has condition value set. Valid only
* attribute (against we check) can be dynamic so
* this attribute can't be marked as MANDATORY on
* create since default value will be required.
*
* @note There is only handful of attributes with
* valid only mark. For now we will check that in
* specific attribute logic.
*/
const tai_attr_condition_t* const* const validonly;
/**
* @brief Length of the valid only when conditions.
*/
size_t validonlylength;
/**
* @brief Indicates whether attribute is valid only.
*/
bool isvalidonly;
/**
* @brief When calling GET API result will be put
* in local db for future use (extra logic).
*
* This flag must be taken with care, since when set
* on dynamic attribute it may provide inconsistent data.
*
* Value should be updated after successful set or remove.
*/
bool getsave;
/**
* @brief Determines whether value is vlan.
*
* Can only be set on tai_uint16_t value type.
*/
bool isvlan;
/**
* @brief Determines whether attribute is ACL field
*
* This will become handy for fast determination whether
* default value is present.
*/
bool isaclfield;
/**
* @brief Determines whether attribute is ACL action
*
* This will become handy for fast determination whether
* default value is present.
*/
bool isaclaction;
/**
* @brief Determines whether attribute is mandatory on create
*/
bool ismandatoryoncreate;
/**
* @brief Determines whether attribute is create only
*/
bool iscreateonly;
/**
* @brief Determines whether attribute is create and set
*/
bool iscreateandset;
/**
* @brief Determines whether attribute is read only
*/
bool isreadonly;
/**
* @brief Determines whether attribute is key
*/
bool iskey;
/**
* @brief Determines whether attribute value is primitive.
*
* Primitive values will not contain any pointers so value can be
* transferred by regular assignment operator.
*/
bool isprimitive;
/**
* @brief Notification type
*
* If attribute value type is POINTER then attribute
* value is pointer to switch notification.
* Enum tai_switch_notification_type_t is auto generated
* so it can't be used here, int will be used instead.
*/
int notificationtype;
} tai_attr_metadata_t;
/**
* @brief Defines struct member info for
* non object id object type
*/
typedef struct _tai_struct_member_info_t
{
/**
* @brief Member value type
*/
tai_attr_value_type_t membervaluetype;
/**
* @brief Member name
*/
const char* const membername;
/**
* @brief Indicates whether field is vlan
*/
bool isvlan;
/**
* @brief Specified allowed object types.
*
* If object attr value type is OBJECT_ID
* this list specifies what object type can be used.
*/
const tai_object_type_t* const allowedobjecttypes;
/**
* @brief Length of allowed object types.
*/
size_t allowedobjecttypeslength;
/**
* @brief Indicates whether member is enum value.
*
* Type must be set as INT32.
*
* @note Could be deduced from enum type string or
* enum vector values and attr value type.
*/
bool isenum;
/**
* @brief Provides enum metadata if member is enum
*/
const tai_enum_metadata_t* const enummetadata;
} tai_struct_member_info_t;
/**
* @brief TAI reverse graph member
*/
typedef struct _tai_rev_graph_member_t
{
/**
* @brief Defines main object type which is used
* by dependency object type.
*/
tai_object_type_t objecttype;
/**
* @brief Defines dependency object type on which
* is object type defined above is used.
*/
tai_object_type_t depobjecttype;
/**
* @brief Defines attribute metadata for object type
*
* This can be NULL if dependency object type
* is non object id type and dependency is on
* defined struct.
*/
const tai_attr_metadata_t* const attrmetadata;
/**
* @brief Defines struct member for non object
* id object type.
*
* This member can be NULL if dependency object type
* is object attribute, and is not NULL id object
* dependency is non object id struct member.
*/
const tai_struct_member_info_t* const structmember;
} tai_rev_graph_member_t;
/**
* @brief TAI object type information
*/
typedef struct _tai_object_type_info_t
{
/**
* @brief Object Type
*/
tai_object_type_t objecttype;
/**
* @brief Object Type name
*/
const char* const objecttypename;
/**
* @brief Start of attributes *_START
*/
tai_attr_id_t attridstart;
/**
* @brief End of attributes *_END
*/
tai_attr_id_t attridend;
/**
* @brief Provides enum metadata if attribute
* is enum or enum list.
*/
const tai_enum_metadata_t* const enummetadata;
/**
* @brief Attributes metadata
*/
const tai_attr_metadata_t* const* const attrmetadata;
/**
* @brief Attributes metadata length.
*/
size_t attrmetadatalength;
/**
* @brief Indicates if object is using struct
* instead of actual object id
*/
bool isnonobjectid;
/**
* @brief Indicates if object is OID object
*/
bool isobjectid;
/**
* @brief Defines all struct members
*/
const tai_struct_member_info_t* const* const structmembers;
/**
* @brief Defines count of struct members
*/
size_t structmemberscount;
/**
* @brief Defines reverse dependency graph members
*/
const tai_rev_graph_member_t* const* const revgraphmembers;
/**
* @brief Defines reverse dependency graph members count.
*/
size_t revgraphmemberscount;
} tai_object_type_info_t;
/**
* @}
*/
#endif /** __TAIMETADATATYPES_H_ */

332
meta/taimetadatautils.c Normal file
View File

@@ -0,0 +1,332 @@
/**
* @file taimetadatautils.c
*
* @brief This module implements TAI Metadata Utilities
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#include <stdio.h>
#include <string.h>
#include <tai.h>
#include "taimetadatautils.h"
#include "taimetadata.h"
bool tai_metadata_is_allowed_object_type(
_In_ const tai_attr_metadata_t* metadata,
_In_ tai_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 tai_metadata_is_allowed_enum_value(
_In_ const tai_attr_metadata_t* metadata,
_In_ int value)
{
if (metadata == NULL || metadata->enummetadata == NULL)
{
return false;
}
size_t i = 0;
const tai_enum_metadata_t *emd = metadata->enummetadata;
for (; i < emd->valuescount; ++i)
{
if (emd->values[i] == value)
{
return true;
}
}
return false;
}
const tai_attr_metadata_t* tai_metadata_get_attr_metadata(
_In_ tai_object_type_t objecttype,
_In_ tai_attr_id_t attrid)
{
if (tai_metadata_is_object_type_valid(objecttype))
{
const tai_attr_metadata_t* const* const md = tai_metadata_attr_by_object_type[objecttype];
/*
* Most obejct attributes are not flags, so we can use direct index to
* find attribute metadata, this should speed up search.
*/
const tai_object_type_info_t* oi = tai_metadata_all_object_type_infos[objecttype];
if (!oi->enummetadata->containsflags && attrid < oi->enummetadata->valuescount)
{
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 tai_attr_metadata_t* tai_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)(tai_metadata_attr_sorted_by_id_name_count - 1);
while (first <= last)
{
ssize_t middle = (first + last) / 2;
int res = strcmp(attr_id_name, tai_metadata_attr_sorted_by_id_name[middle]->attridname);
if (res > 0)
{
first = middle + 1;
}
else if (res < 0)
{
last = middle - 1;
}
else
{
/* found */
return tai_metadata_attr_sorted_by_id_name[middle];
}
}
/* not found */
return NULL;
}
const char* tai_metadata_get_enum_value_name(
_In_ const tai_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 tai_attribute_t* tai_metadata_get_attr_by_id(
_In_ tai_attr_id_t id,
_In_ uint32_t attr_count,
_In_ const tai_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 tai_object_type_info_t* tai_metadata_get_object_type_info(
_In_ tai_object_type_t object_type)
{
if (tai_metadata_is_object_type_valid(object_type))
{
return tai_metadata_all_object_type_infos[object_type];
}
return NULL;
}
bool tai_metadata_is_object_type_valid(
_In_ tai_object_type_t object_type)
{
return object_type > TAI_OBJECT_TYPE_NULL && object_type < TAI_OBJECT_TYPE_MAX;
}
bool tai_metadata_is_condition_met(
_In_ const tai_attr_metadata_t *metadata,
_In_ uint32_t attr_count,
_In_ const tai_attribute_t *attr_list)
{
if (metadata == NULL || !metadata->isconditional || attr_list == NULL)
{
return false;
}
size_t idx = 0;
bool met = (metadata->conditiontype == TAI_ATTR_CONDITION_TYPE_AND);
for (; idx < metadata->conditionslength; ++idx)
{
const tai_attr_condition_t *condition = metadata->conditions[idx];
/*
* Conditons may only be on the same object type.
*
* Default value may not exists if conditional object is marked as
* MANDATORY_ON_CREATE.
*/
const tai_attr_metadata_t *cmd = tai_metadata_get_attr_metadata(metadata->objecttype, condition->attrid);
const tai_attribute_t *cattr = tai_metadata_get_attr_by_id(condition->attrid, attr_count, attr_list);
const tai_attribute_value_t* cvalue = NULL;
if (cattr == NULL)
{
/*
* User didn't passed conditional attribute, so check if there is
* default value.
*/
cvalue = cmd->defaultvalue;
}
else
{
cvalue = &cattr->value;
}
if (cvalue == NULL)
{
/*
* There is no default value and user didn't passed attribute.
*/
if (metadata->conditiontype == TAI_ATTR_CONDITION_TYPE_AND)
{
return false;
}
continue;
}
bool current = false;
switch (cmd->attrvaluetype)
{
case TAI_ATTR_VALUE_TYPE_BOOLDATA:
current = (condition->condition.booldata == cvalue->booldata);
break;
case TAI_ATTR_VALUE_TYPE_S8:
current = (condition->condition.s8 == cvalue->s8);
break;
case TAI_ATTR_VALUE_TYPE_S16:
current = (condition->condition.s16 == cvalue->s16);
break;
case TAI_ATTR_VALUE_TYPE_S32:
current = (condition->condition.s32 == cvalue->s32);
break;
case TAI_ATTR_VALUE_TYPE_S64:
current = (condition->condition.s64 == cvalue->s64);
break;
case TAI_ATTR_VALUE_TYPE_U8:
current = (condition->condition.u8 == cvalue->u8);
break;
case TAI_ATTR_VALUE_TYPE_U16:
current = (condition->condition.u16 == cvalue->u16);
break;
case TAI_ATTR_VALUE_TYPE_U32:
current = (condition->condition.u32 == cvalue->u32);
break;
case TAI_ATTR_VALUE_TYPE_U64:
current = (condition->condition.u64 == cvalue->u64);
break;
default:
/*
* We should never get here since sanity check tests all
* attributes and all conditions.
*/
TAI_META_LOG_ERROR("condition value type %d is not supported, FIXME", cmd->attrvaluetype);
return false;
}
if (metadata->conditiontype == TAI_ATTR_CONDITION_TYPE_AND)
{
met &= current;
}
else /* OR */
{
met |= current;
}
}
return met;
}

161
meta/taimetadatautils.h Normal file
View File

@@ -0,0 +1,161 @@
/**
* @file taimetadatautils.h
*
* @brief This module defines TAI Metadata Utilities
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#ifndef __TAIMETADATAUTILS_H_
#define __TAIMETADATAUTILS_H_
#include "taimetadatatypes.h"
/**
* @defgroup TAIMETADATAUTILS TAI - Metadata Utilities Definitions
*
* @{
*/
/**
* @brief Is allowed object type
*
* @param[in] metadata Attribute metadata
* @param[in] object_type Object type to be checked
*
* @return True if object is allowed on this attribute, false otherwise
*/
extern bool tai_metadata_is_allowed_object_type(
_In_ const tai_attr_metadata_t *metadata,
_In_ tai_object_type_t object_type);
/**
* @brief Is allowed enum value
*
* @param[in] metadata Attribute metadata
* @param[in] value Enum value to be checked
*
* @return True if enum value is allowed on this attribute, false otherwise
*/
extern bool tai_metadata_is_allowed_enum_value(
_In_ const tai_attr_metadata_t *metadata,
_In_ int value);
/**
* @brief Gets attribute metadata based on object type and attribute id
*
* @param[in] object_type Object type
* @param[in] attr_id Attribute Id
*
* @return Pointer to object metadata or NULL in case of failure
*/
extern const tai_attr_metadata_t* tai_metadata_get_attr_metadata(
_In_ tai_object_type_t object_type,
_In_ tai_attr_id_t attr_id);
/**
* @brief Gets attribute metadata based on attribute id name
*
* @param[in] attr_id_name Attribute id name
*
* @return Pointer to object metadata or NULL in case of failure
*/
extern const tai_attr_metadata_t* tai_metadata_get_attr_metadata_by_attr_id_name(
_In_ const char *attr_id_name);
/**
* @brief Gets string representation of enum value
*
* @param[in] metadata Enum metadata
* @param[in] value Enum value to be converted to string
*
* @return String representation of enum value or NULL if value was not found
*/
extern const char* tai_metadata_get_enum_value_name(
_In_ const tai_enum_metadata_t *metadata,
_In_ int value);
/**
* @brief Gets attribute from attribute list by attribute id.
*
* @param[in] id Attribute id to be found.
* @param[in] attr_count Total number of attributes.
* @param[in] attr_list List of attributes to search.
*
* @return Attribute pointer with requested ID or NULL if not found.
* When multiple attributes with the same id are passed, only first
* attribute is returned.
*/
extern const tai_attribute_t* tai_metadata_get_attr_by_id(
_In_ tai_attr_id_t id,
_In_ uint32_t attr_count,
_In_ const tai_attribute_t *attr_list);
/**
* @brief Gets object type info
*
* @param[in] object_type Object type
*
* @return Object type info structure or NULL if not found
*/
extern const tai_object_type_info_t* tai_metadata_get_object_type_info(
_In_ tai_object_type_t object_type);
/**
* @brief Checks if object type is valid
*
* @param[in] object_type Object type
*
* @return True if object type is valid, false otherwise
*/
extern bool tai_metadata_is_object_type_valid(
_In_ tai_object_type_t object_type);
/**
* @brief Check if condition met.
*
* List of attributes will be examined in terms of conditions. This is
* convenient since user can pass list when calling create API. If
* condition attribute is not on the list, then default value will be
* examined.
*
* NOTE: When multiple attributes with the same ID are passed,
* tai_metadata_get_attr_by_id will select only first one.
* Function will not be able to handle multiple attributes
*
* @param[in] metadata Metadata of attribute that we need to check.
* @param[in] attr_count Number of attributes.
* @param[in] attr_list Attribute list to check. All attributes must
* belong to the same object type as metadata parameter.
*
* @return True if condition is in force, false otherwise. False will be also
* returned if any of input pointers is NULL or attribute is not conditional.
*/
extern bool tai_metadata_is_condition_met(
_In_ const tai_attr_metadata_t *metadata,
_In_ uint32_t attr_count,
_In_ const tai_attribute_t *attr_list);
/**
* @}
*/
#endif /** __TAIMETADATAUTILS_H_ */

740
meta/taiserialize.c Normal file
View File

@@ -0,0 +1,740 @@
/**
* @file taiserialize.c
*
* @brief This file implements basic serialization functions for
* TAI attributes
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#include <arpa/inet.h>
#include <byteswap.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <tai.h>
#include "taimetadatautils.h"
#include "taimetadatalogger.h"
#include "taiserialize.h"
#define PRIMITIVE_BUFFER_SIZE 128
#define MAX_CHARS_PRINT 25
bool tai_serialize_is_char_allowed(
_In_ char c)
{
/*
* When we will perform deserialize, we allow buffer string to be
* terminated not only by zero, but also with json characters like:
*
* - end of quote
* - comma, next item in array
* - end of array
*
* This will be handy when performing deserialize.
*/
return c == 0 || c == '"' || c == ',' || c == ']' || c == '}';
}
int tai_serialize_bool(
_Out_ char *buffer,
_In_ bool flag)
{
return sprintf(buffer, "%s", flag ? "true" : "false");
}
#define TAI_TRUE_LENGTH 4
#define TAI_FALSE_LENGTH 5
int tai_deserialize_bool(
_In_ const char *buffer,
_Out_ bool *flag)
{
if (strncmp(buffer, "true", TAI_TRUE_LENGTH) == 0 &&
tai_serialize_is_char_allowed(buffer[TAI_TRUE_LENGTH]))
{
*flag = true;
return TAI_TRUE_LENGTH;
}
if (strncmp(buffer, "false", TAI_FALSE_LENGTH) == 0 &&
tai_serialize_is_char_allowed(buffer[TAI_FALSE_LENGTH]))
{
*flag = false;
return TAI_FALSE_LENGTH;
}
/*
* Limit printf to maximum "false" length + 1 if there is invalid character
* after "false" string.
*/
TAI_META_LOG_WARN("failed to deserialize '%.*s' as bool",
TAI_FALSE_LENGTH + 1,
buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_chardata(
_Out_ char *buffer,
_In_ const char data[TAI_CHARDATA_LENGTH])
{
int idx;
for (idx = 0; idx < TAI_CHARDATA_LENGTH; ++idx)
{
char c = data[idx];
if (c == 0)
{
break;
}
if (isprint(c) && c != '\\' && c != '"')
{
buffer[idx] = c;
continue;
}
TAI_META_LOG_WARN("invalid character 0x%x in chardata", c);
return TAI_SERIALIZE_ERROR;
}
buffer[idx] = 0;
return idx;
}
int tai_deserialize_chardata(
_In_ const char *buffer,
_Out_ char data[TAI_CHARDATA_LENGTH])
{
int idx;
memset(data, 0, TAI_CHARDATA_LENGTH);
for (idx = 0; idx < TAI_CHARDATA_LENGTH; ++idx)
{
char c = buffer[idx];
if (isprint(c) && c != '\\' && c != '"')
{
data[idx] = c;
continue;
}
if (c == 0)
{
break;
}
if (c == '"')
{
/*
* We allow quote as last char since chardata will be serialized in
* quotes.
*/
break;
}
TAI_META_LOG_WARN("invalid character 0x%x in chardata", c);
return TAI_SERIALIZE_ERROR;
}
if (tai_serialize_is_char_allowed(buffer[idx]))
{
return idx;
}
TAI_META_LOG_WARN("invalid character 0x%x in chardata", buffer[idx]);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_uint8(
_Out_ char *buffer,
_In_ uint8_t u8)
{
return sprintf(buffer, "%u", u8);
}
int tai_deserialize_uint8(
_In_ const char *buffer,
_Out_ uint8_t *u8)
{
uint64_t u64;
int res = tai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= UCHAR_MAX)
{
*u8 = (uint8_t)u64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as uint8", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_int8(
_Out_ char *buffer,
_In_ int8_t u8)
{
return sprintf(buffer, "%d", u8);
}
int tai_deserialize_int8(
_In_ const char *buffer,
_Out_ int8_t *s8)
{
int64_t s64;
int res = tai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= CHAR_MIN && s64 <= CHAR_MAX)
{
*s8 = (int8_t)s64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as int8", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_uint16(
_Out_ char *buffer,
_In_ uint16_t u16)
{
return sprintf(buffer, "%u", u16);
}
int tai_deserialize_uint16(
_In_ const char *buffer,
_Out_ uint16_t *u16)
{
uint64_t u64;
int res = tai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= USHRT_MAX)
{
*u16 = (uint16_t)u64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as uint16", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_int16(
_Out_ char *buffer,
_In_ int16_t s16)
{
return sprintf(buffer, "%d", s16);
}
int tai_deserialize_int16(
_In_ const char *buffer,
_Out_ int16_t *s16)
{
int64_t s64;
int res = tai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= SHRT_MIN && s64 <= SHRT_MAX)
{
*s16 = (int16_t)s64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as int16", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_uint32(
_Out_ char *buffer,
_In_ uint32_t u32)
{
return sprintf(buffer, "%u", u32);
}
int tai_deserialize_uint32(
_In_ const char *buffer,
_Out_ uint32_t *u32)
{
uint64_t u64;
int res = tai_deserialize_uint64(buffer, &u64);
if (res > 0 && u64 <= UINT_MAX)
{
*u32 = (uint32_t)u64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as uint32", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_int32(
_Out_ char *buffer,
_In_ int32_t s32)
{
return sprintf(buffer, "%d", s32);
}
int tai_deserialize_int32(
_In_ const char *buffer,
_Out_ int32_t *s32)
{
int64_t s64;
int res = tai_deserialize_int64(buffer, &s64);
if (res > 0 && s64 >= INT_MIN && s64 <= INT_MAX)
{
*s32 = (int32_t)s64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as int32", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_uint64(
_Out_ char *buffer,
_In_ uint64_t u64)
{
return sprintf(buffer, "%lu", u64);
}
#define TAI_BASE_10 10
int tai_deserialize_uint64(
_In_ const char *buffer,
_Out_ uint64_t *u64)
{
int idx = 0;
uint64_t result = 0;
while (isdigit(buffer[idx]))
{
char c = (char)(buffer[idx] - '0');
/*
* Base is 10 we can check, that if result is greater than (2^64-1)/10)
* then next multiplication with 10 will cause overflow.
*/
if (result > (ULONG_MAX/TAI_BASE_10) ||
((result == ULONG_MAX/TAI_BASE_10) && (c > (char)(ULONG_MAX % TAI_BASE_10))))
{
idx = 0;
break;
}
result = result * 10 + (uint64_t)(c);
idx++;
}
if (idx > 0 && tai_serialize_is_char_allowed(buffer[idx]))
{
*u64 = result;
return idx;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s...' as uint64", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_int64(
_Out_ char *buffer,
_In_ int64_t s64)
{
return sprintf(buffer, "%ld", s64);
}
int tai_deserialize_int64(
_In_ const char *buffer,
_Out_ int64_t *s64)
{
uint64_t result = 0;
bool negative = 0;
if (*buffer == '-')
{
buffer++;
negative = true;
}
int res = tai_deserialize_uint64(buffer, &result);
if (res > 0)
{
if (negative)
{
if (result <= (uint64_t)(LONG_MIN))
{
*s64 = -(int64_t)result;
return res + 1;
}
}
else
{
if (result <= LONG_MAX)
{
*s64 = (int64_t)result;
return res;
}
}
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as int64", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_float(
_Out_ char *buffer,
_In_ float flt)
{
return sprintf(buffer, "%f", flt);
}
int tai_deserialize_float(
_In_ const char *buffer,
_In_ float *flt)
{
double v = atof(buffer);
*flt = (float)v;
return strlen(buffer);
}
int tai_serialize_size(
_Out_ char *buffer,
_In_ tai_size_t size)
{
return sprintf(buffer, "%zu", size);
}
int tai_deserialize_size(
_In_ const char *buffer,
_Out_ tai_size_t *size)
{
uint64_t u64;
int res = tai_deserialize_uint64(buffer, &u64);
if (res > 0)
{
*size = (tai_size_t)u64;
return res;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s...' as tai_size_t", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_object_id(
_Out_ char *buffer,
_In_ tai_object_id_t oid)
{
return sprintf(buffer, "oid:0x%lx", oid);
}
int tai_deserialize_object_id(
_In_ const char *buffer,
_Out_ tai_object_id_t *oid)
{
int read;
int n = sscanf(buffer, "oid:0x%16lx%n", oid, &read);
if (n == 1 && tai_serialize_is_char_allowed(buffer[read]))
{
return read;
}
TAI_META_LOG_WARN("failed to deserialize '%.*s' as oid", MAX_CHARS_PRINT, buffer);
return TAI_SERIALIZE_ERROR;
}
int tai_serialize_enum(
_Out_ char *buffer,
_In_ const tai_enum_metadata_t* meta,
_In_ int32_t value,
_In_ const tai_serialize_option_t *option)
{
if (meta == NULL)
{
return tai_serialize_int32(buffer, value);
}
bool short_ = false;
if ( option != NULL && option->human ) {
short_ = true;
}
size_t i = 0;
for (; i < meta->valuescount; ++i)
{
if (meta->values[i] == value)
{
if ( short_ ) {
return sprintf(buffer, "%s", meta->valuesshortnames[i]);
} else {
return sprintf(buffer, "%s", meta->valuesnames[i]);
}
}
}
TAI_META_LOG_WARN("enum value %d not found in enum %s", value, meta->name);
return tai_serialize_int32(buffer, value);
}
int tai_deserialize_enum(
_In_ const char *buffer,
_In_ const tai_enum_metadata_t* meta,
_Out_ int32_t *value,
_In_ const tai_serialize_option_t *option)
{
if (meta == NULL)
{
return tai_deserialize_int32(buffer, value);
}
const char* const* names = meta->valuesnames;
if ( option != NULL && option->human ) {
names = meta->valuesshortnames;
}
size_t idx = 0;
for (; idx < meta->valuescount; ++idx)
{
size_t len = strlen(names[idx]);
if (strncmp(names[idx], buffer, len) == 0 &&
tai_serialize_is_char_allowed(buffer[len]))
{
*value = meta->values[idx];
return (int)len;
}
}
TAI_META_LOG_WARN("enum value '%.*s' not found in enum %s", MAX_CHARS_PRINT, buffer, meta->name);
return tai_deserialize_int32(buffer, value);
}
int tai_serialize_attribute(
_Out_ char *buffer,
_In_ const tai_attr_metadata_t *meta,
_In_ const tai_attribute_t *attr,
_In_ const tai_serialize_option_t *option)
{
int i;
char *ptr = buffer;
if ( option == NULL || !option->valueonly ) {
if ( option != NULL && option->human ) {
ptr += sprintf(ptr, "%s | ", meta->attridshortname);
} else {
ptr += sprintf(ptr, "%s | ", meta->attridname);
}
}
switch ( meta->attrvaluetype ) {
case TAI_ATTR_VALUE_TYPE_BOOLDATA:
return tai_serialize_bool(ptr, attr->value.booldata);
case TAI_ATTR_VALUE_TYPE_CHARDATA:
return tai_serialize_chardata(ptr, attr->value.chardata);
case TAI_ATTR_VALUE_TYPE_U8:
return tai_serialize_uint8(ptr, attr->value.u8);
case TAI_ATTR_VALUE_TYPE_S8:
return tai_serialize_int8(ptr, attr->value.s8);
case TAI_ATTR_VALUE_TYPE_U16:
return tai_serialize_uint16(ptr, attr->value.u16);
case TAI_ATTR_VALUE_TYPE_S16:
return tai_serialize_int16(ptr, attr->value.s16);
case TAI_ATTR_VALUE_TYPE_U32:
return tai_serialize_uint32(ptr, attr->value.u32);
case TAI_ATTR_VALUE_TYPE_S32:
if ( meta->isenum ) {
return tai_serialize_enum(ptr, meta->enummetadata, attr->value.s32, option);
}
return tai_serialize_int32(ptr, attr->value.s32);
case TAI_ATTR_VALUE_TYPE_U64:
return tai_serialize_uint64(ptr, attr->value.u64);
case TAI_ATTR_VALUE_TYPE_S64:
return tai_serialize_int64(ptr, attr->value.s64);
case TAI_ATTR_VALUE_TYPE_FLT:
return tai_serialize_float(ptr, attr->value.flt);
case TAI_ATTR_VALUE_TYPE_PTR:
TAI_META_LOG_WARN("pointer serialization is not implemented");
return TAI_SERIALIZE_ERROR;
case TAI_ATTR_VALUE_TYPE_OID:
return tai_serialize_object_id(ptr, attr->value.oid);
case TAI_ATTR_VALUE_TYPE_OBJLIST:
for ( i = 0; i < attr->value.objlist.count; i++ ) {
ptr += tai_serialize_object_id(ptr, attr->value.objlist.list[i]);
if ( i + 1 < attr->value.objlist.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_CHARLIST:
memcpy(ptr, attr->value.charlist.list, attr->value.charlist.count);
return ptr - buffer + attr->value.charlist.count;
case TAI_ATTR_VALUE_TYPE_U8LIST:
for ( i = 0; i < attr->value.u8list.count; i++ ) {
ptr += tai_serialize_uint8(ptr, attr->value.u8list.list[i]);
if ( i + 1 < attr->value.u8list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_S8LIST:
for ( i = 0; i < attr->value.s8list.count; i++ ) {
ptr += tai_serialize_int8(ptr, attr->value.s8list.list[i]);
if ( i + 1 < attr->value.s8list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_U16LIST:
for ( i = 0; i < attr->value.u16list.count; i++ ) {
ptr += tai_serialize_uint16(ptr, attr->value.u16list.list[i]);
if ( i + 1 < attr->value.u16list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_S16LIST:
for ( i = 0; i < attr->value.s16list.count; i++ ) {
ptr += tai_serialize_int16(ptr, attr->value.s16list.list[i]);
if ( i + 1 < attr->value.s16list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_U32LIST:
for ( i = 0; i < attr->value.u32list.count; i++ ) {
ptr += tai_serialize_uint32(ptr, attr->value.u32list.list[i]);
if ( i + 1 < attr->value.u32list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_S32LIST:
if ( meta->isenum ) {
for ( i = 0; i < attr->value.s32list.count; i++ ) {
ptr += tai_serialize_enum(ptr, meta->enummetadata, attr->value.s32list.list[i], option);
if ( i + 1 < attr->value.s32list.count ) {
ptr += sprintf(ptr, "|");
}
}
return ptr - buffer;
}
for ( i = 0; i < attr->value.s32list.count; i++ ) {
ptr += tai_serialize_int32(ptr, attr->value.s32list.list[i]);
if ( i + 1 < attr->value.s32list.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_FLOATLIST:
for ( i = 0; i < attr->value.floatlist.count; i++ ) {
ptr += tai_serialize_float(ptr, attr->value.floatlist.list[i]);
if ( i + 1 < attr->value.floatlist.count ) {
ptr += sprintf(ptr, ",");
}
}
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_U32RANGE:
ptr += sprintf(ptr, "%u..%u", attr->value.u32range.min, attr->value.u32range.max);
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_S32RANGE:
ptr += sprintf(ptr, "%d..%d", attr->value.s32range.min, attr->value.s32range.max);
return ptr - buffer;
case TAI_ATTR_VALUE_TYPE_OBJMAPLIST:
TAI_META_LOG_WARN("objmaplist serialization is not implemented");
return TAI_SERIALIZE_ERROR;
default:
TAI_META_LOG_WARN("unknown attr value type");
}
return TAI_SERIALIZE_ERROR;
}
int tai_deserialize_attribute(
_In_ const char *buffer,
_In_ const tai_attr_metadata_t *meta,
_Out_ tai_attribute_t *attribute,
_In_ const tai_serialize_option_t *option)
{
TAI_META_LOG_WARN("not implemented");
return TAI_SERIALIZE_ERROR;
}
int tai_deserialize_attribute_value(
_In_ const char *buffer,
_In_ const tai_attr_metadata_t *meta,
_Out_ tai_attribute_value_t *value,
_In_ const tai_serialize_option_t *option)
{
switch ( meta->attrvaluetype ) {
case TAI_ATTR_VALUE_TYPE_BOOLDATA:
return tai_deserialize_bool(buffer, &value->booldata);
case TAI_ATTR_VALUE_TYPE_CHARDATA:
return tai_deserialize_chardata(buffer, value->chardata);
case TAI_ATTR_VALUE_TYPE_U8:
return tai_deserialize_uint8(buffer, &value->u8);
case TAI_ATTR_VALUE_TYPE_S8:
return tai_deserialize_int8(buffer, &value->s8);
case TAI_ATTR_VALUE_TYPE_U16:
return tai_deserialize_uint16(buffer, &value->u16);
case TAI_ATTR_VALUE_TYPE_S16:
return tai_deserialize_int16(buffer, &value->s16);
case TAI_ATTR_VALUE_TYPE_U32:
return tai_deserialize_uint32(buffer, &value->u32);
case TAI_ATTR_VALUE_TYPE_S32:
if ( meta->isenum ) {
return tai_deserialize_enum(buffer, meta->enummetadata, &value->s32, option);
}
return tai_deserialize_int32(buffer, &value->s32);
case TAI_ATTR_VALUE_TYPE_U64:
return tai_deserialize_uint64(buffer, &value->u64);
case TAI_ATTR_VALUE_TYPE_S64:
return tai_deserialize_int64(buffer, &value->s64);
case TAI_ATTR_VALUE_TYPE_FLT:
return tai_deserialize_float(buffer, &value->flt);
case TAI_ATTR_VALUE_TYPE_PTR:
TAI_META_LOG_WARN("pointer serialization is not implemented");
return TAI_SERIALIZE_ERROR;
}
return TAI_SERIALIZE_ERROR;
}

525
meta/taiserialize.h Normal file
View File

@@ -0,0 +1,525 @@
/**
* @file taiserialize.h
*
* @brief This module defines TAI Serialize methods
*
* @copyright Copyright (c) 2014 Microsoft Open Technologies, Inc.
* @copyright Copyright (c) 2018 Nippon Telegraph and Telephone Corporation
*
* @remark 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
*
* @remark 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.
*
* @remark See the Apache Version 2.0 License for specific language governing
* permissions and limitations under the License.
*
* @remark 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.
*/
#ifndef __TAISERIALIZE_H_
#define __TAISERIALIZE_H_
/**
* @defgroup TAISERIALIZE TAI - Serialize Definitions
*
* @{
*/
/**
* @def TAI_SERIALIZE_ERROR
*
* Returned from serialize/deserialize methods on any error.
* Meta log functions are used to produce specific error message.
*/
#define TAI_SERIALIZE_ERROR (-1)
/**
* @def TAI_CHARDATA_LENGTH
*
* Defines size of char data inside tai_attribute_value_t union.
*/
#define TAI_CHARDATA_LENGTH 32
/**
* @brief Is char allowed.
*
* Function checks if given char is one of the following:
* - '\0', '"', ',', ']', '}'
*
* Since serialization is done to json format, after each value
* there may be some characters specific to json format, like:
*
* * quote, if value was in quotes (string)
* * comma, if value was without quotes but an item in array (number, bool)
* * square bracket, if item was last item in array (number, bool)
* * curly bracket, if item was last item in object (number, bool)
*
* This means that deserialize is "relaxed", so each item don't need to end
* as zero '\0' but it can end on any of those characters. This allows us to
* deserialize json string reading it directly without creating json object
* tree and without any extra string copy. For example if we have item:
* {"foo":true}, we can just read value "true}" and ignore last character and
* still value will be deserialized correctly.
*
* This is not ideal solution, but in this case it will work just fine.
*
* NOTE: All auto generated methods will enforce to check extra characters at
* the end of each value.
*/
bool tai_serialize_is_char_allowed(
_In_ char c);
/**
* @brief Serialize bool value.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] flag Bool flag to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_bool(
_Out_ char *buffer,
_In_ bool flag);
/**
* @brief Deserialize bool value.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] flag Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_bool(
_In_ const char *buffer,
_Out_ bool *flag);
/**
* @brief Serialize char data value.
*
* All printable characters (isprint) are allowed except '\' and '"'.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] data Data to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_chardata(
_Out_ char *buffer,
_In_ const char data[TAI_CHARDATA_LENGTH]);
/**
* @brief Deserialize char data value.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] data Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_chardata(
_In_ const char *buffer,
_Out_ char data[TAI_CHARDATA_LENGTH]);
/**
* @brief Serialize 8 bit unsigned integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] u8 Deserialized value.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_uint8(
_Out_ char *buffer,
_In_ uint8_t u8);
/**
* @brief Deserialize 8 bit unsigned integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] u8 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_uint8(
_In_ const char *buffer,
_Out_ uint8_t *u8);
/**
* @brief Serialize 8 bit signed integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] u8 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_int8(
_Out_ char *buffer,
_In_ int8_t u8);
/**
* @brief Deserialize 8 bit signed integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] s8 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_int8(
_In_ const char *buffer,
_Out_ int8_t *s8);
/**
* @brief Serialize 16 bit unsigned integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] u16 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_uint16(
_Out_ char *buffer,
_In_ uint16_t u16);
/**
* @brief Deserialize 16 bit unsigned integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] u16 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_uint16(
_In_ const char *buffer,
_Out_ uint16_t *u16);
/**
* @brief Serialize 16 bit signed integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] s16 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_int16(
_Out_ char *buffer,
_In_ int16_t s16);
/**
* @brief Deserialize 16 bit signed integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] s16 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_int16(
_In_ const char *buffer,
_Out_ int16_t *s16);
/**
* @brief Serialize 32 bit unsigned integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] u32 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_uint32(
_Out_ char *buffer,
_In_ uint32_t u32);
/**
* @brief Deserialize 32 bit unsigned integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] u32 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_uint32(
_In_ const char *buffer,
_Out_ uint32_t *u32);
/**
* @brief Serialize 32 bit signed integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] s32 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_int32(
_Out_ char *buffer,
_In_ int32_t s32);
/**
* @brief Deserialize 32 bit signed integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] s32 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_int32(
_In_ const char *buffer,
_Out_ int32_t *s32);
/**
* @brief Serialize 64 bit unsigned integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] u64 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_uint64(
_Out_ char *buffer,
_In_ uint64_t u64);
/**
* @brief Deserialize 64 bit unsigned integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] u64 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_uint64(
_In_ const char *buffer,
_Out_ uint64_t *u64);
/**
* @brief Serialize 64 bit signed integer.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] s64 Integer to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_int64(
_Out_ char *buffer,
_In_ int64_t s64);
/**
* @brief Deserialize 64 bit signed integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] s64 Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_int64(
_In_ const char *buffer,
_Out_ int64_t *s64);
/**
* @brief Serialize float.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] Float to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_float(
_Out_ char *buffer,
_In_ float flt);
/**
* @brief Deserialize float.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] Float Deserialized value.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_float(
_In_ const char *buffer,
_Out_ float *flt);
/**
* @brief Serialize tai_size_t.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] size Size to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_size(
_Out_ char *buffer,
_In_ tai_size_t size);
/**
* @brief Deserialize tai_size_t.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] size Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_size(
_In_ const char *buffer,
_Out_ tai_size_t *size);
/**
* @brief Serialize object ID.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] object_id Object ID to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_object_id(
_Out_ char *buffer,
_In_ tai_object_id_t object_id);
/**
* @brief Deserialize object Id.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] object_id Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_object_id(
_In_ const char *buffer,
_Out_ tai_object_id_t *object_id);
/**
* @brief Attribute serialize/deserialize option.
*/
typedef struct _tai_serialize_option_t
{
/**
* @brief use human friendly names
*/
bool human;
/**
* @brief value only
*/
bool valueonly;
} tai_serialize_option_t;
/**
* @brief Serialize enum value.
*
* Buffer will contain actual enum name of number if enum
* value was not found in specified enum metadata.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] meta Enum metadata for serialization info.
* @param[in] value Enum value to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_enum(
_Out_ char *buffer,
_In_ const tai_enum_metadata_t *meta,
_In_ int32_t value,
_In_ const tai_serialize_option_t *option);
/**
* @brief Deserialize enum value.
*
* If buffer will not contain valid enum name, function will attempt to
* deserialize value as signed 32 bit integer.
*
* @param[in] buffer Input buffer to be examined.
* @param[in] meta Enum metadata.
* @param[out] value Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_enum(
_In_ const char *buffer,
_In_ const tai_enum_metadata_t *meta,
_Out_ int32_t *value,
_In_ const tai_serialize_option_t *option);
/**
* @brief Serialize TAI attribute.
*
* @param[out] buffer Output buffer for serialized value.
* @param[in] meta Attribute metadata.
* @param[in] attribute Attribute to be serialized.
*
* @return Number of characters written to buffer excluding '\0',
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_serialize_attribute(
_Out_ char *buffer,
_In_ const tai_attr_metadata_t *meta,
_In_ const tai_attribute_t *attribute,
_In_ const tai_serialize_option_t *option);
/**
* @brief Deserialize TAI attribute.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] attribute Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_attribute(
_In_ const char *buffer,
_In_ const tai_attr_metadata_t *meta,
_Out_ tai_attribute_t *attribute,
_In_ const tai_serialize_option_t *option);
/**
* @brief Deserialize TAI attribute value.
*
* @param[in] buffer Input buffer to be examined.
* @param[out] attribute Deserialized value.
*
* @return Number of characters consumed from the buffer,
* or #TAI_SERIALIZE_ERROR on error.
*/
int tai_deserialize_attribute_value(
_In_ const char *buffer,
_In_ const tai_attr_metadata_t *meta,
_Out_ tai_attribute_value_t *value,
_In_ const tai_serialize_option_t *option);
/**
* @}
*/
#endif /** __TAISERIALIZE_H_ */

1
meta/test/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
test

2
meta/test/Makefile Normal file
View File

@@ -0,0 +1,2 @@
all:
gcc -I ../../inc -I ../ -L .. -o test test.c -lmetatai

85
meta/test/test.c Normal file
View File

@@ -0,0 +1,85 @@
#include "tai.h"
#include "taimetadata.h"
#include "stdio.h"
int test(char *buffer) {
tai_attribute_t attr = {0};
tai_serialize_option_t option = {
.valueonly = true,
};
const tai_attr_metadata_t* meta = tai_metadata_get_attr_metadata(TAI_OBJECT_TYPE_MODULE, TAI_MODULE_ATTR_OPER_STATUS);
attr.id = TAI_MODULE_ATTR_OPER_STATUS;
attr.value.s32 = TAI_MODULE_OPER_STATUS_READY;
return tai_serialize_attribute(buffer, meta, &attr, &option);
}
int test2(char *buffer) {
tai_attribute_t attr = {0};
tai_serialize_option_t option = {
.valueonly = true,
};
const tai_attr_metadata_t* meta = tai_metadata_get_attr_metadata(TAI_OBJECT_TYPE_MODULE, TAI_MODULE_ATTR_TEMP);
attr.id = TAI_MODULE_ATTR_TEMP;
attr.value.flt = 1.10;
return tai_serialize_attribute(buffer, meta, &attr, &option);
}
int test3(char *buffer) {
tai_attribute_t attr = {0};
tai_serialize_option_t option = {
.valueonly = false,
.human = true,
};
const tai_attr_metadata_t* meta = tai_metadata_get_attr_metadata(TAI_OBJECT_TYPE_NETWORKIF, TAI_NETWORK_INTERFACE_ATTR_TX_ALIGN_STATUS);
int32_t list[] = {
TAI_NETWORK_INTERFACE_TX_ALIGN_STATUS_LOSS,
TAI_NETWORK_INTERFACE_TX_ALIGN_STATUS_OUT
};
attr.id = TAI_NETWORK_INTERFACE_ATTR_TX_ALIGN_STATUS;
attr.value.s32list.count = 2;
attr.value.s32list.list = (int32_t*)&list;
return tai_serialize_attribute(buffer, meta, &attr, &option);
}
int test4() {
const tai_attr_metadata_t* meta;
meta = tai_metadata_get_attr_metadata_by_attr_id_name("TAI_NETWORK_INTERFACE_ATTR_TX_LASER_FREQ");
printf("%p\n", meta);
return 0;
}
int test5() {
int32_t value;
int ret;
tai_serialize_option_t option = {
.human = true,
};
ret = tai_deserialize_network_interface_attr("tx-channel", &value, &option);
printf("%d, %d\n", value, ret);
return 0;
}
int main() {
int ret, value;
char buf[128] = {0};
ret = tai_serialize_module_oper_status(buf, TAI_MODULE_OPER_STATUS_READY, NULL);
printf("%s, %d\n", buf, ret);
ret = tai_deserialize_module_oper_status("TAI_MODULE_OPER_STATUS_INITIALIZE", &value, NULL);
printf("%d, %d\n", value, ret);
ret = test(buf);
printf("%s, %d\n", buf, ret);
ret = test2(buf);
printf("%s, %d\n", buf, ret);
ret = test3(buf);
printf("%s, %d\n", buf, ret);
test4();
test5();
}