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