From efadaf91996d84fe8e169ce7debd104f121ec210 Mon Sep 17 00:00:00 2001 From: Wataru Ishida Date: Thu, 20 Sep 2018 15:16:01 -0700 Subject: [PATCH] meta: initial TAI metadata implementation Signed-off-by: Wataru Ishida --- meta/.gitignore | 3 + meta/Dockerfile | 5 + meta/Makefile | 20 + meta/README.md | 38 ++ meta/main.py | 463 ++++++++++++++++++++ meta/taimetadatalogger.h | 105 +++++ meta/taimetadatatypes.h | 914 +++++++++++++++++++++++++++++++++++++++ meta/taimetadatautils.c | 332 ++++++++++++++ meta/taimetadatautils.h | 161 +++++++ meta/taiserialize.c | 740 +++++++++++++++++++++++++++++++ meta/taiserialize.h | 525 ++++++++++++++++++++++ meta/test/.gitignore | 1 + meta/test/Makefile | 2 + meta/test/test.c | 85 ++++ 14 files changed, 3394 insertions(+) create mode 100644 meta/.gitignore create mode 100644 meta/Dockerfile create mode 100644 meta/Makefile create mode 100644 meta/README.md create mode 100644 meta/main.py create mode 100644 meta/taimetadatalogger.h create mode 100644 meta/taimetadatatypes.h create mode 100644 meta/taimetadatautils.c create mode 100644 meta/taimetadatautils.h create mode 100644 meta/taiserialize.c create mode 100644 meta/taiserialize.h create mode 100644 meta/test/.gitignore create mode 100644 meta/test/Makefile create mode 100644 meta/test/test.c diff --git a/meta/.gitignore b/meta/.gitignore new file mode 100644 index 0000000..dbea70c --- /dev/null +++ b/meta/.gitignore @@ -0,0 +1,3 @@ +*.so +taimetadata.c +taimetadata.h diff --git a/meta/Dockerfile b/meta/Dockerfile new file mode 100644 index 0000000..f23036a --- /dev/null +++ b/meta/Dockerfile @@ -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 diff --git a/meta/Makefile b/meta/Makefile new file mode 100644 index 0000000..063c968 --- /dev/null +++ b/meta/Makefile @@ -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 diff --git a/meta/README.md b/meta/README.md new file mode 100644 index 0000000..c444fae --- /dev/null +++ b/meta/README.md @@ -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 +``` diff --git a/meta/main.py b/meta/main.py new file mode 100644 index 0000000..c128172 --- /dev/null +++ b/meta/main.py @@ -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 +#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 +#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()) diff --git a/meta/taimetadatalogger.h b/meta/taimetadatalogger.h new file mode 100644 index 0000000..be14e19 --- /dev/null +++ b/meta/taimetadatalogger.h @@ -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_ */ diff --git a/meta/taimetadatatypes.h b/meta/taimetadatatypes.h new file mode 100644 index 0000000..552dc04 --- /dev/null +++ b/meta/taimetadatatypes.h @@ -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_ */ diff --git a/meta/taimetadatautils.c b/meta/taimetadatautils.c new file mode 100644 index 0000000..32d8668 --- /dev/null +++ b/meta/taimetadatautils.c @@ -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 +#include +#include +#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; +} diff --git a/meta/taimetadatautils.h b/meta/taimetadatautils.h new file mode 100644 index 0000000..74c5147 --- /dev/null +++ b/meta/taimetadatautils.h @@ -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_ */ diff --git a/meta/taiserialize.c b/meta/taiserialize.c new file mode 100644 index 0000000..1566ebc --- /dev/null +++ b/meta/taiserialize.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/meta/taiserialize.h b/meta/taiserialize.h new file mode 100644 index 0000000..4dc7539 --- /dev/null +++ b/meta/taiserialize.h @@ -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_ */ diff --git a/meta/test/.gitignore b/meta/test/.gitignore new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/meta/test/.gitignore @@ -0,0 +1 @@ +test diff --git a/meta/test/Makefile b/meta/test/Makefile new file mode 100644 index 0000000..4b7e42a --- /dev/null +++ b/meta/test/Makefile @@ -0,0 +1,2 @@ +all: + gcc -I ../../inc -I ../ -L .. -o test test.c -lmetatai diff --git a/meta/test/test.c b/meta/test/test.c new file mode 100644 index 0000000..5cce976 --- /dev/null +++ b/meta/test/test.c @@ -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(); +}