1 /**
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 
18 #include "libyang.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**
25  * @addtogroup extensions
26  * @{
27  */
28 
29 /**
30  * @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  */
38 #ifdef STATIC
39 #define LYEXT_VERSION_CHECK
40 #else
41 #define LYEXT_VERSION_CHECK int lyext_api_version = LYEXT_API_VERSION;
42 #endif
43 
44 /**
45  * @brief Extension instance structure parent enumeration
46  */
47 typedef 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
76  * extension instance is actually stored in the lys_module's extensions list with the ::lys_ext_instance#insubstmt set to
77  * #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  */
82 typedef 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 /**
130  * @brief Callback to check that the extension can be instantiated inside the provided node
131  *
132  * @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  */
142 typedef 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
146  * the valid argument, cardinality, etc.
147  *
148  * @param[in] ext Extension instance to be checked.
149  * @return 0 - ok
150  *         1 - error
151  */
152 typedef int (*lyext_check_result_clb)(struct lys_ext_instance *ext);
153 
154 /**
155  * @brief Callback to decide whether the extension will be inherited into the provided schema node. The extension
156  * instance is always from some of the node's parents. The inherited extension instances are marked with the
157  * #LYEXT_OPT_INHERIT flag.
158  *
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  */
165 typedef int (*lyext_check_inherit_clb)(struct lys_ext_instance *ext, struct lys_node *node);
166 
167 /**
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  */
176 typedef int (*lyext_valid_data_clb)(struct lys_ext_instance *ext, struct lyd_node *node);
177 
178 struct lyext_plugin {
179     LYEXT_TYPE type;                          /**< type of the extension, according to it the structure will be casted */
180     uint16_t flags;                           /**< [extension flags](@ref extflags) */
181 
182     lyext_check_position_clb check_position;  /**< callbcak for testing that the extension can be instantiated
183                                                    under the provided parent. Mandatory callback. */
184     lyext_check_result_clb check_result;      /**< callback for testing if the argument value of the extension instance
185                                                    is valid. Mandatory if the extension has the argument. */
186     lyext_check_inherit_clb check_inherit;    /**< callback to decide if the extension is supposed to be inherited into
187                                                    the provided node, the callback is used only if the flags contains
188                                                    #LYEXT_OPT_INHERIT flag */
189     lyext_valid_data_clb valid_data;          /**< callback to valid if data is valid toward to schema */
190 };
191 
192 struct 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
201                                                    the provided node, the callback is used only if the flags contains
202                                                    #LYEXT_OPT_INHERIT flag */
203     lyext_valid_data_clb valid_data;          /**< callback to valid if data is valid toward to schema */
204     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 
212 struct lyext_plugin_list {
213     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. */
219     const char *name;            /**< name of the extension */
220     struct lyext_plugin *plugin; /**< plugin for the extension */
221 };
222 
223 /**
224  * @brief Logging function for extension plugins, use #LYEXT_LOG macro instead!
225  */
226 void lyext_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, const char *plugin, const char *function, const char *format, ...);
227 
228 /**
229  * @brief Logging macro for extension plugins
230  *
231  * @param[in] ctx Context to store the error in.
232  * @param[in] level #LY_LOG_LEVEL value with the message importance.
233  * @param[in] plugin Plugin name.
234  * @param[in] str Format string as in case of printf function.
235  * @param[in] args Parameters to expand in format string.
236  */
237 #define LYEXT_LOG(ctx, level, plugin, str, args...)       \
238     lyext_log(ctx, level, plugin, __func__, str, ##args); \
239 
240 /**
241  * @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  */
244 typedef 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  */
256 void 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 /**
274  * @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  */
283 void 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 /**
287  * @}
288  */
289 
290 #ifdef __cplusplus
291 }
292 #endif
293 
294 #endif /* LY_EXTENSIONS_H_ */
295