From 5369cd45d1fd2c2f747a40b51aad54bc324f55b5 Mon Sep 17 00:00:00 2001 From: Stefan Gula Date: Fri, 29 Mar 2024 17:15:02 +0100 Subject: [PATCH 1/2] Adding context based extensions plugins support This patch adds ability to load plugins directly from memory without need to create shared library by using lyplg_add_plugin() API. It also allows to associate plugin directly with context, so given plugin will not affect all contexts, just given context --- src/context.c | 6 +- src/ly_common.h | 2 + src/plugins.c | 147 +++++++++++++++++++++--------- src/plugins.h | 18 ++++ src/plugins_internal.h | 6 +- src/schema_compile_node.c | 6 +- src/tree_schema.c | 2 +- tests/utests/basic/test_plugins.c | 48 +++++++++- tests/utests/types/binary.c | 8 +- tests/utests/types/bits.c | 10 +- tests/utests/types/enumeration.c | 2 +- tests/utests/types/inet_types.c | 8 +- tests/utests/types/int8.c | 8 +- tests/utests/types/leafref.c | 2 +- tests/utests/types/string.c | 8 +- tests/utests/types/union.c | 2 +- tests/utests/types/yang_types.c | 2 +- tests/utests/utests.h | 2 +- 18 files changed, 208 insertions(+), 79 deletions(-) diff --git a/src/context.c b/src/context.c index e023f31d4..307dde762 100644 --- a/src/context.c +++ b/src/context.c @@ -1384,7 +1384,11 @@ ly_ctx_destroy(struct ly_ctx *ctx) /* LYB hash lock */ pthread_mutex_destroy(&ctx->lyb_hash_lock); - /* plugins - will be removed only if this is the last context */ + /* context specific plugins */ + ly_set_erase(&ctx->plugins_types, NULL); + ly_set_erase(&ctx->plugins_extensions, NULL); + + /* shared plugins - will be removed only if this is the last context */ lyplg_clean(); free(ctx); diff --git a/src/ly_common.h b/src/ly_common.h index 00ac5060a..ec0d3eab6 100644 --- a/src/ly_common.h +++ b/src/ly_common.h @@ -356,6 +356,8 @@ struct ly_ctx { struct ly_ht *err_ht; /**< hash table of thread-specific list of errors related to the context */ pthread_mutex_t lyb_hash_lock; /**< lock for storing LYB schema hashes in schema nodes */ struct ly_ht *leafref_links_ht; /**< hash table of leafref links between term data nodes */ + struct ly_set plugins_types; /**< context specific set of type plugins */ + struct ly_set plugins_extensions; /**< contets specific set of extension plugins */ }; /** diff --git a/src/plugins.c b/src/plugins.c index ab264f0a3..74314ddb3 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -130,21 +130,22 @@ static struct ly_set plugins_extensions = {0}; /** * @brief Iterate over list of loaded plugins of the given @p type. * + * @param[in] ctx The context for which the plugin is searched for * @param[in] type Type of the plugins to iterate. * @param[in,out] index The iterator - set to 0 for the first call. * @return The plugin records, NULL if no more record is available. */ static struct lyplg_record * -plugins_iter(enum LYPLG type, uint32_t *index) +plugins_iter(const struct ly_ctx *ctx, enum LYPLG type, uint32_t *index) { - struct ly_set *plugins; + const struct ly_set *plugins; assert(index); if (type == LYPLG_EXTENSION) { - plugins = &plugins_extensions; + plugins = ctx ? &ctx->plugins_extensions : &plugins_extensions; } else { - plugins = &plugins_types; + plugins = ctx ? &ctx->plugins_types : &plugins_types; } if (*index == plugins->count) { @@ -156,7 +157,7 @@ plugins_iter(enum LYPLG type, uint32_t *index) } static void * -lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name) +lyplg_record_find(const struct ly_ctx *ctx, enum LYPLG type, const char *module, const char *revision, const char *name) { uint32_t i = 0; struct lyplg_record *item; @@ -164,7 +165,7 @@ lyplg_record_find(enum LYPLG type, const char *module, const char *revision, con assert(module); assert(name); - while ((item = plugins_iter(type, &i)) != NULL) { + while ((item = plugins_iter(ctx, type, &i)) != NULL) { if (!strcmp(item->module, module) && !strcmp(item->name, name)) { if (item->revision && revision && strcmp(item->revision, revision)) { continue; @@ -180,23 +181,47 @@ lyplg_record_find(enum LYPLG type, const char *module, const char *revision, con } struct lyplg_type * -lyplg_type_plugin_find(const char *module, const char *revision, const char *name) +lyplg_type_plugin_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name) { - struct lyplg_record *record; + struct lyplg_record *record = NULL; + + if (ctx) { + /* try to find context specific plugin */ + record = lyplg_record_find(ctx, LYPLG_TYPE, module, revision, name); + } + + if (!record) { + /* try to find shared plugin */ + record = lyplg_record_find(NULL, LYPLG_TYPE, module, revision, name); + } - record = lyplg_record_find(LYPLG_TYPE, module, revision, name); return record ? &((struct lyplg_type_record *)record)->plugin : NULL; } struct lyplg_ext_record * -lyplg_ext_record_find(const char *module, const char *revision, const char *name) +lyplg_ext_record_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name) { - return lyplg_record_find(LYPLG_EXTENSION, module, revision, name); + struct lyplg_ext_record *record = NULL; + + if (ctx) { + /* try to find context specific plugin */ + record = lyplg_record_find(ctx, LYPLG_EXTENSION, module, revision, name); + } + + if (!record) { + /* try to find shared plugin */ + record = lyplg_record_find(NULL, LYPLG_EXTENSION, module, revision, name); + } + + return record; } /** * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang. * + * @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared + * between all existing contexts. + * @param[in] type The type of plugins records * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed * record. * @return LY_SUCCESS in case of success @@ -204,8 +229,10 @@ lyplg_ext_record_find(const char *module, const char *revision, const char *name * @return LY_EMEM in case of memory allocation failure. */ static LY_ERR -plugins_insert(enum LYPLG type, const void *recs) +plugins_insert(struct ly_ctx *ctx, enum LYPLG type, const void *recs) { + struct ly_set *plugins; + if (!recs) { return LY_SUCCESS; } @@ -213,14 +240,18 @@ plugins_insert(enum LYPLG type, const void *recs) if (type == LYPLG_EXTENSION) { const struct lyplg_ext_record *rec = (const struct lyplg_ext_record *)recs; + plugins = ctx ? &ctx->plugins_extensions : &plugins_extensions; + for (uint32_t i = 0; rec[i].name; i++) { - LY_CHECK_RET(ly_set_add(&plugins_extensions, (void *)&rec[i], 0, NULL)); + LY_CHECK_RET(ly_set_add(plugins, (void *)&rec[i], 0, NULL)); } } else { /* LYPLG_TYPE */ const struct lyplg_type_record *rec = (const struct lyplg_type_record *)recs; + plugins = ctx ? &ctx->plugins_types : &plugins_types; + for (uint32_t i = 0; rec[i].name; i++) { - LY_CHECK_RET(ly_set_add(&plugins_types, (void *)&rec[i], 0, NULL)); + LY_CHECK_RET(ly_set_add(plugins, (void *)&rec[i], 0, NULL)); } } @@ -329,7 +360,7 @@ plugins_load(void *dlhandler, const char *pathname, enum LYPLG type) } /* ... and load all the types plugins */ - LY_CHECK_RET(plugins_insert(type, plugins)); + LY_CHECK_RET(plugins_insert(NULL, type, plugins)); } return LY_SUCCESS; @@ -457,48 +488,48 @@ lyplg_init(ly_bool builtin_type_plugins_only) } /* internal types */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_binary), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_bits), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_boolean), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_decimal64), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_empty), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_enumeration), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_identityref), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_integer), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_leafref), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_string), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_union), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_binary), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_bits), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_boolean), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_decimal64), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_empty), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_enumeration), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_identityref), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_instanceid), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_integer), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_leafref), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_string), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_union), error); if (!builtin_type_plugins_only) { /* yang */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_instanceid_keys), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_instanceid_keys), error); /* ietf-inet-types */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_address_no_zone), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_address_no_zone), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv4_prefix), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_ipv6_prefix), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_address), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_address_no_zone), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_address), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_address_no_zone), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv4_prefix), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_ipv6_prefix), error); /* ietf-yang-types */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_date_and_time), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_hex_string), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_xpath10), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_date_and_time), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_hex_string), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_xpath10), error); /* ietf-netconf-acm */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_node_instanceid), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_node_instanceid), error); /* lyds_tree */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_TYPE, plugins_lyds_tree), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_TYPE, plugins_lyds_tree), error); /* internal extensions */ - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_metadata), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_nacm), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_yangdata), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_schema_mount), error); - LY_CHECK_GOTO(ret = plugins_insert(LYPLG_EXTENSION, plugins_structure), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_metadata), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_nacm), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_yangdata), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_schema_mount), error); + LY_CHECK_GOTO(ret = plugins_insert(NULL, LYPLG_EXTENSION, plugins_structure), error); } #ifndef STATIC @@ -562,3 +593,31 @@ lyplg_add(const char *pathname) return ret; #endif } + +LIBYANG_API_DEF LY_ERR +lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const void *recs) +{ + LY_ERR ret = LY_SUCCESS; + + LY_CHECK_ARG_RET(NULL, recs, LY_EINVAL); + + if (version != plugins_load_info[type].apiver) { + LOGERR(ctx, LY_EINVAL, "Adding user %s plugin failed, wrong API version - %d expected, %d found.", + plugins_load_info[type].id, plugins_load_info[type].apiver, version); + return LY_EINVAL; + } + + /* works only in case a context exists */ + pthread_mutex_lock(&plugins_guard); + if (!context_refcount) { + /* no context */ + pthread_mutex_unlock(&plugins_guard); + LOGERR(NULL, LY_EDENIED, "To add a plugin, at least one context must exists."); + return LY_EDENIED; + } + + plugins_insert(ctx, type, recs); + pthread_mutex_unlock(&plugins_guard); + + return ret; +} diff --git a/src/plugins.h b/src/plugins.h index f8688797a..9e919cc34 100644 --- a/src/plugins.h +++ b/src/plugins.h @@ -85,6 +85,24 @@ enum LYPLG { */ LIBYANG_API_DECL LY_ERR lyplg_add(const char *pathname); +/** + * @brief Manually load a plugins from memory + * + * Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the + * existence of a context. When all the contexts are destroyed, all the plugins are unloaded. + * + * @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared + * between all existing contexts. + * @param[in] version The version of plugin records. + * @param[in] type The type of plugins records. + * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed + * record. + * + * @return LY_SUCCESS if the plugins with compatible version were successfully loaded. + * @return LY_EDENIED in case there is no context and the plugin cannot be loaded. + * @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version. + */ +LIBYANG_API_DECL LY_ERR lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const void *recs); /** @} plugins */ #ifdef __cplusplus diff --git a/src/plugins_internal.h b/src/plugins_internal.h index 59adacfd7..2ba54f136 100644 --- a/src/plugins_internal.h +++ b/src/plugins_internal.h @@ -63,6 +63,7 @@ void lyplg_clean(void); /** * @brief Find a type plugin. * + * @param[in] ctx The optional context for which the plugin should be find. If NULL, only shared plugins will be searched * @param[in] module Name of the module where the type is defined. Must not be NULL, in case of plugins for * built-in types, the module is "". * @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches @@ -70,17 +71,18 @@ void lyplg_clean(void); * @param[in] name Name of the type which the plugin implements. * @return Found type plugin, NULL if none found. */ -struct lyplg_type *lyplg_type_plugin_find(const char *module, const char *revision, const char *name); +struct lyplg_type *lyplg_type_plugin_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name); /** * @brief Find an extension plugin. * + * @param[in] ctx The optional context for which the plugin should be find. If NULL, only shared plugins will be searched * @param[in] module Name of the module where the extension is defined. * @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches * only the plugins with NULL revision specified. * @param[in] name Name of the extension which the plugin implements. * @return Found extension record, NULL if none found. */ -struct lyplg_ext_record *lyplg_ext_record_find(const char *module, const char *revision, const char *name); +struct lyplg_ext_record *lyplg_ext_record_find(const struct ly_ctx *ctx, const char *module, const char *revision, const char *name); #endif /* LY_PLUGINS_INTERNAL_H_ */ diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c index c7724ec02..3aa97f258 100644 --- a/src/schema_compile_node.c +++ b/src/schema_compile_node.c @@ -2263,7 +2263,7 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t } /* try to find loaded user type plugins */ - plugin = lyplg_type_plugin_find(tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision, + plugin = lyplg_type_plugin_find(ctx->ctx, tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision, tctx->tpdf->name); if (!plugin && base) { /* use the base type implementation if available */ @@ -2271,7 +2271,7 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t } if (!plugin) { /* use the internal built-in type implementation */ - plugin = lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]); + plugin = lyplg_type_plugin_find(ctx->ctx, "", NULL, ly_data_type2str[basetype]); } assert(plugin); @@ -2312,7 +2312,7 @@ lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t /* process the type definition in leaf */ if (type_p->flags || type_p->exts || !base || (basetype == LY_TYPE_LEAFREF)) { /* leaf type has changes that need to be compiled into the type */ - plugin = base ? base->plugin : lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]); + plugin = base ? base->plugin : lyplg_type_plugin_find(ctx->ctx, "", NULL, ly_data_type2str[basetype]); ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, (struct lysp_type *)type_p, basetype, NULL, base, plugin, &tpdf_chain, 0, type); LY_CHECK_GOTO(ret, cleanup); diff --git a/src/tree_schema.c b/src/tree_schema.c index e8b985757..9d9d2b488 100644 --- a/src/tree_schema.c +++ b/src/tree_schema.c @@ -1362,7 +1362,7 @@ lysp_resolve_ext_instance_records(struct lysp_ctx *pctx) LY_CHECK_RET(lysp_ext_instance_resolve_argument(PARSER_CTX(pctx), ext)); /* find the extension record, if any */ - ext->record = lyplg_ext_record_find(mod->name, mod->revision, ext->def->name); + ext->record = lyplg_ext_record_find(mod->ctx, mod->name, mod->revision, ext->def->name); } } diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c index cf2e87b6d..fa0111361 100644 --- a/tests/utests/basic/test_plugins.c +++ b/tests/utests/basic/test_plugins.c @@ -54,12 +54,12 @@ test_add_simple(void **state) leaf = (struct lysc_node_leaf *)mod->compiled->data; assert_int_equal(LYS_LEAF, leaf->nodetype); - assert_non_null(plugin_t = lyplg_type_plugin_find("libyang-plugins-simple", NULL, "note")); + assert_non_null(plugin_t = lyplg_type_plugin_find(NULL, "libyang-plugins-simple", NULL, "note")); assert_string_equal("ly2 simple test v1", plugin_t->id); assert_ptr_equal(leaf->type->plugin, plugin_t); assert_int_equal(1, LY_ARRAY_COUNT(leaf->exts)); - assert_non_null(record_e = lyplg_ext_record_find("libyang-plugins-simple", NULL, "hint")); + assert_non_null(record_e = lyplg_ext_record_find(NULL, "libyang-plugins-simple", NULL, "hint")); assert_string_equal("ly2 simple test v1", record_e->plugin.id); assert_ptr_equal(leaf->exts[0].def->plugin, &record_e->plugin); @@ -96,6 +96,49 @@ test_not_implemented(void **state) lyd_free_all(tree); } +static LY_ERR +parse_clb(struct lysp_ctx *UNUSED(pctx), struct lysp_ext_instance *ext) +{ + struct lysp_node_leaf *leaf; + + leaf = (struct lysp_node_leaf *)ext->parent; + leaf->flags |= LYS_STATUS_OBSLT; + return LY_SUCCESS; +} + +struct lyplg_ext_record memory_recs[] = { + { + .module = "libyang-plugins-simple", + .revision = NULL, + .name = "hint", + + .plugin.id = "memory-plugin-v1", + .plugin.parse = parse_clb, + .plugin.compile = NULL, + .plugin.printer_info = NULL, + .plugin.node = NULL, + .plugin.snode = NULL, + .plugin.validate = NULL, + .plugin.pfree = NULL, + .plugin.cfree = NULL + }, + {0} /* terminating zeroed item */ +}; + +static void +test_simple_from_memory(void **state) +{ + struct lys_module *mod; + struct lysc_node_leaf *leaf; + + lyplg_add_plugin(UTEST_LYCTX, LYPLG_EXT_API_VERSION, LYPLG_EXTENSION, memory_recs); + UTEST_ADD_MODULE(simple, LYS_IN_YANG, NULL, &mod); + + leaf = (struct lysc_node_leaf *)mod->compiled->data; + assert_int_equal(LYS_LEAF, leaf->nodetype); + assert_true(leaf->flags & LYS_STATUS_OBSLT); +} + int main(void) { @@ -103,6 +146,7 @@ main(void) UTEST(test_add_invalid), UTEST(test_add_simple), UTEST(test_not_implemented), + UTEST(test_simple_from_memory), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/tests/utests/types/binary.c b/tests/utests/types/binary.c index 910f756eb..4d0cfbcc5 100644 --- a/tests/utests/types/binary.c +++ b/tests/utests/types/binary.c @@ -51,7 +51,7 @@ test_plugin_store(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value value = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BINARY]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]); struct lysc_type *lysc_type, *lysc_type2; LY_ERR ly_ret; const char *schema; @@ -250,7 +250,7 @@ test_plugin_print(void **state) struct lyd_value value = {0}; struct lys_module *mod; struct lysc_type *lysc_type; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BINARY]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]); struct ly_err_item *err = NULL; /* create schema. Prepare common used variables */ @@ -273,7 +273,7 @@ test_plugin_duplicate(void **state) struct lyd_value value = {0}, dup; struct lys_module *mod; struct lysc_type *lysc_type; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BINARY]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]); struct ly_err_item *err = NULL; /* create schema. Prepare common used variables */ @@ -298,7 +298,7 @@ test_plugin_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BINARY]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BINARY]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; diff --git a/tests/utests/types/bits.c b/tests/utests/types/bits.c index ddf8143ad..35553773d 100644 --- a/tests/utests/types/bits.c +++ b/tests/utests/types/bits.c @@ -800,7 +800,7 @@ test_plugin_store(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value value = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BITS]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]); struct lysc_type *lysc_type; struct lysc_type lysc_type_test; LY_ERR ly_ret; @@ -894,7 +894,7 @@ test_plugin_compare(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BITS]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]); struct lysc_type *lysc_type; LY_ERR ly_ret; const char *schema; @@ -956,7 +956,7 @@ test_plugin_sort(void **state) { const char *schema; struct lys_module *mod; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BITS]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; struct lyd_value val1 = {0}, val2 = {0}; @@ -993,7 +993,7 @@ test_plugin_print(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BITS]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]); struct lysc_type *lysc_type; LY_ERR ly_ret; const char *schema; @@ -1035,7 +1035,7 @@ test_plugin_dup(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_BITS]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_BITS]); struct lysc_type *lysc_type; const char *schema; LY_ERR ly_ret; diff --git a/tests/utests/types/enumeration.c b/tests/utests/types/enumeration.c index 04bbae252..0d42c54f6 100644 --- a/tests/utests/types/enumeration.c +++ b/tests/utests/types/enumeration.c @@ -94,7 +94,7 @@ test_plugin_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_ENUM]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_ENUM]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; diff --git a/tests/utests/types/inet_types.c b/tests/utests/types/inet_types.c index 016d5bbf1..402cadea1 100644 --- a/tests/utests/types/inet_types.c +++ b/tests/utests/types/inet_types.c @@ -196,7 +196,7 @@ test_plugin_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_UNION]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; @@ -238,7 +238,7 @@ test_plugin_sort(void **state) /* ipv6-address */ lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next)->type; - type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); v1 = "2008:15:0:0:0:0:feAC:1"; assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1), @@ -266,7 +266,7 @@ test_plugin_sort(void **state) /* ipv4-address-no-zone */ lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next)->type; - type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_UNION]); + type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]); v1 = "127.0.0.1"; assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1), 0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err)); @@ -281,7 +281,7 @@ test_plugin_sort(void **state) /* ipv6-address-no-zone */ lysc_type = ((struct lysc_node_leaflist *)mod->compiled->data->next->next->next)->type; - type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); v1 = "A:B:c:D:e:f:1:1"; assert_int_equal(LY_SUCCESS, type->store(UTEST_LYCTX, lysc_type, v1, strlen(v1), 0, LY_VALUE_JSON, NULL, LYD_VALHINT_STRING, NULL, &val1, NULL, &err)); diff --git a/tests/utests/types/int8.c b/tests/utests/types/int8.c index d92d14666..dff29efbe 100644 --- a/tests/utests/types/int8.c +++ b/tests/utests/types/int8.c @@ -1399,7 +1399,7 @@ test_plugin_store(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value value = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_INT8]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]); struct lysc_type *lysc_type; LY_ERR ly_ret; char *alloc; @@ -1546,7 +1546,7 @@ test_plugin_compare(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_INT8]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]); struct lysc_type *lysc_type; LY_ERR ly_ret; const char *schema; @@ -1631,7 +1631,7 @@ test_plugin_print(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_INT8]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]); struct lysc_type *lysc_type; LY_ERR ly_ret; const char *schema; @@ -1671,7 +1671,7 @@ test_plugin_dup(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_INT8]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_INT8]); struct lysc_type *lysc_type[2]; const char *schema; LY_ERR ly_ret; diff --git a/tests/utests/types/leafref.c b/tests/utests/types/leafref.c index 1941e482c..81e8ded83 100644 --- a/tests/utests/types/leafref.c +++ b/tests/utests/types/leafref.c @@ -216,7 +216,7 @@ test_plugin_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_LEAFREF]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_LEAFREF]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; diff --git a/tests/utests/types/string.c b/tests/utests/types/string.c index f5aec3467..2f002b73a 100644 --- a/tests/utests/types/string.c +++ b/tests/utests/types/string.c @@ -1060,7 +1060,7 @@ test_plugin_store(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value value = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); struct lysc_type *lysc_type; char *alloc_text; unsigned int alloc_text_size; @@ -1201,7 +1201,7 @@ test_plugin_compare(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); struct lysc_type *lysc_type; LY_ERR ly_ret; const char *schema; @@ -1259,7 +1259,7 @@ test_plugin_print(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); struct lysc_type *lysc_type; LY_ERR ly_ret; @@ -1298,7 +1298,7 @@ test_plugin_dup(void **state) struct ly_err_item *err = NULL; struct lys_module *mod; struct lyd_value values[10]; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_STRING]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_STRING]); struct lysc_type *lysc_type[2]; const char *schema; LY_ERR ly_ret; diff --git a/tests/utests/types/union.c b/tests/utests/types/union.c index 2c378df19..0d6ad2145 100644 --- a/tests/utests/types/union.c +++ b/tests/utests/types/union.c @@ -154,7 +154,7 @@ test_plugin_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("", NULL, ly_data_type2str[LY_TYPE_UNION]); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[LY_TYPE_UNION]); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c index 51a7c7f3d..42e1f3289 100644 --- a/tests/utests/types/yang_types.c +++ b/tests/utests/types/yang_types.c @@ -235,7 +235,7 @@ test_sort(void **state) const char *schema; struct lys_module *mod; struct lyd_value val1 = {0}, val2 = {0}; - struct lyplg_type *type = lyplg_type_plugin_find("ietf-yang-types", "2013-07-15", "date-and-time"); + struct lyplg_type *type = lyplg_type_plugin_find(NULL, "ietf-yang-types", "2013-07-15", "date-and-time"); struct lysc_type *lysc_type; struct ly_err_item *err = NULL; diff --git a/tests/utests/utests.h b/tests/utests/utests.h index 6824db4e6..7b8107f15 100644 --- a/tests/utests/utests.h +++ b/tests/utests/utests.h @@ -231,7 +231,7 @@ struct utest_context { assert_non_null(NODE); \ assert_int_equal((NODE)->basetype, TYPE); \ CHECK_ARRAY((NODE)->exts, EXTS); \ - assert_ptr_equal((NODE)->plugin, lyplg_type_plugin_find("", NULL, ly_data_type2str[TYPE])) + assert_ptr_equal((NODE)->plugin, lyplg_type_plugin_find(NULL, "", NULL, ly_data_type2str[TYPE])) /** * @brief check compileted numeric type From 306252c2b499916999877f1047f58cccff347a91 Mon Sep 17 00:00:00 2001 From: Stefan Gula Date: Tue, 2 Apr 2024 12:12:24 +0200 Subject: [PATCH 2/2] Refactored based on PR comments --- src/plugins.c | 31 ++++++++++++++++++++++++++++++- src/plugins.h | 26 +++++++++++++++++++++++--- tests/utests/basic/test_plugins.c | 2 +- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index 74314ddb3..87273fa66 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -594,7 +594,24 @@ lyplg_add(const char *pathname) #endif } -LIBYANG_API_DEF LY_ERR +/** + * @brief Manually load an extension plugins from memory + * + * Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the + * existence of a context. When all the contexts are destroyed, all the plugins are unloaded. + * + * @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared + * between all existing contexts. + * @param[in] version The version of plugin records. + * @param[in] type The type of plugins records. + * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed + * record. + * + * @return LY_SUCCESS if the plugins with compatible version were successfully loaded. + * @return LY_EDENIED in case there is no context and the plugin cannot be loaded. + * @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version. + */ +static LY_ERR lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const void *recs) { LY_ERR ret = LY_SUCCESS; @@ -621,3 +638,15 @@ lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const vo return ret; } + +LIBYANG_API_DEF LY_ERR +lyplg_add_extension_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_ext_record *recs) +{ + return lyplg_add_plugin(ctx, version, LYPLG_EXTENSION, recs); +} + +LIBYANG_API_DEF LY_ERR +lyplg_add_type_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_type_record *recs) +{ + return lyplg_add_plugin(ctx, version, LYPLG_TYPE, recs); +} diff --git a/src/plugins.h b/src/plugins.h index 9e919cc34..3ffc7cf82 100644 --- a/src/plugins.h +++ b/src/plugins.h @@ -17,6 +17,9 @@ #include "log.h" +struct lyplg_ext_record; +struct lyplg_type_record; + #ifdef __cplusplus extern "C" { #endif @@ -86,7 +89,25 @@ enum LYPLG { LIBYANG_API_DECL LY_ERR lyplg_add(const char *pathname); /** - * @brief Manually load a plugins from memory + * @brief Manually load extension plugins from memory + * + * Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the + * existence of a context. When all the contexts are destroyed, all the plugins are unloaded. + * + * @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared + * between all existing contexts. + * @param[in] version The version of plugin records. + * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed + * record. + * + * @return LY_SUCCESS if the plugins with compatible version were successfully loaded. + * @return LY_EDENIED in case there is no context and the plugin cannot be loaded. + * @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version. + */ +LIBYANG_API_DECL LY_ERR lyplg_add_extension_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_ext_record *recs); + +/** + * @brief Manually load type plugins from memory * * Note, that a plugin can be loaded only if there is at least one context. The loaded plugins are connected with the * existence of a context. When all the contexts are destroyed, all the plugins are unloaded. @@ -94,7 +115,6 @@ LIBYANG_API_DECL LY_ERR lyplg_add(const char *pathname); * @param[in] ctx The context to which the plugin should be associated with. If NULL, the plugin is considered to be shared * between all existing contexts. * @param[in] version The version of plugin records. - * @param[in] type The type of plugins records. * @param[in] recs An array of plugin records provided by the plugin implementation. The array must be terminated by a zeroed * record. * @@ -102,7 +122,7 @@ LIBYANG_API_DECL LY_ERR lyplg_add(const char *pathname); * @return LY_EDENIED in case there is no context and the plugin cannot be loaded. * @return LY_EINVAL when recs is NULL or the plugin contains invalid content for this libyang version. */ -LIBYANG_API_DECL LY_ERR lyplg_add_plugin(struct ly_ctx *ctx, uint32_t version, enum LYPLG type, const void *recs); +LIBYANG_API_DECL LY_ERR lyplg_add_type_plugin(struct ly_ctx *ctx, uint32_t version, const struct lyplg_type_record *recs); /** @} plugins */ #ifdef __cplusplus diff --git a/tests/utests/basic/test_plugins.c b/tests/utests/basic/test_plugins.c index fa0111361..df7523af5 100644 --- a/tests/utests/basic/test_plugins.c +++ b/tests/utests/basic/test_plugins.c @@ -131,7 +131,7 @@ test_simple_from_memory(void **state) struct lys_module *mod; struct lysc_node_leaf *leaf; - lyplg_add_plugin(UTEST_LYCTX, LYPLG_EXT_API_VERSION, LYPLG_EXTENSION, memory_recs); + lyplg_add_extension_plugin(UTEST_LYCTX, LYPLG_EXT_API_VERSION, memory_recs); UTEST_ADD_MODULE(simple, LYS_IN_YANG, NULL, &mod); leaf = (struct lysc_node_leaf *)mod->compiled->data;