blob: 75dbf856e5d033dd120ac1a6dbb8164a42c08db1 [file] [log] [blame]
Radek Krejcid7e8a622018-10-29 15:54:55 +01001/**
Radek Krejci0935f412019-08-20 16:15:18 +02002 * @file plugins_exts.h
Radek Krejcid7e8a622018-10-29 15:54:55 +01003 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vaskofbbea932022-06-07 11:00:55 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejcid7e8a622018-10-29 15:54:55 +01005 * @brief libyang support for YANG extensions implementation.
6 *
Michal Vaskofbbea932022-06-07 11:00:55 +02007 * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
Radek Krejcid7e8a622018-10-29 15:54:55 +01008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Radek Krejci0935f412019-08-20 16:15:18 +020016#ifndef LY_PLUGINS_EXTS_H_
17#define LY_PLUGINS_EXTS_H_
Radek Krejcid7e8a622018-10-29 15:54:55 +010018
Radek Krejci535ea9f2020-05-29 16:01:05 +020019#include "log.h"
Michal Vaskofbbea932022-06-07 11:00:55 +020020#include "parser_data.h"
Radek Krejci3e6632f2021-03-22 22:08:21 +010021#include "plugins.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010022#include "tree_data.h"
Radek Krejci859a15a2021-03-05 20:56:59 +010023#include "tree_edit.h"
Radek Krejci0e59c312019-08-15 15:34:15 +020024#include "tree_schema.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020025
Radek Krejci5f9a3672021-03-05 21:35:22 +010026#include "plugins_exts_compile.h"
Radek Krejcif8d7f9a2021-03-10 14:32:36 +010027#include "plugins_exts_print.h"
Radek Krejci5f9a3672021-03-05 21:35:22 +010028
Radek Krejci535ea9f2020-05-29 16:01:05 +020029struct ly_ctx;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010030struct ly_in;
Radek Krejci535ea9f2020-05-29 16:01:05 +020031struct lyd_node;
Radek Krejci0aa1f702021-04-01 16:16:19 +020032struct lysc_ext_substmt;
33struct lysp_ext_instance;
Radek Krejci0e59c312019-08-15 15:34:15 +020034
Radek Krejcid7e8a622018-10-29 15:54:55 +010035#ifdef __cplusplus
36extern "C" {
37#endif
38
39/**
Radek Krejci75104122021-04-01 15:37:45 +020040 * @page howtoPluginsExtensions Extension Plugins
41 *
42 * Note that the part of the libyang API here is available only by including a separated `<libyang/plugins_exts.h>` header
43 * file. Also note that the extension plugins API is versioned separately from libyang itself, so backward incompatible
44 * changes can come even without changing libyang major version.
45 *
46 * YANG extensions are very complex. Usually only its description specifies how it is supposed to behave, what are the
47 * allowed substatements, their cardinality or if the standard YANG statements placed inside the extension differs somehow
aPiecekb0445f22021-06-24 11:34:07 +020048 * in their meaning or behavior. libyang provides the Extension plugins API to implement such extensions and add its support
Radek Krejci75104122021-04-01 15:37:45 +020049 * into libyang itself. However we tried our best, the API is not (and it cannot be) so universal and complete to cover all
50 * possibilities. There are definitely use cases which cannot be simply implemented only with this API.
51 *
52 * libyang implements 3 important extensions: [NACM](https://tools.ietf.org/html/rfc8341), [Metadata](@ref howtoDataMetadata)
53 * and [yang-data](@ref howtoDataYangdata). Despite the core implementation in all three cases is done via extension plugin
54 * API, also other parts of the libyang code had to be extended to cover complete scope of the extensions.
55 *
56 * We believe, that the API is capable to allow implementation of very wide range of YANG extensions. However, if you see
57 * limitations for the particular YANG extension, don't hesitate to contact the project developers to discuss all the
58 * options, including updating the API.
59 *
60 * The plugin's functionality is provided to libyang via a set of callbacks specified as an array of ::lyplg_ext_record
61 * structures using the ::LYPLG_EXTENSIONS macro.
62 *
63 * The most important ::lyplg_ext.compile callback is responsible for processing the parsed extension instance. In this
64 * phase, the callback must validate all the substatements, their values or placement of the extension instance itself.
65 * If needed, the processed data can be stored in some form into the compiled schema representation of the extension
66 * instance. To make the compilation process as easy as possible, libyang provides several
67 * [helper functions](@ref pluginsExtensionsCompile) to handle the schema compilation context and to compile standard YANG
68 * statements in the same way the libyang does it internally.
69 *
70 * The data validation callback ::lyplg_ext.validate is used for additional validation of a data nodes that contains the
71 * connected extension instance directly (as a substatement) or indirectly in case of terminal nodes via their type (no
72 * matter if the extension instance is placed directly in the leaf's/leaf-list's type or in the type of the referenced
73 * typedef).
74 *
75 * The ::lyplg_ext.sprinter callback implement printing the compiled extension instance data when the schema (module) is
76 * being printed in the ::LYS_OUT_YANG_COMPILED (info) format. As for compile callback, there are also
77 * [helper functions](@ref pluginsExtensionsPrint) to access printer's context and to print standard YANG statements
78 * placed in the extension instance by libyang itself.
79 *
80 * The last callback, ::lyplg_ext.free, is supposed to free all the data allocated by the ::lyplg_ext.compile callback.
81 * To free the data created by helper function ::lys_compile_extension_instance(), the plugin can used
82 * ::lyplg_ext_instance_substatements_free().
83 *
84 * The plugin information contains also the plugin identifier (::lyplg_type.id). This string can serve to identify the
85 * specific plugin responsible to storing data value. In case the user can recognize the id string, it can access the
86 * plugin specific data with the appropriate knowledge of its structure.
87 *
88 * Logging information from an extension plugin is possible via ::lyplg_ext_log() function
89 */
90
91/**
92 * @defgroup pluginsExtensions Plugins: Extensions
93 *
94 * Structures and functions to for libyang plugins implementing specific YANG extensions defined in YANG modules. For more
95 * information, see @ref howtoPluginsTypes.
96 *
97 * This part of libyang API is available by including `<libyang/plugins_ext.h>` header file.
Radek Krejcid7e8a622018-10-29 15:54:55 +010098 *
99 * @{
100 */
101
102/**
Radek Krejci0935f412019-08-20 16:15:18 +0200103 * @brief Extensions API version
104 */
Michal Vaskofbbea932022-06-07 11:00:55 +0200105#define LYPLG_EXT_API_VERSION 4
Radek Krejci0935f412019-08-20 16:15:18 +0200106
107/**
Radek Krejcia6f61e72021-03-24 21:00:19 +0100108 * @brief Macro to define plugin information in external plugins
109 *
110 * Use as follows:
111 * LYPLG_EXTENSIONS = {{<filled information of ::lyplg_ext_record>}, ..., {0}};
Radek Krejci0935f412019-08-20 16:15:18 +0200112 */
Radek Krejcia6f61e72021-03-24 21:00:19 +0100113#define LYPLG_EXTENSIONS \
114 uint32_t plugins_extensions_apiver__ = LYPLG_EXT_API_VERSION; \
115 const struct lyplg_ext_record plugins_extensions__[]
Radek Krejci0935f412019-08-20 16:15:18 +0200116
117/**
Radek Krejci8678fa42020-08-18 16:07:28 +0200118 * @brief Free the extension instance's data compiled with ::lys_compile_extension_instance().
Radek Krejci1b2eef82021-02-17 11:17:27 +0100119 *
Radek Krejci75104122021-04-01 15:37:45 +0200120 * @param[in] ctx libyang context
Radek Krejci1b2eef82021-02-17 11:17:27 +0100121 * @param[in] substmts The sized array of extension instance's substatements. The whole array is freed except the storage
122 * places which are expected to be covered by the extension plugin.
Radek Krejci38d85362019-09-05 16:26:38 +0200123 */
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100124LIBYANG_API_DECL void lyplg_ext_instance_substatements_free(struct ly_ctx *ctx, struct lysc_ext_substmt *substmts);
Radek Krejci38d85362019-09-05 16:26:38 +0200125
126/**
Radek Krejci0e59c312019-08-15 15:34:15 +0200127 * @brief Callback to compile extension from the lysp_ext_instance to the lysc_ext_instance. The later structure is generally prepared
128 * and only the extension specific data are supposed to be added (if any).
129 *
Radek Krejciadcf63d2021-02-09 10:21:18 +0100130 * The parsed generic statements can be processed by the callback on its own or the ::lys_compile_extension_instance
131 * function can be used to let the compilation to libyang following the standard rules for processing the YANG statements.
132 *
Radek Krejci0e59c312019-08-15 15:34:15 +0200133 * @param[in] cctx Current compile context.
134 * @param[in] p_ext Parsed extension instance data.
Michal Vaskoddd76592022-01-17 13:34:48 +0100135 * @param[in,out] c_ext Prepared compiled extension instance structure where an addition, extension-specific, data are
136 * supposed to be placed for later use (data validation or use of external tool).
Radek Krejci0e59c312019-08-15 15:34:15 +0200137 * @return LY_SUCCESS in case of success.
138 * @return LY_EVALID in case of non-conforming parsed data.
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100139 * @return LY_ENOT in case the extension instance is not supported and should be removed.
Radek Krejci0e59c312019-08-15 15:34:15 +0200140 */
Michal Vaskoddd76592022-01-17 13:34:48 +0100141typedef LY_ERR (*lyplg_ext_compile_clb)(struct lysc_ctx *cctx, const struct lysp_ext_instance *p_ext,
142 struct lysc_ext_instance *c_ext);
Radek Krejci0e59c312019-08-15 15:34:15 +0200143
144/**
Michal Vaskoddd76592022-01-17 13:34:48 +0100145 * @brief Callback to print the compiled extension instance's private data in the INFO format.
146 *
147 * @param[in] ctx YANG printer context to provide output handler and other information for printing.
148 * @param[in] ext The compiled extension instance, mainly to access the extensions.
149 * @param[in,out] flag Flag to be shared with the caller regarding the opening brackets - 0 if the '{' not yet printed,
150 * 1 otherwise.
151 * @return LY_SUCCESS when everything was fine, other LY_ERR values in case of failure
152 */
153typedef LY_ERR (*lyplg_ext_schema_printer_clb)(struct lyspr_ctx *ctx, struct lysc_ext_instance *ext, ly_bool *flag);
154
155/**
156 * @brief Callback to free the extension-specific data created by its compilation.
Radek Krejci0e59c312019-08-15 15:34:15 +0200157 *
Radek Krejci38d85362019-09-05 16:26:38 +0200158 * @param[in] ctx libyang context.
Radek Krejci0e59c312019-08-15 15:34:15 +0200159 * @param[in,out] ext Compiled extension structure where the data to free are placed.
160 */
Radek Krejci0b013302021-03-29 15:22:32 +0200161typedef void (*lyplg_ext_free_clb)(struct ly_ctx *ctx, struct lysc_ext_instance *ext);
Radek Krejci0e59c312019-08-15 15:34:15 +0200162
163/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200164 * @brief Callback for getting a schema node for a new YANG instance data described by an extension instance.
165 * Needed only if the extension instance supports some nested standard YANG data.
Radek Krejci0e59c312019-08-15 15:34:15 +0200166 *
Michal Vaskoddd76592022-01-17 13:34:48 +0100167 * @param[in] ext Compiled extension instance.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200168 * @param[in] parent Parsed parent data node. Set if @p sparent is NULL.
169 * @param[in] sparent Schema parent node. Set if @p parent is NULL.
170 * @param[in] prefix Element prefix, if any.
171 * @param[in] prefix_len Length of @p prefix.
172 * @param[in] format Format of @p prefix.
173 * @param[in] prefix_data Format-specific prefix data.
174 * @param[in] name Element name.
175 * @param[in] name_len Length of @p name.
176 * @param[out] snode Schema node to use for parsing the node.
Michal Vaskoddd76592022-01-17 13:34:48 +0100177 * @return LY_SUCCESS on success.
178 * @return LY_ENOT if the data are not described by @p ext.
179 * @return LY_ERR on error.
Radek Krejci0e59c312019-08-15 15:34:15 +0200180 */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200181typedef LY_ERR (*lyplg_ext_data_snode_clb)(struct lysc_ext_instance *ext, const struct lyd_node *parent,
182 const struct lysc_node *sparent, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data,
183 const char *name, size_t name_len, const struct lysc_node **snode);
Radek Krejci0e59c312019-08-15 15:34:15 +0200184
185/**
Michal Vaskoddd76592022-01-17 13:34:48 +0100186 * @brief Callback for validating parsed YANG instance data described by an extension instance.
Radek Krejciadcf63d2021-02-09 10:21:18 +0100187 *
Michal Vaskoddd76592022-01-17 13:34:48 +0100188 * This callback is used only for nested data definition (with a standard YANG schema parent).
Radek Krejciadcf63d2021-02-09 10:21:18 +0100189 *
Michal Vaskoddd76592022-01-17 13:34:48 +0100190 * @param[in] ext Compiled extension instance.
Michal Vasko9af7cd42022-04-05 12:26:09 +0200191 * @param[in] sibling First sibling with schema node returned by ::lyplg_ext_data_snode_clb.
Michal Vaskofbbea932022-06-07 11:00:55 +0200192 * @param[in] dep_tree Tree to be used for validating references from the operation subtree, if operation.
193 * @param[in] data_type Validated data type, can be ::LYD_TYPE_DATA_YANG, ::LYD_TYPE_RPC_YANG, ::LYD_TYPE_NOTIF_YANG,
194 * or ::LYD_TYPE_REPLY_YANG.
Michal Vaskoddd76592022-01-17 13:34:48 +0100195 * @param[in] val_opts Validation options, see @ref datavalidationoptions.
Michal Vaskof4c6f002022-04-01 09:12:22 +0200196 * @param[out] diff Optional diff with any changes made by the validation.
Michal Vaskoddd76592022-01-17 13:34:48 +0100197 * @return LY_SUCCESS on success.
198 * @return LY_ERR on error.
Radek Krejciadcf63d2021-02-09 10:21:18 +0100199 */
Michal Vaskofbbea932022-06-07 11:00:55 +0200200typedef LY_ERR (*lyplg_ext_data_validate_clb)(struct lysc_ext_instance *ext, struct lyd_node *sibling,
201 const struct lyd_node *dep_tree, enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff);
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100202
203/**
Radek Krejci0e59c312019-08-15 15:34:15 +0200204 * @brief Extension plugin implementing various aspects of a YANG extension
205 */
Radek Krejcicc9e30f2021-03-29 12:45:08 +0200206struct lyplg_ext {
Michal Vaskoddd76592022-01-17 13:34:48 +0100207 const char *id; /**< plugin identification (mainly for distinguish incompatible versions
208 of the plugins for external tools) */
209 lyplg_ext_compile_clb compile; /**< callback to compile extension instance from the parsed data */
210 lyplg_ext_schema_printer_clb sprinter; /**< callback to print the compiled content (info format) of the extension
211 instance */
212 lyplg_ext_free_clb free; /**< free the extension-specific data created by its compilation */
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100213
Michal Vasko8cc3f662022-03-29 11:25:51 +0200214 lyplg_ext_data_snode_clb snode; /**< callback to get schema node for nested YANG data */
Michal Vaskoddd76592022-01-17 13:34:48 +0100215 lyplg_ext_data_validate_clb validate; /**< callback to validate parsed data instances according to the extension
216 definition */
Radek Krejci0e59c312019-08-15 15:34:15 +0200217};
218
Radek Krejci3e6632f2021-03-22 22:08:21 +0100219struct lyplg_ext_record {
220 /* plugin identification */
221 const char *module; /**< name of the module where the extension is defined */
222 const char *revision; /**< optional module revision - if not specified, the plugin applies to any revision,
223 which is not an optimal approach due to a possible future revisions of the module.
224 Instead, there should be defined multiple items in the plugins list, each with the
225 different revision, but all with the same pointer to the plugin functions. The
226 only valid use case for the NULL revision is the case the module has no revision. */
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100227 const char *name; /**< YANG name of the extension */
Radek Krejci3e6632f2021-03-22 22:08:21 +0100228
229 /* runtime data */
230 struct lyplg_ext plugin; /**< data to utilize plugin implementation */
231};
232
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100233/**
234 * @brief Get specific run-time extension instance data from a callback set by ::ly_ctx_set_ext_data_clb().
235 *
236 * @param[in] ctx Context with the callback.
237 * @param[in] ext Compiled extension instance.
238 * @param[out] ext_data Provided extension instance data.
239 * @param[out] ext_data_free Whether the extension instance should free @p ext_data or not.
240 * @return LY_SUCCESS on success.
241 * @return LY_ERR on error.
242 */
Michal Vaskoddd76592022-01-17 13:34:48 +0100243LIBYANG_API_DECL LY_ERR lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, void **ext_data,
244 ly_bool *ext_data_free);
245
246/**
247 * @brief Insert extension instance data into a parent.
248 *
249 * @param[in] parent Parent node to insert into.
250 * @param[in] first First top-level sibling node to insert.
251 * @return LY_SUCCESS on success.
252 * @return LY_ERR error on error.
253 */
254LIBYANG_API_DECL LY_ERR lyd_insert_ext(struct lyd_node *parent, struct lyd_node *first);
255
Radek Krejci0935f412019-08-20 16:15:18 +0200256/**
257 * @brief Provide a log message from an extension plugin.
258 *
259 * @param[in] ext Compiled extension structure providing generic information about the extension/plugin causing the message.
260 * @param[in] level Log message level (error, warning, etc.)
261 * @param[in] err_no Error type code.
262 * @param[in] path Path relevant to the message.
263 * @param[in] format Format string to print.
264 */
Jan Kundrátc53a7ec2021-12-09 16:01:19 +0100265LIBYANG_API_DECL void lyplg_ext_log(const struct lysc_ext_instance *ext, LY_LOG_LEVEL level, LY_ERR err_no, const char *path,
Radek Krejci0b013302021-03-29 15:22:32 +0200266 const char *format, ...);
Radek Krejci0935f412019-08-20 16:15:18 +0200267
Radek Krejci75104122021-04-01 15:37:45 +0200268/** @} pluginsExtensions */
Radek Krejcid7e8a622018-10-29 15:54:55 +0100269
270#ifdef __cplusplus
271}
272#endif
273
Radek Krejci0935f412019-08-20 16:15:18 +0200274#endif /* LY_PLUGINS_EXTS_H_ */