blob: 871f382252f0f3a0e21a1545ea566a2950890086 [file] [log] [blame]
Radek Krejcie534c132016-11-23 13:32:31 +01001/**
2 * @file extensions.h
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief libyang support for YANG extension implementations.
5 *
6 * Copyright (c) 2016 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#ifndef LY_EXTENSIONS_H_
16#define LY_EXTENSIONS_H_
17
Radek Krejcic25fe432017-02-22 16:20:09 +010018#include "libyang.h"
Radek Krejcie534c132016-11-23 13:32:31 +010019
20#ifdef __cplusplus
21extern "C" {
22#endif
23
Radek Krejcie534c132016-11-23 13:32:31 +010024/**
Radek Krejci8d6b7422017-02-03 14:42:13 +010025 * @addtogroup extensions
26 * @{
27 */
28
29/**
Radek Krejci3040eb52019-04-03 13:12:58 +020030 * @brief Extensions API version
31 */
32#define LYEXT_API_VERSION 1
33
34/**
35 * @brief Macro to store version of extension plugins API in the plugins.
36 * It is matched when the plugin is being loaded by libyang.
37 */
Robin Jarry21924e92019-04-15 18:33:27 +020038#ifdef STATIC
39#define LYEXT_VERSION_CHECK
40#else
Radek Krejci3040eb52019-04-03 13:12:58 +020041#define LYEXT_VERSION_CHECK int lyext_api_version = LYEXT_API_VERSION;
Robin Jarry21924e92019-04-15 18:33:27 +020042#endif
Radek Krejci3040eb52019-04-03 13:12:58 +020043
44/**
Radek Krejcibe336392017-02-07 10:54:24 +010045 * @brief Extension instance structure parent enumeration
46 */
47typedef enum {
48 LYEXT_PAR_MODULE, /**< ::lys_module or ::lys_submodule */
49 LYEXT_PAR_NODE, /**< ::lys_node (and the derived structures) */
50 LYEXT_PAR_TPDF, /**< ::lys_tpdf */
51 LYEXT_PAR_TYPE, /**< ::lys_type */
52 LYEXT_PAR_TYPE_BIT, /**< ::lys_type_bit */
53 LYEXT_PAR_TYPE_ENUM, /**< ::lys_type_enum */
54 LYEXT_PAR_FEATURE, /**< ::lys_feature */
55 LYEXT_PAR_RESTR, /**< ::lys_restr - YANG's must, range, length and pattern statements */
56 LYEXT_PAR_WHEN, /**< ::lys_when */
57 LYEXT_PAR_IDENT, /**< ::lys_ident */
58 LYEXT_PAR_EXT, /**< ::lys_ext */
59 LYEXT_PAR_EXTINST, /**< ::lys_ext_instance */
60 LYEXT_PAR_REFINE, /**< ::lys_refine */
61 LYEXT_PAR_DEVIATION, /**< ::lys_deviation */
62 LYEXT_PAR_DEVIATE, /**< ::lys_deviate */
63 LYEXT_PAR_IMPORT, /**< ::lys_import */
64 LYEXT_PAR_INCLUDE, /**< ::lys_include */
65 LYEXT_PAR_REVISION, /**< ::lys_revision */
66 LYEXT_PAR_IFFEATURE /**< ::lys_iffeature */
67} LYEXT_PAR;
68
69/**
70 * @brief List of substatement without extensions storage. If the module contains extension instances in these
71 * substatements, they are stored with the extensions of the parent statement and flag to show to which substatement
72 * they belongs to.
73 *
74 * For example, if the extension is supposed to be instantiated as a child to the description statement, libyang
75 * stores the description just as its value. So, for example in case of the module's description, the description's
Radek Krejci89db0592017-02-16 15:07:13 +010076 * extension instance is actually stored in the lys_module's extensions list with the ::lys_ext_instance#insubstmt set to
Radek Krejcibe336392017-02-07 10:54:24 +010077 * #LYEXT_SUBSTMT_DESCRIPTION, ::lys_ext_instance#parent_type is LYEXT_PAR_MODULE and the ::lys_ext_instance#parent
78 * points to the ::lys_module structure.
79 *
80 * The values are (convertible) subset of #LY_STMT
81 */
82typedef enum {
83 LYEXT_SUBSTMT_ALL = -1, /**< special value for the lys_ext_iter() */
84 LYEXT_SUBSTMT_SELF = 0, /**< extension of the structure itself, not substatement's */
85 LYEXT_SUBSTMT_ARGUMENT, /**< extension of the argument statement, can appear in lys_ext */
86 LYEXT_SUBSTMT_BASE, /**< extension of the base statement, can appear (repeatedly) in lys_type and lys_ident */
87 LYEXT_SUBSTMT_BELONGSTO, /**< extension of the belongs-to statement, can appear in lys_submodule */
88 LYEXT_SUBSTMT_CONTACT, /**< extension of the contact statement, can appear in lys_module */
89 LYEXT_SUBSTMT_DEFAULT, /**< extension of the default statement, can appear in lys_node_leaf, lys_node_leaflist,
90 lys_node_choice and lys_deviate */
91 LYEXT_SUBSTMT_DESCRIPTION, /**< extension of the description statement, can appear in lys_module, lys_submodule,
92 lys_node, lys_import, lys_include, lys_ext, lys_feature, lys_tpdf, lys_restr,
93 lys_ident, lys_deviation, lys_type_enum, lys_type_bit, lys_when and lys_revision */
94 LYEXT_SUBSTMT_ERRTAG, /**< extension of the error-app-tag statement, can appear in lys_restr */
95 LYEXT_SUBSTMT_ERRMSG, /**< extension of the error-message statement, can appear in lys_restr */
96 LYEXT_SUBSTMT_KEY, /**< extension of the key statement, can appear in lys_node_list */
97 LYEXT_SUBSTMT_NAMESPACE, /**< extension of the namespace statement, can appear in lys_module */
98 LYEXT_SUBSTMT_ORGANIZATION, /**< extension of the organization statement, can appear in lys_module and lys_submodule */
99 LYEXT_SUBSTMT_PATH, /**< extension of the path statement, can appear in lys_type */
100 LYEXT_SUBSTMT_PREFIX, /**< extension of the prefix statement, can appear in lys_module, lys_submodule (for
101 belongs-to's prefix) and lys_import */
102 LYEXT_SUBSTMT_PRESENCE, /**< extension of the presence statement, can appear in lys_node_container */
103 LYEXT_SUBSTMT_REFERENCE, /**< extension of the reference statement, can appear in lys_module, lys_submodule,
104 lys_node, lys_import, lys_include, lys_revision, lys_tpdf, lys_restr, lys_ident,
105 lys_ext, lys_feature, lys_deviation, lys_type_enum, lys_type_bit and lys_when */
106 LYEXT_SUBSTMT_REVISIONDATE, /**< extension of the revision-date statement, can appear in lys_import and lys_include */
107 LYEXT_SUBSTMT_UNITS, /**< extension of the units statement, can appear in lys_tpdf, lys_node_leaf,
108 lys_node_leaflist and lys_deviate */
109 LYEXT_SUBSTMT_VALUE, /**< extension of the value statement, can appear in lys_type_enum */
110 LYEXT_SUBSTMT_VERSION, /**< extension of the yang-version statement, can appear in lys_module and lys_submodule */
111 LYEXT_SUBSTMT_MODIFIER, /**< extension of the modifier statement, can appear in lys_restr */
112 LYEXT_SUBSTMT_REQINSTANCE, /**< extension of the require-instance statement, can appear in lys_type */
113 LYEXT_SUBSTMT_YINELEM, /**< extension of the yin-element statement, can appear in lys_ext */
114 LYEXT_SUBSTMT_CONFIG, /**< extension of the config statement, can appear in lys_node and lys_deviate */
115 LYEXT_SUBSTMT_MANDATORY, /**< extension of the mandatory statement, can appear in lys_node_leaf, lys_node_choice,
116 lys_node_anydata and lys_deviate */
117 LYEXT_SUBSTMT_ORDEREDBY, /**< extension of the ordered-by statement, can appear in lys_node_list and lys_node_leaflist */
118 LYEXT_SUBSTMT_STATUS, /**< extension of the status statement, can appear in lys_tpdf, lys_node, lys_ident,
119 lys_ext, lys_feature, lys_type_enum and lys_type_bit */
120 LYEXT_SUBSTMT_DIGITS, /**< extension of the fraction-digits statement, can appear in lys_type */
121 LYEXT_SUBSTMT_MAX, /**< extension of the max-elements statement, can appear in lys_node_list,
122 lys_node_leaflist and lys_deviate */
123 LYEXT_SUBSTMT_MIN, /**< extension of the min-elements statement, can appear in lys_node_list,
124 lys_node_leaflist and lys_deviate */
125 LYEXT_SUBSTMT_POSITION, /**< extension of the position statement, can appear in lys_type_bit */
126 LYEXT_SUBSTMT_UNIQUE, /**< extension of the unique statement, can appear in lys_node_list and lys_deviate */
127} LYEXT_SUBSTMT;
128
129/**
Radek Krejcie534c132016-11-23 13:32:31 +0100130 * @brief Callback to check that the extension can be instantiated inside the provided node
131 *
Radek Krejci43ce4b72017-01-04 11:02:38 +0100132 * @param[in] parent The parent of the instantiated extension.
133 * @param[in] parent_type The type of the structure provided as \p parent.
134 * @param[in] substmt_type libyang does not store all the extension instances in the structures where they are
135 * instantiated in the module. In some cases (see #LYEXT_SUBSTMT) they are stored in parent
136 * structure and marked with flag to know in which substatement of the parent the extension
137 * was originally instantiated.
138 * @return 0 - yes
139 * 1 - no
140 * 2 - ignore / skip without an error
141 */
142typedef int (*lyext_check_position_clb)(const void *parent, LYEXT_PAR parent_type, LYEXT_SUBSTMT substmt_type);
143
144/**
145 * @brief Callback to check that the extension instance is correct - have
Radek Krejci2b107412017-02-22 15:26:42 +0100146 * the valid argument, cardinality, etc.
Radek Krejci43ce4b72017-01-04 11:02:38 +0100147 *
Radek Krejci80056d52017-01-05 13:13:33 +0100148 * @param[in] ext Extension instance to be checked.
Radek Krejci90db7552017-01-04 16:17:46 +0100149 * @return 0 - ok
150 * 1 - error
Radek Krejcie534c132016-11-23 13:32:31 +0100151 */
Radek Krejci43ce4b72017-01-04 11:02:38 +0100152typedef int (*lyext_check_result_clb)(struct lys_ext_instance *ext);
Radek Krejcie534c132016-11-23 13:32:31 +0100153
Radek Krejci80056d52017-01-05 13:13:33 +0100154/**
155 * @brief Callback to decide whether the extension will be inherited into the provided schema node. The extension
Radek Krejci89db0592017-02-16 15:07:13 +0100156 * instance is always from some of the node's parents. The inherited extension instances are marked with the
157 * #LYEXT_OPT_INHERIT flag.
Radek Krejci80056d52017-01-05 13:13:33 +0100158 *
159 * @param[in] ext Extension instance to be inherited.
160 * @param[in] node Schema node where the node is supposed to be inherited.
161 * @return 0 - yes
162 * 1 - no (do not process the node's children)
163 * 2 - no, but continue with children
164 */
165typedef int (*lyext_check_inherit_clb)(struct lys_ext_instance *ext, struct lys_node *node);
166
PavolVicane9392862018-02-19 17:34:40 +0100167/**
168 * @brief Callback to decide if data is valid towards to schema.
169 *
170 * @param[in] ext Extension instance to be checked.
171 * @param[in] node Data node, which try to valid.
172 *
173 * @return 0 - valid
174 * 1 - invalid
175 */
176typedef int (*lyext_valid_data_clb)(struct lys_ext_instance *ext, struct lyd_node *node);
177
Radek Krejci43ce4b72017-01-04 11:02:38 +0100178struct lyext_plugin {
179 LYEXT_TYPE type; /**< type of the extension, according to it the structure will be casted */
Radek Krejci80056d52017-01-05 13:13:33 +0100180 uint16_t flags; /**< [extension flags](@ref extflags) */
Radek Krejcie534c132016-11-23 13:32:31 +0100181
Radek Krejci80056d52017-01-05 13:13:33 +0100182 lyext_check_position_clb check_position; /**< callbcak for testing that the extension can be instantiated
Radek Krejci43ce4b72017-01-04 11:02:38 +0100183 under the provided parent. Mandatory callback. */
Radek Krejci80056d52017-01-05 13:13:33 +0100184 lyext_check_result_clb check_result; /**< callback for testing if the argument value of the extension instance
Radek Krejci43ce4b72017-01-04 11:02:38 +0100185 is valid. Mandatory if the extension has the argument. */
Radek Krejci80056d52017-01-05 13:13:33 +0100186 lyext_check_inherit_clb check_inherit; /**< callback to decide if the extension is supposed to be inherited into
Radek Krejci89db0592017-02-16 15:07:13 +0100187 the provided node, the callback is used only if the flags contains
188 #LYEXT_OPT_INHERIT flag */
PavolVicane9392862018-02-19 17:34:40 +0100189 lyext_valid_data_clb valid_data; /**< callback to valid if data is valid toward to schema */
Radek Krejcie534c132016-11-23 13:32:31 +0100190};
191
Radek Krejci8d6b7422017-02-03 14:42:13 +0100192struct lyext_plugin_complex {
193 LYEXT_TYPE type; /**< type of the extension, according to it the structure will be casted */
194 uint16_t flags; /**< [extension flags](@ref extflags) */
195
196 lyext_check_position_clb check_position; /**< callbcak for testing that the extension can be instantiated
197 under the provided parent. Mandatory callback. */
198 lyext_check_result_clb check_result; /**< callback for testing if the argument value of the extension instance
199 is valid. Mandatory if the extension has the argument. */
200 lyext_check_inherit_clb check_inherit; /**< callback to decide if the extension is supposed to be inherited into
Radek Krejci89db0592017-02-16 15:07:13 +0100201 the provided node, the callback is used only if the flags contains
202 #LYEXT_OPT_INHERIT flag */
PavolVicane9392862018-02-19 17:34:40 +0100203 lyext_valid_data_clb valid_data; /**< callback to valid if data is valid toward to schema */
Radek Krejci8d6b7422017-02-03 14:42:13 +0100204 struct lyext_substmt *substmt; /**< NULL-terminated array of allowed substatements and restrictions
205 to their instantiation inside the extension instance */
206 size_t instance_size; /**< size of the instance structure to allocate, the structure is
207 is provided as ::lys_ext_instance_complex, but the content array
208 is accessed according to the substmt specification provided by
209 plugin */
210};
211
Radek Krejci43ce4b72017-01-04 11:02:38 +0100212struct lyext_plugin_list {
Radek Krejci3b88c6c2017-01-04 16:12:12 +0100213 const char *module; /**< name of the module where the extension is defined */
214 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
215 which is not an optional approach due to a possible future revisions of the module.
216 Instead, there should be defined multiple items in the plugins list, each with the
217 different revision, but all with the same pointer to the plugin extension. The
218 only valid use case for the NULL revision is the case the module has no revision. */
Radek Krejci43ce4b72017-01-04 11:02:38 +0100219 const char *name; /**< name of the extension */
220 struct lyext_plugin *plugin; /**< plugin for the extension */
Radek Krejcie534c132016-11-23 13:32:31 +0100221};
222
Radek Krejci8d6b7422017-02-03 14:42:13 +0100223/**
Radek Krejcic25fe432017-02-22 16:20:09 +0100224 * @brief Logging function for extension plugins, use #LYEXT_LOG macro instead!
225 */
Michal Vasko53b7da02018-02-13 15:28:42 +0100226void lyext_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, const char *plugin, const char *function, const char *format, ...);
Radek Krejcic25fe432017-02-22 16:20:09 +0100227
228/**
229 * @brief Logging macro for extension plugins
230 *
Michal Vasko53b7da02018-02-13 15:28:42 +0100231 * @param[in] ctx Context to store the error in.
Radek Krejcic25fe432017-02-22 16:20:09 +0100232 * @param[in] level #LY_LOG_LEVEL value with the message importance.
Radek Krejci24f86902017-02-23 13:07:48 +0100233 * @param[in] plugin Plugin name.
Radek Krejcic25fe432017-02-22 16:20:09 +0100234 * @param[in] str Format string as in case of printf function.
235 * @param[in] args Parameters to expand in format string.
236 */
Michal Vasko53b7da02018-02-13 15:28:42 +0100237#define LYEXT_LOG(ctx, level, plugin, str, args...) \
238 lyext_log(ctx, level, plugin, __func__, str, ##args); \
Radek Krejcic25fe432017-02-22 16:20:09 +0100239
240/**
Robin Jarry46159ad2019-04-08 10:18:10 +0200241 * @brief Type of object concerned by a validation error.
242 * This is used to determine how to compute the path of the element at issue.
243 */
244typedef enum {
245 LYEXT_VLOG_NONE = 0,
246 LYEXT_VLOG_XML, /**< const struct ::lyxml_elem* */
247 LYEXT_VLOG_LYS, /**< const struct ::lys_node* */
248 LYEXT_VLOG_LYD, /**< const struct ::lyd_node* */
249 LYEXT_VLOG_STR, /**< const char* */
250 LYEXT_VLOG_PREV, /**< Use the same path as the previous validation error */
251} LYEXT_VLOG_ELEM;
252
253/**
254 * @brief Validation logging function for extension plugins, use #LYEXT_VLOG macro instead!
255 */
256void lyext_vlog(const struct ly_ctx *ctx, LY_VECODE vecode, const char *plugin, const char *function,
257 LYEXT_VLOG_ELEM elem_type, const void *elem, const char *format, ...);
258
259/**
260 * @brief Validation logging macro for extension plugins
261 *
262 * @param[in] ctx Context to store the error in.
263 * @param[in] vecode #LY_VECODE validation error code.
264 * @param[in] plugin Plugin name.
265 * @param[in] elem_type #LYEXT_VLOG_ELEM what to expect in \p elem.
266 * @param[in] elem The element at issue.
267 * @param[in] str Format string as in case of printf function.
268 * @param[in] args Parameters to expand in format string.
269 */
270#define LYEXT_VLOG(ctx, vecode, plugin, elem_type, elem, str, args...) \
271 lyext_vlog(ctx, vecode, plugin, __func__, elem_type, elem, str, ##args)
272
273/**
Michal Vaskoe41dfe62018-11-08 13:28:07 +0100274 * @brief Free iffeature structure. In API only for plugins that want to handle if-feature statements similarly
275 * to libyang.
276 *
277 * @param[in] ctx libyang context.
278 * @param[in] iffeature iffeature array to free.
279 * @param[in] iffeature_size size of array \p iffeature.
280 * @param[in] shallow Whether to make only shallow free.
281 * @param[in] private_destructor Custom destructor for freeing any extension instances.
282 */
283void lys_iffeature_free(struct ly_ctx *ctx, struct lys_iffeature *iffeature, uint8_t iffeature_size, int shallow,
284 void (*private_destructor)(const struct lys_node *node, void *priv));
285
286/**
Radek Krejci8d6b7422017-02-03 14:42:13 +0100287 * @}
288 */
Radek Krejci43ce4b72017-01-04 11:02:38 +0100289
Radek Krejcie534c132016-11-23 13:32:31 +0100290#ifdef __cplusplus
291}
292#endif
293
294#endif /* LY_EXTENSIONS_H_ */